像素点是昂贵的

时间:2023-02-14 14:28:22

原文:  Pixels are expensive by Paul Lewis

像素点是昂贵的在CC-By 3.0许可证下使用. 像素点是昂贵的


像素点是昂贵的

你应该了解像素点是如何呈现在用户屏幕上的。不是为了知道而了解,而是因为作为一个高效的当代网页开发人员,你将需要优化它。


前几天,我正在通读《对于网页渲染,每一个前端开发人员都应该知道的是什么》,我觉得这篇文章好像漏了一些关键点。文章着重强调了CSS选择器的匹配、布局(或基于Gecko浏览器(比如火狐)的回流)和强制同步布局(亦称Layout Thrashing)的注意事项。我得说,所有这些都是我们需要知道的非常好的东西,但对于我来讲,它不能涵盖所有我需要知道的关于页面渲染的信息。大部分情况下,我们都会试着在工作中做到60fps,通常这就意味着要了解浏览器为了帧数在做什么和在优化什么。


在今年的Google I/O大会上,我单步调试了相当数量细节的管道。如果与阅读文章相比,你更喜欢看视频,那么下面就是此次会议的视频:

                                                                         像素点是昂贵的

如果只想看渲染管道的部分,可以从16分钟左右开始看。


对于网页渲染,开发人员需要知道什么?
从一个开发者的角度来说,需要注意四个主要的领域:
1. 重新计算模式
这是文章关注的第一部分,描述的是关于选择器匹配和计算出哪种模式可应用于DOM的哪些部分。

像素点是昂贵的

                                                                      浏览器算出哪个CSS用于哪个元素。


通常来说,不论怎样,这是超级快的,除非你有一个有成千上万元素的DOM树,并且使树中的一大部分无效(比如说通过在body中加一个类影响他的所有子类)。


大多数情况下,优化选择器匹配将会产生最小的回报。不将下一步发生什么考虑在内时…


2. 布局


一旦我们知道了哪种模式应用于渲染树(要涂色的)的DOM。对我们来说,它本质上看起来就好像漏掉了一些东西(我们不需要画的东西)、又加上了一些东西(比如伪元素)的DOM。

像素点是昂贵的

                                                                      渲染树:我们需要涂色的东西。

在布局上我们算出页面的几何结构,即每个元素在页面上的什么位置上?这正是在计算上开始变得昂贵的地方,因为元素布局的方式是不一定的;一个元素所在的位置往往和另一个元素也有关系。如果我改变了<body>的尺寸,那么有可能<body>里的东西也都需要改变。


这也正是开始变得有趣的地方。打比方说你改变了一个布局的属性,某些东西改变了页面的几何结构(填充、页边空白、位置、文本大小、边界),接下来会怎样?嗯,下面是我做的一段视频,展示了当改变元素的几何结构式,Chrome的开发调试工具DevTools的时间轴的情况。在这个例子里,我改变了它的高度:


                                                        像素点是昂贵的

要注意的事情是那些条块很快的通过了60fps时间线,我们用了大约23ms找出了几何结构的每一帧的变化。无论这个动画是由JavaScript还是CSS触发的,这都是真实的,因为仍需要完成布局工作。当我们打算达到60fps时,我们有16ms去完成所有事情,我们在刚才的任务中也做到这个了。哎哟喂,一石二鸟。


这里算是一点福利吧,你肯定想避免layout thrashing或强制同步布局,这将导致浏览器不必要的去进行布局/回流。这只会让情况变得更糟糕。


无论怎样,希望从那个视频里你也能看到尽管我们在布局上花费了23ms,但我们用了600ms对改变的像素点进行涂色。


3. 涂色


现在我们知道了要填到他们的像素点里的元素在哪了,这也是你将要花费大部分时间的地方。如果你触发了涂色,那么你一定会感觉到它的。所以,当你的网站在挣扎的时候,你的用户肯定也会感觉得到。这里是另一个我通过改变元素的颜色(从灰色改成了鲜艳的亮粉色)来触发涂色(这里没有布局变化)的例子:

                                                      像素点是昂贵的

能触发涂色的属性有颜色、背景或阴影,但如果你改变一个布局属性,事实上也会触发涂色。页面几何结构改变时,像素点被污染,需要固定位置。


一旦涂色完成,我们将要进行最后部分。


4. 合成


默认情况下,在内存中将元素着色至一个图层,对于咱们这些开发者来说,可以将它想象成Photoshop里的画布。如果你用笔刷改变一个像素点,这是破坏性的,将不能再得到原来的那个像素点。(Photoshop还有个撤销功能呢…哈哈)


为了应付这个问题,用一种与Photoshop和其他平面包装设计软件很相似的方法,我们有时将多个元素分到不同的图层,称作复合图层。如果我们要对一个元素着色,理想情况下其他元素都不被着色,就可以用这种方法。我之前已经写过了为“推广”一个元素占用一个独立图层的目前正在使用的规则,但还有一个全新的方法,我会简短的解释一下!:-O

                                  像素点是昂贵的

                                                                 一个艺术家的效果…好吧,是我的,我的页面复合图层的效果。

当我们完成这些图层后,我们再把他们合并在一起,这就是合成。


避免性能瓶颈


不久前我和Paul Irish在HTML5 Rocks上写了一篇文章,解释你怎样得到高性能动画,或在这种情况下,你如何利用管道来确保动画到达60fps。总的说来就是只通过改变属性触发影像合成,而不是布局或涂色:


                                     像素点是昂贵的


                                                                                                 更改这些属性不会触发布局或涂色。


这里列出了最常见的参数变换(连同不透明度),但理论上其中任何一个都应起作用。你将需要把元素放到各自的复合图层上。但最新最闪亮的方式是will-change,这种方式对于确定的关键词,如opacity或transform将使Chrome和火狐在后台做出适当的优化。至于这两个关键词,至少对Chrome来说,指的是创建复合图层。


如果你刚接触will-change,Sara Soueidan最近在dev.Opera上发表了一篇关于will-change的帖子。如果对于你的工作,你不能依靠will-change,而且will-change还包括了当前版本的Chrome,那么你肯定还在用一些非常老派的黑客技术,比如-webkit-backface-visibility: hidden或者永远的最爱-webkit-transform: translateZ(0);(哦吼,黑了无效变换图层!),你还会再走你自己的老路。


当我们坚持使用复合图层操作时,会看到一个个超亮的帧,并且画面达到了60fps!

                                                                      像素点是昂贵的

出于好奇,我们看到透明帧的原因是因为我们仍在追踪60fps,即使16ms前工作负载就完成了。在这种情况下我们用空白空间填充时间轴。哦,空间!


工具,不是规则,是更光明的未来


事物总是不断变化的,包括我已经解释过的管道。好消息是你的开发工具将总是最新的和真实的,所以如果你不习惯于花时间更新你的工具,你应该改变一下了。它们会用爱来回报你的。


真正的好消息是这些也都会变得更快。在今年的Google I/O大会上,我们用Android系统里的Chrome展示稳定在60fps的快速、流动、持续的动画,这些对于Chrome团队仍是非常重要的。我知道这对于其他浏览器供应商也是非常重要的。


我希望有一天你所需要注意的就只是写“精神正常”的代码,不管它是触发布局、涂色还是其他的,你可以让浏览器做它的工作,但是直到那时候,这才是对于网页渲染,每一个前端开发人员都应该知道的。