在国家公祭日,我们哀悼沉思,势要勿忘国耻振兴中华;在国家重要人物逝世后,举国哀悼;这些时段很多网站都会积极呼应,给与自己的网页设置成灰色;那给网页设置成灰色是经过怎样的设置来实现的呢?
有的网站给自己整个页面设置为灰色;有的网站给首屏设置成灰色;有的则是给大多区域设置成灰色,留出某些部分是原色。
1、filter(让整个网页都呈现出灰色效果)
使用filter要注意,当给父级元素设置了灰色效果后,就像给父级加上了一个滤镜,这个元素的子级是不能通过调整子级的filter来摆脱父级滤镜遮盖。
所以给与整个网页呈现灰色,可以直接给html设置
<style>
html {
filter: grayscale(0.95);
-webkit-filter: grayscale(0.95);
}
</style>
2、使用svg滤镜
SVG 滤镜的存在,让本来就非常强大的 CSS 如虎添翼。具体方案是使用svg的feColorMatrix
<style>
html {
filter: url(#grayscale);
}
</style>
<svg xmlns="https://www.w3.org/2000/svg" style="display:none;">
<filter id="grayscale">
<feColorMatrix type="matrix" values="0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0"/>
</filter>
</svg>
3、backdrop-filter
把效果应用在元素后面的区域所覆盖的所有的元素(可能有些绕,可以对比下filter的作用)
filter:把效果应用在该元素身上,其后代元素不能摆脱
拿blur模糊效果来举例看效果(以下分别是正常效果、filter的效果、backdrop-filter的效果)
<style>
.bg {
padding: 10px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
background-image: url(./bg-2.jpg);
}
.bg > div {
width: 300px;
height: 250px;
line-height: 250px;
text-align: center;
background: rgba(255, 255, 255, 0.7);
}
.bg div:nth-child(2) {
filter: blur(6px);
}
.bg div:nth-child(3) {
backdrop-filter: blur(6px);
}
</style>
看到效果后再回想上面的那句话,backdrop-filter不影响自己这个元素,会把效果放在这个元素下面的区域上。
这次来个新的,用它来做首屏变灰,下滚的区域正常显示
<style>
html {
position: relative;
width: 100%;
height: 100%;
overflow: scroll;
}
html::before {
content: "";
position: absolute;
inset: 0; /* top/bottom/left/right:0的简写 */
backdrop-filter: grayscale(95%);
z-index: 10;
}
</style>
【注意】backdrop-filter 存在一些兼容性问题,对于火狐 v103 及以下可能不支持
4、混合 mix-blend-mode
mix-blend-mode是CSS中另一个可以对颜色效果进行干预操作的属性——混合模式,相对backdrop-filter兼容性要好
继续拿首屏置灰来实验,具体实现代码:
<style>
html {
position: relative;
width: 100%;
height: 100%;
overflow: scroll;
/* 一定要加上白背景的! */
background: #fff;
}
html::before {
content: "";
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 1);
mix-blend-mode: color;
z-index: 10;
}
</style>
【问题】
无论是兼容性好的min-blend-mode还是兼容性欠佳的backdrop-filter,都会有个问题——影响交互,就像有mask隔开一样,我们类似hover这些交互无法实现。(后面说解决办法)
5、除部分元素外,其他的区域置灰
有时候我们想要页面上除去某些地方之外的地方变灰,比如页面变灰但不让头像变灰
我们用filter来实现,就得考虑子级不能摆脱父级的遮罩
所以这个选择器很有意思,需要认真琢磨琢磨
<style>
:not(:has(.avatar)):not(.avatar){
filter:grayscale(1);
}
</style>
【解释】
拿xb类举例子 :not(:has(.xb)){样式} 所选元素——后代元素中不存在类名为xb的元素
下面两个图中可以看到样式不会加在div.avatar-box身上,而是会加在img.avatar.xb上
因为img.avatar.xb下面没有后代元素了,所以更不用说类名为xb的元素了,所以就得选它
基于上面的选择器,再增加:not(.xb) 即 :not(:has(.xb)):not(.xb){样式}
所选的元素——其【后代元素中】类名不包含xb的元素并且其本身不是类名为xb的元素(既不包含,也不是)
这样就可以避免 在avatar的父级上添加filter后导致avatar无法摆脱父级效果的问题
从下面两个图中可以看到,样式没有加在div.note-user上,因为这个元素的后代元素中存在类名为xb的元素,但是div.note-txt-box上是有样式的,因为这个元素的后代元素中不存在类名为xb的元素。
所以我们把用于测试的xb去掉,使用avatar类名来排除头像区域的灰色效果
同img.avatar的父级div.avatar-box同级的div.user-nick会有灰色效果,因为它的后代元素中既没有.avatar的元素自己本身也不是.avatar的元素;但div.avatar-box没有灰色效果,因为它的后代元素中存在.avatar的元素,所以不符合:not(:has(.xb)) 条件。
6、滤镜影响交互问题
上面说到的一个问题——min-blend-mode或backdrop-filter的设置会影响一些交互效果
想要在鼠标hover到♥的时候,让♥转一圈,但实际这颗心没能被我打动
需要 pointer-events 的帮助,让我们的鼠标事件不发生在这个“mask”身上,也就是穿透到下面
pointer-events:none;