页面变灰二三事

又一次“天灾”降临,又一次无数工程师彻夜加班,又一次互联网产品集体变灰。有些产品换上灰色logo,有些产品增加了灰色banner,有些产品整个页面变灰。我想,不同的表现形式,表达的含义应该都是哀悼和祈福吧。这里,只想从技术实现上简单说说页面变灰这个话题。

实现和问题

大家都知道,利用IE古老的滤镜,以及webkit支持的css3滤镜,可以很方便的让IE和webkit内核浏览器下的元素变灰。如果滤镜作用于html元素,整个页面就变灰了。

html{
    filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
    -webkit-filter:grayscale(100%);
}

从体验上来看,用户很难看清全灰页面上的重点,很容易错过重要信息。从技术上,这样做也带来两个问题:1、消耗更多CPU资源,让网站变卡(手机上更为明显);2、-webkit-filter会导致retina设备上的页面变模糊。第1个问题很好理解不用多说。第2个问题,应该出在-webkit-filter的实现上:首先拷贝元素渲染后的图像,再针对图像进行转换。我猜测在拷贝时获取的是小尺寸图片,导致在retina设备(如rmbp、iPad 3+、iPhone 4+)上,对元素使用任何-webkit-filter都会让元素的渲染变模糊(见下图)。这个问题已经有人给webkit报bug了,官方已确认。

神奇的是,webkit这个bug,居然被我发现可以用一个离奇的方法来解决:给页面引入一个flash即可(更可行的方案请看本文最后)。

对于不支持IE滤镜和webkit滤镜的firefox,网上流传一个svg方案,先定义svg文件如下:

<svg version="1.1" 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"></feColorMatrix>
</filter>
</svg>

再在要变灰的页面加上这行样式就好了:

html {filter: url(desaturate.svg#grayscale);}

或者像下面这样把外链的svg写到datauri里:

html {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");}

这个svg能完美的让firefox页面变灰,在retina设备上也完全正常,但毫无疑问的也会消耗更多的CPU。对于尚未更换内核的opera,没有能直接让整个html变灰的样式。

思考和探索

上面这些方案既不环保,又可能伤害retina用户的体验,还不能兼容全部浏览器。更极致的做法是彻底改掉整个页面样式,主要是两个地方:1、css中定义的颜色值;2、网站引入的图片。css规则一般都放在外链文件;图片则有css背景图、img前景图、flash焦点图等,css、html、js都需要排查。

css中的颜色值,可以用代码自动转换,例如彪叔之前发布的CSS演示转换工具。原理是用正则获取颜色值的R,G,B,取平均值A=(R+G+B)/3,最终替换成A,A,A就只有灰度了。这个方案有个缺点,除非内置red=>#ff0000这样的完整对照表,否则用单词表示的颜色值得不到转换。另外,对于计算颜色的灰度值,网上有另外一个看上去更精确的公式:0.299R+0.587G+0.114*B。

给图片去色就比较简单了,很多图片工具都支持批量转换。例如大名鼎鼎的ImageMagick,通过这样一行命令就能搞定:

convert <input> -colorspace Gray <output>

有些产品引用的图片来源多样,处理起来很麻烦。如果平时养成了图片使用统一的图床服务来管理的好习惯,那么通过升级基础服务,就可以实现按照某个规则替换url就输出灰色图片的功能,这就能大大减少业务线的图片替换工作量。如:原图 灰图

网上还有一些现成的工具,可以批量替换项目中的css和图片,例如CssGaga就提供了一体化的解决方案。我们内部统一的编译平台,也可以利用整站源码分析编译的平台优势,自动完成代码和图片同步修改的工作。

最后要说的是,从技术上看,让页面变灰是件小事;如何能让自己的代码更环保,如何能让基础服务更快速灵活的支持业务需求,如何通过工具让项目更流程化、自动化,才是需要大家继续思考和努力的。

补充说明

update @2013.04.23, 在ytzong同学博客上看到这个:解决 -webkit-filter: grayscale(100%) 在 retina 下的模糊问题。对于webkit这个bug,在官方修复之前,这应该是最好的解决方案了。多加下面这行 css 就可以了:

-webkit-transform: translateZ(0);

update @2014.03.25,今天发现加了上述 css 后,某台非 retina 屏 iMac 上的 Safari 6 会变得更模糊,文字完全无法辨认。所以建议再加一层判断,只针对高分屏增加 transform:

html {
    filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
    -webkit-filter: grayscale(100%);
}

@media only screen and (-webkit-min-device-pixel-ratio: 2) {
    html {
        -webkit-transform: translateZ(0);
    }
}

本文链接:参与评论 »

--EOF--

提醒:本文最后更新于 1326 天前,文中所描述的信息可能已发生改变,请谨慎使用。

专题「Web 产品思考」的其他文章 »

Comments