全国哀悼日,一段css让全站变灰

    |     2020年4月6日   |   html/css/js, web前端技术   |     0 条评论   |    1151

为表达全国各族人民对抗击新冠肺炎疫情斗争牺牲烈士和逝世同胞的深切哀悼,国务院决定 2020 年 4 月 4 日举行全国性哀悼活动。期间全国和驻外使领馆下半旗致哀,停止公共娱乐活动;4 月 4 日 10 点起默哀 3 分钟,汽车、火车、舰船鸣笛,防空警报鸣响。

默哀日访问网站时,整站常常变成全灰。若临时改设计稿、重出图,成本很高。一段 CSS 就能把所有元素变灰:filter: grayscale。原文:掘金原文。

一、用 grayscale 把页面变灰

filter: grayscale 可以调整元素灰度。兼容写法把 WebKit、旧 IE 的 BasicImage 和 SVG 滤镜一并带上:

.gray-filter {
    filter: grayscale(100%);
    -webkit-filter: grayscale(100%);
    -moz-filter: grayscale(100%);
    -ms-filter: grayscale(100%);
    -o-filter: grayscale(100%);
    filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><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>#grayscale");
    filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
    -webkit-filter: grayscale(1);
}

二、实战:加在 body 上会打坏 fixed

以 B 站为例。正常情况下,导航栏滑到下面之后是 fixed 在页面顶部的:

20200406201219

但如果你把这段 CSS 加到了 body 上,会出现下面这种情况:

20200406201246

资料说明:对指定了 filter 且值不为 none 的元素,其子元素里 position: absolute 或 fixed 的元素会得到一个新的包含块。fixed 本相对于视口(可理解为 html 根容器)定位;body 上设 filter 后,新的定位基准随 body 滚出屏幕,子孙的 fixed 就会失效。

做法 效果 适用
filter 写在 body fixed 导航错位 不要这样全站灰
filter 写在 html 新包含块仍是根,fixed 正常 全站变灰
只给局部容器加 class 不影响页面其它 fixed 局部变灰 / 小程序

三、两种解法

方案 1:作用在 html

影响全站时,把样式应用到根元素 html。即使创建了新的定位基准,也不会把子孙的 fixed 带出视口。

html {
    filter: grayscale(100%);
    -webkit-filter: grayscale(100%);
    -moz-filter: grayscale(100%);
    -ms-filter: grayscale(100%);
    -o-filter: grayscale(100%);
    filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><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>#grayscale");
    filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
    -webkit-filter: grayscale(1);
}

效果:

20200406201309

方案 2:只给需要变灰的节点加 class

非全站变灰时,把 filter 单独加在目标元素上:

<html>
    <body>
        <div class="gray-filter"></div>
    </body>
</html>

<style>
.fixed {
    position: fixed;
    top: 100px;
    left: 100px;
    height: 100px;
    width: 100px;
    background-color: #f00;
}
.gray-filter {
    filter: grayscale(100%);
    -webkit-filter: grayscale(100%);
    -moz-filter: grayscale(100%);
    -ms-filter: grayscale(100%);
    -o-filter: grayscale(100%);
    filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><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>#grayscale");
    filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
    -webkit-filter: grayscale(1);
}
</style>

20200406201332

四、IE 与小程序

IE 低版本可用 grayscale.js Demo。源码会把 color、background-color、borderColor 抽出来改成灰色;background-image 和图片则用 canvas 处理后替换源。demo 里的 functions.js 按 userAgent 区分浏览器版本再走对应处理。参考:cross-browser-grayscale-ie11。

微信小程序把样式加在 page 上,fixed 仍会失效,只能用第二种方法给局部节点加样式。

一句话总结:全站变灰用 html { filter: grayscale(100%) },不要写在 body 上,否则会新建包含块,把 position:fixed 弄丢。

转载请注明来源:全国哀悼日,一段css让全站变灰
本文链接地址:https://ai.zhousir.top/?p=2581
回复 取消