网页中的抗锯齿
抗锯齿是网络图形显示技术中一个从未被赞颂过的英雄;正是因为有了抗锯齿,我们才可以在屏幕上看到各种清晰的文字与平滑的矢量图形。如今,有好几种抗锯齿技术被用在了浏览器上,尤其是在对文字的渲染上,我们可以很明显的观察到抗锯齿的作用。
如果改变抗锯齿的处理算法,将可能导致一些出乎意料的视觉差异。在这篇文章中,我们将对在浏览器上使用的抗锯齿技术做一个介绍,并让我们来看看浏览器上的像素点是如何绘制的。
正如我们所知,我们的屏幕是由像素组成的。它是一个巨大的块状的网格,每一个都由红、绿、蓝(RGB)三原色组合而成。从一定距离看向屏幕时,我们可以看到图片、文字和各种图标。但是当我们近距离观察时,我们就可以看到这些由三原色组成的网格,还有它们是如何组成的。
图 1 - 近距离观察时屏幕上的像素点。每一个像素点由红、绿、蓝三原色组成。
抗锯齿
现在我们考虑,当需要绘制一个矢量图形,而这个图形需要经过一个完整像素点的一部分,这时会发生什么呢?假设我们要绘制的这个图形是黑色的,且背景是白色的。我们需要给那个图形通过的非完整的像素点绘颜色吗?如果需要的话,应该绘制什么颜色呢?黑色、灰色,还是别的什么颜色?
通过抗锯齿的处理,决定了我们应该给像素填充哪个颜色。最简单的抗锯齿处理被称为灰度抗锯齿,它将像素的三原色分量做了相同的处理。所以,如果一个图形仅通过了一个像素点的一部分 — 并且为了简单考虑,让我们暂时假设是黑色的文字在白色的背景上渲染 — 你可能会认为每一个三原色分量都会被设为半明度(我知道我自己肯定会这么认为),但是实际上的情况要比这复杂的多:你需要考虑颜色的伽马值(gamma),这意味着你可能永远不可能将它设置到一个精确的值(半明度)。
当然,这让事情变得有一些复杂,但由于这里仅是对这个话题的一个介绍,我不会在这里对它进行深入的分析。我们仅需要知道的是,灰度抗锯齿是在 像素级别 上做处理的, 而我们可以选择更好的办法来处理它。
图 2 - 抗锯齿处理 vs 锯齿边
从图2你可以看到两个同样的三角图形被绘制在屏幕上,不过左图做了抗锯齿处理,而右图没有。正如你看到的,当我们对图形做了抗锯齿处理以后,图形通过一个不完整的像素点时,这个像素会被施加一种灰色的阴影。而没有做抗锯齿处理时,所有的像素点不是被完全填充成黑色,就是被填充成白色,如你所见,整个图形看起来非常糟糕。
文字渲染
无论何时,当浏览器渲染文字时,和渲染矢量图形一样,我们都需要面对这样的问题:对字符的渲染,它们总是需要通过非完整的像素点,所以我们需要一种策略,到底该给这些像素点绘制何种颜色。理想情况下,我们希望给文字施加抗锯齿,好使得文字对于人们阅读来说更加友好。
然而,事实证明灰度抗锯齿仅能以 一种办法 去处理像素。另外还有一种常用来处理抗锯齿的办法,这种办法让我们对于像素点三原色各分量的处理上更有选择性,它叫做次像素抗锯齿。这些年来,微软的ClearType团队在研究次像素抗锯齿上花了大量的时间,并且让其技术的发展有了很大的进步。现在,次像素抗锯齿是用的最多的技术,所有主流浏览器目前都多多少少使用了这项技术。
首先我们知道,每一个像素点实际上都是由红、绿、蓝三原色由左到右并排组成的。我们发现要决定一个像素上的哪些分量需要打开(switch on)、哪些需要关闭(switch off)是一个问题。所以如果一个像素是从左手边 半覆盖 的,我们将把红色分量全部打开,绿色分量只打开一半,而完全关闭蓝色分量。这个过程通常被称之为“三倍屏幕的水平分辨率”,这是依赖于每个像素都是由三个分量挨个分布、而不是一个独立的单位的事实的。
图 3 - 灰度抗锯齿 vs 次像素抗锯齿
你可以从上面的图3中看到,在左图(灰度抗锯齿)里,我们同等的对待每一个三原色分量,每一个分量都是相同的“打开”或是“关闭”的状态。而在右图里,我们使用了次像素抗锯齿 - 根据三原色分量各在待绘制图形上占有多少比重,来决定抗锯齿后三原色分量的开闭。
虽然有了上面的说法,人类的视觉对三原色的感知是有差异的。我们对绿色的敏感程度要远远大于红色与蓝色,这意味着比起灰度抗锯齿,次像素抗锯齿是更有优势的。就像Darel Rex Finley 的文章里说的,分别对待三原色的开闭实际上并没有提升3倍的清晰度,但是次像素抗锯齿绝对是对清晰度有帮助的,跟灰度抗锯齿比起来,次像素抗锯齿可以帮助我们更清晰的读到文字。
图 4 - 次像素抗锯齿的文字。这个效果是由每个像素中的三原色分量分别开闭而组合成的
切入正题
那么这些对我们开发者有什么意义呢?嗯,至少从 Chrome perspective 的角度来说,Chrome 混合使用了灰度抗锯齿和次像素抗锯齿来渲染文字,而有一套标准来决定你实际看到的是使用哪种技术来渲染的文字。不过首先,我们需要对浏览器中的 layer(渲染层,下文统一用layer来表示)需要有一定的了解,因为这是浏览器渲染的主要标准。如果你对 layer 以及 Chrome 内部是如何使用它的并不熟悉,你应该首先阅读 Tom Wiltzius 曾经写过的一篇关于这个话题非常优秀的文章。
假设你已经对渲染层非常熟悉了,或者你已经刚刚翻阅了相关的文章,那么让我们继续往下说。如果一个网页使用了硬件合成,并且你现在有一些文本内容被渲染在非 root layer (non-root layer)上,那么默认的,这些文本将使用灰度抗锯齿来渲染。一些开发者会经常发现这样一个现象,当他们对元素施加一些黑魔法来使得这些元素获得自己的(非 root layer)layer(比如说添加 translateZ 属性)时,会发现文字渲染出来变得不一样了。当开发者通过CSS或者JavaScript来使元素获得layer时,会让文字渲染从灰度抗锯齿变到次像素抗锯齿。如果你不清楚是什么导致渲染出现差异的话,这会让人觉得非常困惑。而如果你的文本是在root layer上,那么它们在渲染时会被施加次像素抗锯齿,这会使得它们看起来要更加清晰。
但是,就像所有 web 技术一样,一切都是在变化的。在 Chrome 中,次像素抗锯齿会在当 non-root layer 满足如下三个条件的情况下被激活。有必要提出的是,这些条件适用于当前,但是将来很可能会改变,你可以持续关注这方面的变化。目前使用的条件为:
- 这个 layer 拥有一个完全不透明的背景颜色。 特别要注意的是当
border-radius
或者一个非标准的background-clip
属性施加在这个 layer 上时,会导致这个layer被当作一个非不透明的层来对待,而使得它从次像素抗锯齿回退到灰度抗锯齿。 - 这个 layer 只能被施加一个单一的transform,或者一个整数 translation。整数 translation 的意思是施加给translate的值必须是整数,如
translate(20.2px, 30px)
就会被施加灰度抗锯齿,因为它的 x 分量20.2px
是一个非整数。而单一的 transform 的意思是在一个transform语句中除了默认值,不能有另外的rotation、translation 或者 scale。 - 这个 layer 不可以带透明度(=1.0)。任何透明度的变化都将使得它从次像素抗锯齿回退到灰度抗锯齿。
图 5 - 之前与之后: 灰度抗锯齿 vs. 次像素抗锯齿. 注意文字右边的彩色的锯齿边
最后一件需要注意的事就是,当施加一个 CSS animation 时,会给这个元素创建一个 layer,但是使用 requestAnimationFrame
时却不会。所以对于一些开发者,当他们发现文字渲染不同时,应该去检查你是否使用了 CSS animation。而当你使用 JavaScript 去执行动画,却发现文字渲染不同时,你应该去检查上述的这些特性你是否注意到了。
所以这就是 Chrome 对抗锯齿的表现了。对于其他浏览器,比如说 Opera,由于它迁移到了Chromium,所以它对抗锯齿的表现应该很接近 Chrome。IE 貌似使用次像素抗锯齿来渲染所有可见的文本(当然,仅当你启用了 ClearType 的情况下),但是这样的行为貌似并没有在 Win8 的 Metro mode 中的IE中表现。Safari 由于使用了WebKit内核,它的表现也十分接近 Chrome,尽管它没有那么多最新的优化来使得更多的次像素抗锯齿被使用于渲染。Firefox 目前来说,大部分表现都接近于IE,它对所有可见文本施加了次像素抗锯齿。当然这并不是一个详尽的关于各浏览器关于抗锯齿具体表现的列表,而仅仅是各浏览中可能会使用灰度抗锯齿而不是次像素抗锯齿的一些可能情况,但知道次像素抗锯齿是被广泛应用于各主流浏览器是有好处的。
结论
所以现在你知道了关于抗锯齿是如何作用的,并且知道了为什么你的网站和应用中,有些情况下字体渲染得不一样,特别对于某些低分辨率(DPI)的设备。如果你对关于 Chrome 对于文本的渲染是如何实施的感兴趣,可以阅读以下相关的文章:
- Automatic Font Grayscale Anti-Aliasing above 48px not Overridable
- Horrible font rendering with Google Web Fonts on Chrome for Windows
- DirectWrite support
资源和参考文献
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 自定义元素:在 HTML 中定义新元素
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论