实现达到 60FPS 的高性能交互动画

Web性能优化系列(2):剖析页面绘制时间

2015/04/15 · CSS,
HTML5,
JavaScript ·
性能优化

本文由 伯乐在线 –
刘健超-J.c
翻译,sunbiaobiao
校稿。未经许可,禁止转载!
英文出处:www.deanhume.com。欢迎加入翻译组。

最近,我参加了在伦敦举办的Facebook移动开发者大会。在那天期间,有很多的交谈,但真正让我关注的是一场关于性能的,名为“让m.facebook.com更快”的交流会,它的主题是关于Facebook如何不断努力改善网页性能和从中汲取的经验。

Facebook开发团队是使用Chrome
Cannry
来测试网页CSS性能的。Google Chrome
Canary
拥有Chrome的最新特性,并允许试用一些即将成为Chrome标准版本的,可行的最新特性。考虑到Chrome
Canary作为一个为开发者和尝鲜者专门设计的“预览版”,所以有时候会因Chrome开发团队的快速迭代而导致一些B
UG。尽管如此,它仍然有一些很棒的开发者工具帮助你测试网页性能

永利酒店赌场 1

在这篇文章里,我展示如何使用Chrome
Canary的开发者工具去定位你的CSS中的一部分,这部分CSS可能会导致页面滚动缓慢和影响页面的绘制时间。当浏览器加载和绘制页面时,为了“绘制”并让内容显示在屏幕上,需要遍历所有可见元素。由于这依赖于布局和复杂的CSS,你可能会发现绘制时间会很长。这会导致网页看起来忽动忽停和响应较慢。这种缓慢滚动也称为jank(jank是Android系统的一个专业术语,指的是屏幕上流畅动态画面中断的卡顿现象)。在移动设备上滚动页面时,浏览器会使劲地绘制复杂的CSS,这时这种情况更加明显。

即使页面的加载时间十分快,也仍然值得去研究页面的绘制时间。不同设备对CSS属性有着不一样的反应,但无论如何,能提高性能总是一件很好的事。为了进行测试,首先得去Google
Chrome
网站下载Chrome
Canary。一旦安装完成,就可以打开你想测试的网页。HTML5
Rocks
网站里有一个很好的案例网站,我们使用它来证明高耗能CSS属性的操作,会增加页面的绘制时间。

永利酒店赌场 2

一旦你打开到这个网页,按下F12,会弹出Chrome的开发者工具。然后在开发者工具的底部右侧点击设置按钮,开启测试页面渲染性能的设置。

永利酒店赌场 3

点击后会显示一个允许你更改设置的控制板。

永利酒店赌场 4

因为我们要测试页面的渲染性能,所以选择“Enable continuous page
repainting
(页面持续重新绘制)“和 “Show FPS
meter(显示FPS仪表)”**。如果你关闭设置面板,查看你的网页,你应该会看到下面的图片在页面右上角。

永利酒店赌场 5

该表显示以毫秒为单位的当前页面绘制所需时间,而右侧显示了当前图表的最小与最大值。另外,也显示了最近80帧的树状图。这个图表的强大之处是它不断试图重新绘制页面,使得页面好像是第一次加载。这允许你精确定位因CSS影响的绘制问题,而不用每次重新加载页面。无论你的改变是否产生影响,树状图都会持续监测。

如果我们详细查看这个页面的HTML和CSS,你会看到其中一个div添加了一些CSS效果。

永利酒店赌场 6

这个div有border-radius(圆角)和投影属性。当移除box-shadow属性,再观察FPS
meter在绘制时间的变化。

永利酒店赌场 7

哇!正如你从图表可看出,页面绘制时间有一个令人关注的变化。通过简单地将border-radius属性移除,就可以证明这个改变能让页面的绘制时间显著减少。当你更新或改变CSS属性时,这个图表就立即下降。在同一个元素上同时使用box-shadowborder-radius,会导致非常重的绘制负担,这是因为浏览器不能为之做出优化。如果有一个元素需要频繁的重复绘制,你应该在建立网页时时刻记住这点。

这是一个很好的,在Google IO
网站上的视频,它更深入地阐述绘制时间,并介绍一些减少网页“jank(卡顿)”的技巧。

想更进一步学习绘制时间的优化,看看这些链接。

祝测试愉快!

打赏支持我翻译更多好文章,谢谢!

打赏译者

永利酒店赌场 6

查询指定事件

你可以通过在DevTools上按Cmd+F(Mac)
调出查询框,来查看指定时间区域范围内的指定类型的事件,点击Cmd+G(Mac)
或者Cmd+Shift+G(Mac)
可以按事件发生的顺序来查询。

永利酒店赌场 9

实现达到 60FPS 的高性能交互动画。图中查询到了4个红色标记着的Parse HTML
事件,点击Cmd+G
焦点会在这4个事件移动。

页面在其脚本不可用时包含一些内容

基本内容和页面功能不应该依赖于CSS或JS。对于必需依赖JavaScript的页面,一种方法是使用一个

滚动

实现性能良好的平滑滚动可是个挑战。幸运的是,最近规范提供一些可配置选项。开发者不再需要通过禁止浏览器默认行为
(preventDefault),开启Passive event
listeners即可提升滚动性能(声明之后,就不需要通过阻止元素的
touch
事件监听和鼠标滚轮事件监听以优化滚动性能)。使用方法仅是在需要的监听器中声明{passive:
true}:

永利酒店赌场 10

从 Chrome 56 开始,这个选项将在touchmove和touchstart中默认开启。

新出的Intersection Observer
API能够告诉开发者某个元素是不是在视口内,或者是不是和其他元素有交互。和通过事件处理这种会阻塞主线程的交互方式相比,Intersection
Observer API
可以监听元素,只有当元素交叉路径的时候才会执行相应操作。这个 API
在无限滚动和懒加载的场景都可以使用。

关于作者:刘健超-J.c

永利酒店赌场 11

前端,在路上…
个人主页 ·
我的文章 ·
19 ·
    

永利酒店赌场 12

在这篇文章里,我展示如何使用Chrome
Canary的开发者工具去定位你的CSS中的一部分,这部分CSS可能会导致页面滚动缓慢和影响页面的绘制时间。当浏览器加载和绘制页面时,为了“绘制”并让内容显示在屏幕上,需要遍历所有可见元素。由于这依赖于布局和复杂的CSS,你可能会发现绘制时间会很长。这会导致网页看起来忽动忽停和响应较慢。这种缓慢滚动也称为jank(jank是Android系统的一个专业术语,指的是屏幕上流畅动态画面中断的卡顿现象)。在移动设备上滚动页面时,浏览器会使劲地绘制复杂的CSS,这时这种情况更加明显。

【转载】
Chrome开发者工具详解(3):Timeline面板

避免DOM过大

大型的DOM树会以多种方式降低页面性能:

  • 网络效率和负载性能,如果你的服务器发送一个大的DOM树,你可能会运送大量不必要的字节。这也可能会减慢页面加载时间,因为浏览器可能会解析许多没有显示在屏幕上的节点。
  • 运行时性能。当用户和脚本与页面交互时,浏览器必须不断重新计算节点的位置和样式。一个大的DOM树与复杂的样式规则相结合可能会严重减慢渲染速度。
    内存性能。如果使用通用查询选择器(例如,document.querySelectorAll(‘li’)
    您可能会无意中将引用存储到大量的节点),这可能会压倒用户设备的内存功能。

一个最佳的DOM树:

  • 总共少于1500个节点。
  • 最大深度为32个节点。
  • 没有超过60个子节点的父节点。
  • 一般来说,只需要在需要时寻找创建DOM节点的方法,并在不再需要时将其销毁。

如果你不能避免一个大型的DOM树,改善渲染性能的另一种方法是简化你的CSS选择器。请参阅减少风格计算的范围和复杂性。

原文链接 http://web.jobbole.com/92871/

打赏支持我翻译更多好文章,谢谢!

任选一种支付方式

永利酒店赌场 13
永利酒店赌场 14

赞 2 收藏
评论

一旦你打开到这个网页,按下F12,会弹出Chrome的开发者工具。然后在开发者工具的底部右侧点击设置按钮,开启测试页面渲染性能的设置。

录制中捕获截屏

在录制之前点击Controls中的Screenshots复选框,可以在录制过程中捕获截屏,鼠标在Overview上从左向右移动则可以看到录制的动画。

永利酒店赌场 15

避免使用Web SQL

Web
SQL已弃用,建议替换为IndexedDB

命令式动画

命令式动画告诉浏览器如何去演绎动画。CSS
动画代码在某些场景下会变得很臃肿,或者需要更多的交互控制,此时 JS
就要介入了。注意!和 CSS 动画不同,JS
动画是在主线程中执行的(也就是说丢帧的可能性大于 CSS
动画的),性能相对差一些。在使用 JS
动画的场景中,考虑范围中的性能之选比较少。

祝测试愉快!

网页录制详情

支持两种网页录制操作:①录制网页加载,②录制网页交互。为了便于分析,录制的时间不宜太长、还要避免不必要的交互操作、并禁用浏览器的缓存和插件。
当录制完成后,在Flame
Chart
(火焰图)中点击左侧三角可以展开详情,点击其中的事件或者空白处,可以在Details里面查看该事件或者总的概要信息。这里面包含的信息量很大,限于篇幅原因,下次有机会再作深入介绍,或者直接到Google上查看Timeline
Event Reference这个参考文档。

避免巨大的网络负载

延迟请求直到需要它们
启用文本压缩
压缩HTML、JS和CSS
使用Webp而不是JPEG或PNG
将JPEG图像的压缩级别设置为85
缓存请求

激发创造力

一般情况下,更改复合层是相对消耗性能较少的一个操作,所以尽量通过改变opacity和transform的值触发复合层绘制。看起来好像…我们能做出的效果会很有限,但真的是这样吗?要好好开发自己的创造力哦。

哇!正如你从图表可看出,页面绘制时间有一个令人关注的变化。通过简单地将border-radius属性移除,就可以证明这个改变能让页面的绘制时间显著减少。当你更新或改变CSS属性时,这个图表就立即下降。在同一个元素上同时使用box-shadowborder-radius,会导致非常重的绘制负担,这是因为浏览器不能为之做出优化。如果有一个元素需要频繁的重复绘制,你应该在建立网页时时刻记住这点。

Chrome 开发者工具详解(2):Network
面板

避免在页面加载时自动请求地理位置

页面在加载时自动请求用户位置会使用户不信任页面或感到困惑。应将此请求与用户的手势进行关联,而不是在页面加载时自动请求用户的位置。

新方法

现在有了will-change,它能够显式地通知浏览器对某一个元素的某个或某些元素做渲染优化。will-change接收各种各样的属性值,比如一个或多个
CSS 属性
(transform,opacity)、contents或者scroll-position。不过最常用值可能就是auto,这个值表示的是浏览器将进行默认的优化:

永利酒店赌场 16

优化有度,我们总能听到关于「复合层过多反而阻碍渲染」的讨论。因为浏览器已经为优化做了能做的一切,will-change的性能优化方案本身对资源要求很高。如果浏览器持续在执行某个元素的will-change,就意味着浏览器要持续对这个元素的进行优化,性能消耗造成页面卡顿。过多的复合层降低页面性能的现象在移动端很常见。

点击后会显示一个允许你更改设置的控制板。

运行时性能分析

上面大致介绍了Timeline面板上的各个功能菜单,那么如何去利用该面板去分析和优化网页程序的运行性能呢,由于篇幅限制,就不在这边展开讨论,感兴趣的读者直接到Google开发者文档上查看,Google开发者文档有最权威最新的信息。
参考文档
Analyze Runtime Performance

Diagnose Forced Synchronous Layouts

Chrome拓展程序

安装地址(需要梯子)
永利酒店赌场 17
永利酒店赌场 18

在右上角或者菜单里点击图中图标,Options可以配置测试项目,点击Generate
report即可测试。

复合

最后一步,将所有绘制好的元素进行复合。默认情况下,所有元素将会被绘制到同一个层中;如果将元素分开到不同的复合层中,更新元素对性能友好,不在同一层的元素不容易受到影响。CPU
绘制层,GPU
生成层。基础绘图操作在硬件加速合成中完成效率高。层的分离允许非破坏性的改变,正如你所猜测的,GPU
复合层上的改变代价最小性能消耗最少

Facebook开发团队是使用Chrome
Cannry
来测试网页CSS性能的。Google Chrome
Canary
拥有Chrome的最新特性,并允许试用一些即将成为Chrome标准版本的,可行的最新特性。考虑到Chrome
Canary作为一个为开发者和尝鲜者专门设计的“预览版”,所以有时候会因Chrome开发团队的快速迭代而导致一些B
UG。尽管如此,它仍然有一些很棒的开发者工具帮助你测试网页性能

作者:伯乐在线专栏作者 – CharlieChu
点击 →
了解如何加入专栏作者
如需转载,发送「转载」二字查看说明

测试结果示例


永利酒店赌场 19

测试和迭代

动画性能优化最简单的方案就是减少每一帧的工作量。最有效缓解性能压力的方法就是,尽量只更新在复合层中的元素,重新渲染复合层元素不容易影响到页面上其他元素。性能优化往往意味着反复地测试和验证,以及跳出惯性思维找到奇技淫巧实现高性能动画
— 无论怎么样,最终受益的会是用户和开发者。

永利酒店赌场 1

录制中进行JS分析

在录制之前点击Controls中的JS
Profile
复选框,可以在时间轴中捕获JavaScript的堆栈信息(会产生一定的性能消耗),并且在Flame
Chart
(火焰图)中会显示所有被调用的JavaScript函数信息。

永利酒店赌场 21

开发者工具

仅能在Chrome60及以上使用,因为之前版本的Chrome的开发者工具的audits面板还不是Lighthouse。永利酒店赌场 22

永利酒店赌场 23

通过右上角的菜单或者快捷键(command+option+i)打开开发者工具,然后选择audits面板,点击Perform
an audits会弹出一个options面板勾选测试项然后点击Run audits即可。

变换

「变换」为元素提供了无限的可能性:位置可以改变 (translateX,translateY,
或translate3d)、大小也可以通过缩放 (scale) 改变、还能旋转、斜切甚至 3D
变换。就是在某些场景下,开发者需要换一种思考方式,通过使用变换减少重排和重绘。
比如给一个元素添加 active 类名后它会向左移动 10px,可以通过改变 left
属性:

永利酒店赌场 24

这是一个很好的,在Google IO
网站上的视频,它更深入地阐述绘制时间,并介绍一些减少网页“jank(卡顿)”的技巧。

Chrome
开发者工具详解(1):Elements、Console、Sources面板

最佳实践


这些最佳实践主要针对移动端或者Web应用。某些技术对浏览器版本要求较高,用之前最好在Can
I
use、MDN上查一下浏览器支持情况

性能测试

知道了如何优化页面性能后,还要做性能测试才行。依我之见,Chrome
开发者工具就是最棒的测试工具。在 ‘More Tools’ 中有一个 ‘Rendering’
面板,其中包含了一些选项:比如追踪「脏元素」、计算每秒的帧率、高亮每层的边界还有监测滚动性能问题。

永利酒店赌场 25

‘Performance’ 面板中的 ‘Timeline’
工具能记录动画过程,开发者可以直接定位到出问题的部分。很简单,红色表示有问题,绿色表示渲染正常。开发者可以直接点击红色区域,看看是哪个函数造成了性能问题的函数。

另一个有趣的工具是在 ‘Caputrue Settings’ 中的 ‘CPU
throtting’,开发者可以通过这个选项模拟页面运行在一台非常卡的设备上。开发者在桌面浏览器上测试页面的时候效果可能很好,那是因为
PC 或者 Mac 的本身性能就优于移动设备。这个选项提供了很好的真机模拟。

最近,我参加了在伦敦举办的Facebook移动开发者大会。在那天期间,有很多的交谈,但真正让我关注的是一场关于性能的,名为“让m.facebook.com更快”的交流会,它的主题是关于Facebook如何不断努力改善网页性能和从中汲取的经验。

绘制解析

在录制之前点击Controls中的Paint复选框,可以获取绘制事件的更多细节信息(注意这会产生很多的性能消耗)。如果要深入了解网页渲染方面的信息,可以点击DevTools右上角的菜单,在More
tools
里面选中Rendering settings,这里面包含了如下设置项:

永利酒店赌场 26

Paint Flashing 高亮显示网页中需要被重绘的部分。

Layer Borders 显示Layer边界。

FPS Meter 每一秒的帧细节,帧速率的分布信息和GPU的内存使用情况。

Scrolling Performance Issues
分析鼠标滚动时的性能问题,会显示使屏幕滚动变慢的区域。

Emulate CSS Media
仿真CSS媒体类型,查看不同的设备上CSS样式效果,可能的媒体类型选项有print
、screen

把上面的所有设置项勾选上,网页的显示效果如下:

永利酒店赌场 27

背景和前景应该有足够的对比度

低对比度文本对于许多用户来说很难或不可能读取
使用Chrome扩展程序aXe可以分析出所有的可访问性问题

布局

渲染树生成后,浏览器会从页面左上角开始迭代地计算出每个元素尺寸和位置,最终生成布局。这个过程可能是一气呵成的,但也可能由于元素的排列导致反复地绘制。元素间的位置关系都紧密相关。为了优化必要的任务,浏览器会追踪元素的变化情况,并将这些元素以及它们的子节点标记为
‘dirty’(脏元素)。但是元素间耦合紧密,任何布局上的改变代价都是重大的,应该尽量避免

因为我们要测试页面的渲染性能,所以选择“Enable continuous page
repainting
(页面持续重新绘制)“和 “Show FPS
meter(显示FPS仪表)”**。如果你关闭设置面板,查看你的网页,你应该会看到下面的图片在页面右上角。

Timeline面板

Timeline面板是整个面板里面最复杂的一个面板,涉及的东西比较多。可以利用这个面板来记录和分析网页运行过程中的所有活动行为信息。
你可以充分利用这个面板来分析你的网页的程序性能问题。

永利酒店赌场 28

概述
下图是从Google官方网站中介绍Timeline面板的图贴到这里,该面板主要包括4大块窗格(Pane):
Controls 录制开关和控制录制过程中需要记录哪些信息。

Overview 网页性能的概要信息。

Flame Chart
CPU堆栈轨迹的可视化图表(火焰图)。在图表里面有1到3条虚竖线。

Details
当选择一个指定的事件后,会显示这个事件的更多信息;当没有选择事件时,会显示指定的时间帧信息。

Flame
Chart
里面的虚竖线含义:蓝色标记DOMContentLoaded事件;绿色标记第一次的绘制时间点;红色代表load事件。

永利酒店赌场 29

其中第2块Overview显示了网页性能相关的概要信息,可以通过鼠标或者区域边界上的灰色滑块来拖出一个指定区域范围,Flame
Chart
会跟着局部放大显示指定区域内的详情信息。
可以通过键盘上的W
,S
来放大和缩小指定区域,通过A
,D
来向左或向右移动指定区域。

从Google把图贴到这里,这个窗格包含了三个图表:
FPS 每秒帧数(Frames Per
Second)。绿色柱状条越高,则每秒帧数越高。在FPS图表上方的红色块是标记一个长帧。

CPU 标记CPU资源的使用情况,这里的面积图标记着消耗CPU资源的各类事件。

NET
各种颜色的柱状条分别显示一种资源。柱状条越长,代表获取这个资源的时间越长。

永利酒店赌场 30

CPU面积图中各颜色的含义:蓝色代表HTML文件;黄色代表脚本文件;紫色代表样式文件;绿色代表媒体文件;灰色代表其它杂项文件。

NET图表柱状条两种颜色的含义:较亮的部分表示等待时间(当资源被请求时,直到第一个字节被下载的时间);较暗的部分表示传输时间(在第一个和最后一个字节被下载之间的时间)。

地址栏颜色应该和品牌颜色、网页主题匹配

永利酒店赌场 31

就是地址栏的背景颜色应该和品牌颜色一致
通过meta标签实现的:

<meta name="theme-color" content="#ff6633">

不过仅在认可这个meta的浏览器上有效,比如Chrome for
Android,实测pc、ios的Chrome、Safari无效。
永利酒店赌场 32

如果场景能用上还是能提高一些用户体验的,避免了地址栏突兀。

requestAnimationFrame

requestAnimationFrame对性能友好,你可以将它视作setTimeout的进化版,不过这其实是一个动画执行的
API。理论上调用了这个 API 就能保证 60fps
的帧率,但实践证明这个函数是请求在下一次可用时绘制动画,也就是并没有固定的时间间隔。浏览器会把页面上发生的变化组合接着一次绘制,而不会为每一次变化都进行绘制,通过这个方式提升
CPU 的使用率。 RAF 可以递归地使用

永利酒店赌场 33

另外,类似缩放窗口或页面滚动这样的场景,直接绑定事件是相对消耗性能的,开发者可以考虑在类似情况下用
RAF 提升性能。

永利酒店赌场 2

优化代码在浏览器中的运行方式:
  1. 对于动画效果的实现,避免使用setTimeout或setInterval,请使用requestAnimationFrame
  2. 将长时间运行的JavaScript从主线程移动到Web Worker
  3. 使用micro-tasks来执行对多个帧的DOM更改
  4. 使用Chrome
    DevTools的Timeline和Javascript分析器来评估JavaScript的影响。
    降低选择器的复杂性(例如:nth-of-type、:nth-child);使用以类为中心的方法,例如BEM,这有一篇BEM的教程
  5. 尽可能避免布局操作,对“几何属性”(如宽度、高度左侧或顶部)的更改都需要布局计算。布局几乎总是作用到整个文档,如果有大量元素,会消耗很长时间来计算出所有元素的位置和尺寸。
  6. 避免强制同步布局
    永利酒店赌场 35
    首先JavaScript运行,然后计算样式,然后布局。但是,可以使用JavaScript强制浏览器提前执行布局。这被称为强制同步布局。在JavaScript运行时,来自上一帧的所有旧布局值是已知的,并且可供查询。因此,如果在帧的开头写出一个元素的高度是没有问题的,但是在查询高度之前,已经更改其样式,如下列代码。,就会强制页面计算返回正确的高度。这是不必要的,并且开销很大。始终应先批量读取样式并执行,然后执行任何写操作。

function logBoxHeight() {

  box.classList.add('super-big');

  // Gets the height of the box in pixels
  // and logs it out.
  console.log(box.offsetHeight);
}
  1. 除 transform 或 opacity
    属性之外,更改任何属性始终都会触发绘制。可以使用Chrome
    DevTools来快速确定正在绘制的区域。打开DevTools,按下键盘上的 Esc
    键。在出现的面板中,转到“rendering”标签,然后选中“Show paint
    rectangles”。永利酒店赌场 36

  2. 每一个表单元素都应该有一个label
    label阐明了表单元素的用途。虽然每个元素的目的对于有视觉的用户来说可能是显而易见的,但对于依靠屏幕阅读器的用户来说并非如此。有四种方式可以实现:

  • 隐含标签

<label>First Name <input type="text"/></label>
  • 显式标签

<label for="first">First Name <input type="text" id="first"/></label>
  • aria-label

<button class="hamburger-menu" aria-label="menu">...</button>
  • aria-labelledby

Select seat:
<custom-dropdown aria-labelledby="foo">...</custom-dropdown>
  1. 每个图像都有一个alt属性
    信息性图像应该具有alt包含该图像内容的文本描述的属性。屏幕阅读器使视觉障碍的用户能够通过将文本内容转换为可以使用的表格(如合成语音或盲文)来使用您的网站。屏幕阅读器无法转换图像。因此,如果您的图片包含重要信息,那么视觉障碍用户无法获取该信息。
    可以在DevTools的Console选项卡中使用以下命令来查找没有alt属性的图片

$$('img:not([alt])');

在Console中$$()相当于document.querySelectorAll()

  1. 配置HTML的Viewport meta标签
    如果没有Viewport
    meta标签,移动设备将以典型的桌面设备屏幕宽度渲染页面,然后对页面进行缩放以适合移动设备屏幕。通过Viewport
    meta标签可以控制宽度和缩放比例。
    配置视口
    设置视口
    width=device-width键值对将视口宽度设置为设备宽度。在访问页面时,initial-scale=1键值对设置初始缩放级别。

<head>
  ...
  <meta name="viewport" content="width=device-width, initial-scale=1">
  ...
</head>
  1. 压缩图片(仅针对JPEG)
    将每个图像的压缩级别设置为85或更低,像TinyJPG这样的Web服务可以帮助自动化图像优化的过程

动画方法

想要元素动起来可以用 CSS(声明式),也可以使用
JavaScript(命令式),按需选择。

该表显示以毫秒为单位的当前页面绘制所需时间,而右侧显示了当前图表的最小与最大值。另外,也显示了最近80帧的树状图。这个图表的强大之处是它不断试图重新绘制页面,使得页面好像是第一次加载。这允许你精确定位因CSS影响的绘制问题,而不用每次重新加载页面。无论你的改变是否产生影响,树状图都会持续监测。

避免使用document.write()

对于网速较慢(2G、3G或较慢的WLAN)的用户,外部脚本通过document.write()动态注入会使页面内容的显示延迟数十秒。

hack 方法

从前,开发者通常是通过backface-visibility:hidden或者trasform:
translate3d(0,0,0)触发浏览器生成新的复合层,但这并不是标准的写法,这两种写法也对元素的视觉效果不起作用。

即使页面的加载时间十分快,也仍然值得去研究页面的绘制时间。不同设备对CSS属性有着不一样的反应,但无论如何,能提高性能总是一件很好的事。为了进行测试,首先得去Google
Chrome
网站下载Chrome
Canary。一旦安装完成,就可以打开你想测试的网页。HTML5
Rocks
网站里有一个很好的案例网站,我们使用它来证明高耗能CSS属性的操作,会增加页面的绘制时间。

预计输入延迟时间

输入响应能力对用户如何看待应用的性能起着关键作用。应用有100毫秒的时间响应用户输入。如果超过此时间,用户就会认为应用反应迟缓。

手动优化

还有一个好消息 —
开发者可以选择想要控制的属性,创建复合层,并将元素拖到该层。通过手动优化,确保元素总能被绘制好,这也是通知浏览器准备绘制该元素的最简单方式。需要独立层的场景包括:元素的状态将发生一些变化(比如动画)、改变了很消耗性能的样式(比如position:fixed和overflow:scroll)。可能你也见过了糟糕的性能导致了页面闪烁、震动…或其他不如预期的效果,例如移动端常见的固定在视口顶部的头部,会在页面滚动的时候闪烁。将这样的元素独立到自己的复合层,就是常见的解决这类问题的方法。

本文由 伯乐在线 – J.c 翻译,sunbiaobiao 校稿。未经许可,禁止转载!
英文出处:www.deanhume.com。欢迎加入翻译小组。

使用入门


运行Lighthouse的方式有三种:在开发者工具(Devtools)的Audits,作为Chrome拓展程序使用,或者作为命令行工具使用。Chrome开发者工具不需要额外安装,和扩展程序一样提供了一个用户友好的界面,方便读取报告;扩展程序相对于开发者工具的优势是更及时,不用等待Chrome发版就能体验到最新的功能;命令行工具可以将Lighthouse集成到持续集成系统。

浏览器 101:像素是怎么来的

在深入研究之前,我们要先搞清楚一个很重要的问题:浏览器是怎么把代码转化成为用户可见的像素点呢?

首次加载时,浏览器会下载并解析 HTML,将 HTML 元素转变为一个 DOM
节点的「内容树」(content tree)。除此之外,样式同样会被解析生成「渲染树」
(render
tree)。为了提升性能,渲染引擎会分开完成这些工作,甚至会出现渲染树比
DOM 树更快生成出来。

永利酒店赌场 4

打开外部链接使用rel=”noopener”

当页面使用 target=”_blank”
跳转至另一个页面时,新页面将与您的页面在同一个进程上运行。
如果新页面正在执行开销极大的
JavaScript,您的页面性能可能会受影响。最重要的是target=”_blank”也是一个安全漏洞。新页面可以通过window.opener访问旧页面的window对象,并且它可以使用window.opener.location=newURL将旧页面导航至不同的网址。所以当在新窗口或标签中打开一个外部链接时,应该始终加上rel=”noopener”,例如:

<a href="https://examplepetstore.com" target="_blank" rel="noopener">...</a>

先读后写

不断地读写 DOM 会导致「强制同步布局」(forced synchronous
layouts),不过在技术发展过程中它演变成了更形象的词 — 「布局抖动」(layout
thrashing)。前文也有提到,浏览器会追踪「脏元素」,在合适的时候将变换过程储存起来。在读取了特定属性以后,开发者可以强制浏览器提前计算。这样反复的读写会导致重排。幸运的是有一个简单的解决方式:读完再写。

为了模拟上述效果,请看下面这个对读写有严苛要求的例子:

永利酒店赌场 38

将「读」放到forEach外面,而不是和「写」一起在每个迭代里都执行,就能提高性能:

永利酒店赌场 39

这个div有border-radius(圆角)和投影属性。当移除box-shadow属性,再观察FPS
meter在绘制时间的变化。

避免使用mutation events

以下mutation events会损害性能,在DOM事件规范中已经弃用:

  • DOMAttrModified
  • DOMAttributeNameChanged
  • DOMCharacterDataModified
  • DOMElementNameChanged
  • DOMNodeInserted
  • DOMNodeInsertedIntoDocument
  • DOMNodeRemoved
  • DOMNodeRemovedFromDocument
  • DOMSubtreeModified
    建议将每个mutation
    events替换成MutationObserver

透明度

可以通过改变opacity的值,实现元素的显示和隐藏(与改变display或者visibility的值达到类似的效果类似,但性能更好)。比如实现菜单的切换效果:菜单展开时,opacity值为1;收起时,opacity值变为
0。要注意的是pointer-events的值也要随之改变,防止用户操作到明明收起的菜单。closed
类名会根据用户点击 ‘open’ 时,closed 类名会被加上;点击 ‘close’
按钮时,closed 类名会被移除。对应的代码是这样的:

永利酒店赌场 40

另外,透明度可变意味着开发者可以控制元素的可见程度。多多思考应用透明度的场景
— 比如直接给元素的阴影 (box-shadow) 做动效很可能会造成严重的性能问题:

永利酒店赌场 41

如果把阴影放到伪元素上,控制伪元素的透明度从而控制阴影,效果一样但性能更好,代码如下:

永利酒店赌场 42

永利酒店赌场 3

避免在页面加载时自动请求通知权限

好的通知需要做到及时、相关且准确。如果页面在加载时要求权限以发送通知,则这些通知可能与您的用户无关或者不是他们的精准需求。为提高用户体验,最好是向用户发送特定类型的通知,并在他们选择加入后显示权限请求。

声明式动画

CSS
动画是声明式的(告诉浏览器要做什么),浏览器需要知道动画的起始状态和终止状态,这样它才知道如何优化。CSS
动画不是在主线程中执行,不会妨碍主线程中的任务执行。总的来说,CSS
动画对性能更友好
。关键帧的动画组合提供了相当丰富的视觉效果,比如下面是一个元素的无限旋转动画:

永利酒店赌场 44

但 CSS 动画缺乏 JS 的表达能力,将两者结合起来效果更好:比如用 JS
监听用户输入,根据动作切换类名。类名对应着不同的动画效果。下面的代码实现的是当元素被点击时切换类名:

永利酒店赌场 45

永利酒店赌场 46

值得一提的是,如果你在操作「出血」(注:设计中在画布四边留出的一定区域称为「出血」)时,新的Web
Animation
API会利用
CSS 的性能。通过这个
API,开发者能轻松地在性能友好的基础上处理动画的同步和时间问题。

如果我们详细查看这个页面的HTML和CSS,你会看到其中一个div添加了一些CSS效果。

启用文本压缩

如果浏览器支持,则配置服务器以使用Brotli压缩响应。Brotli比GZIP可以节省更多的流量。如果不支持Brotli则使用GZIP。在Chrome
DevTools检查响应是否被压缩:

  • 打开DevTools的Network面板
  • 点击指定的回复的请求。
  • 点击Headers选项卡
  • 检查Response Headers中content-heading字段
    永利酒店赌场 47

绘制

生成布局后,浏览器将页面绘制到屏幕上。这个环节和「布局」步骤类似,浏览器会追踪脏元素,将它们合并到一个超大的矩形区域中。每一帧内只会发生一次重绘,用于绘制这个被污染区域。重绘也会消耗大量性能,能免则免

永利酒店赌场 5

优化关键渲染路径

将关键资源数降至最低:消除关键资源、延迟关键资源的下载并将它们标记为不同步等。
优化关键字节数以缩短下载时间。
优化其余关键资源的加载顺序:尽早下载所有关键资产,以缩短关键路径长度。

优化的未来

永利酒店赌场,浏览器在性能优化方面持续投入了越来越多的精力。通过新属性contain可以声明一个元素的子树独立于页面的其他元素(目前只有
Chrome 和 Opera
支持该属性)。这就等于告诉了浏览器「这个元素是安全的,它不会影响到其他元素」。contain的属性值根据变化的范围确定,可以是strict、content、size、layout、style或者paint。这确保了子树被更新的时候,不会造成父元素的重排。特别是在引入第三方控件的时候:

永利酒店赌场 49

想更进一步学习绘制时间的优化,看看这些链接。

避免弃用的API

已弃用的API计划从Chrome中移除,使用这些API后,被删除后将导致网页出错。查看Chrome平台状态

永利酒店赌场 7

避免长宽比不正确的图像

如果渲染的图像与其源文件中的长宽比不同,则呈现的图像可能看起来失真,产生不愉悦的用户体验。

  • 避免将元素的宽度或高度设置为可变大小的容器的百分比。
  • 避免设置不同于源图像尺寸的显式宽度或高度值。
  • 考虑使用css-aspect-ratio或 Aspect
    Ratio
    Boxes来帮助保留宽高比。
  • 如果可能的话,在HTML中指定图片的宽度和高度是一个很好的做法,这样浏览器就可以为图片分配空间,这样可以防止页面在加载时跳过。在HTML中而不是CSS中指定宽度和高度是更理想的,因为浏览器在解析CSS之前分配空间。实际上,如果您使用响应式图像,则此方法可能很困难,因为在知道视口尺寸之前无法指定宽度和高度。
避免使用console.time()

如果使用console.time()测试页面性能,请考虑使用User Timing
API。其优势包括:

  • 高分辨率时间戳
  • 可导出的计时数据
  • 与Chrome Devtools TImeline相集成。在 Timeline 录制期间调用 User
    Timing 函数 performance.measure() 时,DevTools
    自动将此测量结果添加到 Timeline 的结果中。
    将console.time()替换为performance.mark()。如果需要测量两个label之间经过的时间,则使用performance.measure()。User
    Timing
    API

// 获得命名时间戳
window.performance.mark('mark_fully_loaded');
// 获得命名时间戳之间的时间间隔或者与PerformanceTiming的时间间隔
window.performance.measure('measure_load_from_dom', 'domComplete', 'mark_fully_loaded');
允许用户粘贴到密码字段中

密码粘贴提高了安全性,因为它使用户能够使用密码管理器。密码管理员通常为用户生成强密码,安全地存储密码,然后在用户需要登录时自动将其粘贴到密码字段中。
删除阻止用户粘贴到密码字段的代码。使用事件断点中的Clipboard
paste来打断点,可以快速找到阻止粘贴密码的代码。比如下列这种阻止粘贴密码的代码:

let input = document.querySelector('input');
input.addEventListener('paste', (e) => {
  e.preventDefault(); // This is what prevents pasting.
});

永利酒店赌场 51

Lighthouse是一个Google开源的自动化工具,主要用于改进网络应用(移动端)的质量。目前测试项包括页面性能PWA可访问性(无障碍)最佳实践SEO。Lighthouse会对各个测试项的结果打分,并给出优化建议,这些打分标准和优化建议可以视为Google的网页最佳实践。
永利酒店赌场 52

避免使用Date.now()

考虑改用performance.now()代替Date.now()。performance.now()可提供较高的时间戳分辨率,并始终以恒定的速率增加,它不受系统时钟(可以调整)的影响。performance.now()

// 获取相对于navigationStart属性中的时间戳为起点开始计时的精确到千分之一毫秒的时间戳
 window.performance.now()
按钮有一个可访问的名称

没有名字的按钮对依赖屏幕阅读器的用户不可用。当一个按钮没有名字时,屏幕阅读器会宣布“按钮”。
对元素和role=”button”的元素:

  • 设置元素的内部文本
  • 设置aria-label属性
  • 将该aria-labelledby属性设置为屏幕阅读器可见的文本元素。

对于的元素:

  • 设置value属性
  • 设置aria-label属性
  • 设置aria-labelledby属性

对于和:

  • 设置value属性,或省略它。浏览器在value省略时赋予”submit”或”reset”的默认值
  • 设置aria-label属性
  • 设置aria-labelledby属性
避免使用AppCache

AppCache已被废弃
考虑使用service worker的Cache
API,另外现在ios
11.3也支持了service worker,未来一两年应该有很大发展。

使用被动事件监听器以提升滚动性能

被动事件是新兴的Web标准,可以显著提高滚动性能,尤其在移动设备上。当使用touch事件监听器(scroll事件不存在这个问题)进行滚动时,因为浏览器不知道你是否会取消滚动,它们总是等待监听器执行完毕后才开始滚动,这样就造成了明显的延迟。事件监听器options中使用passive:true表明监听器永远不会取消滚动,这样浏览器就可以立即滚动。
在支持被动事件侦听器的浏览器中,将侦听器标记为passive即可:

document.addEventListener('touchstart', onTouchStart, {passive: true});

求赞,欢迎访问我的博客

避免页面存在不成功的HTTP状态码

搜索引擎可能无法正确索引返回不成功的HTTP状态码的页面。

命令行工具

安装:

npm install -g lighthouse
# or use yarn:
# yarn global add lighthouse

使用:

lighthouse https://example.com

配置项:

$ lighthouse --help

lighthouse <url>

Logging:
  --verbose  Displays verbose logging                                                                                                      [boolean]
  --quiet    Displays no progress, debug logs or errors                                                                                    [boolean]

Configuration:
  --save-assets                  Save the trace contents & screenshots to disk                                                             [boolean]
  --list-all-audits              Prints a list of all available audits and exits                                                           [boolean]
  --list-trace-categories        Prints a list of all required trace categories and exits                                                  [boolean]
  --additional-trace-categories  Additional categories to capture with the trace (comma-delimited).
  --config-path                  The path to the config JSON.
  --chrome-flags                 Custom flags to pass to Chrome (space-delimited). For a full list of flags, see
                                 http://peter.sh/experiments/chromium-command-line-switches/.

                                 Environment variables:
                                 CHROME_PATH: Explicit path of intended Chrome binary. If set must point to an executable of a build of
                                 Chromium version 54.0 or later. By default, any detected Chrome Canary or Chrome (stable) will be launched.
                                                                                                                                       [default: ""]
  --perf                         Use a performance-test-only configuration                                                                 [boolean]
  --port                         The port to use for the debugging protocol. Use 0 for a random port                                    [default: 0]
  --hostname                     The hostname to use for the debugging protocol.                                              [default: "localhost"]
  --max-wait-for-load            The timeout (in milliseconds) to wait before the page is considered done loading and the run should continue.
                                 WARNING: Very high values can lead to large traces and instability                                 [default: 45000]
  --enable-error-reporting       Enables error reporting, overriding any saved preference. --no-enable-error-reporting will do the opposite. More:
                                 https://git.io/vFFTO
  --gather-mode, -G              Collect artifacts from a connected browser and save to disk. If audit-mode is not also enabled, the run will quit
                                 early.                                                                                                    [boolean]
  --audit-mode, -A               Process saved artifacts from disk                                                                         [boolean]

Output:
  --output       Reporter for the results, supports multiple values                        [choices: "json", "html", "domhtml"] [default: "domhtml"]
  --output-path  The file path to output the results. Use 'stdout' to write to stdout.
                 If using JSON output, default is stdout.
                 If using HTML output, default is a file in the working directory with a name based on the test URL and date.
                 If using multiple outputs, --output-path is ignored.
                 Example: --output-path=./lighthouse-results.html
  --view         Open HTML report in your browser                                                                                          [boolean]

Options:
  --help                        Show help                                                                                                  [boolean]
  --version                     Show version number                                                                                        [boolean]
  --blocked-url-patterns        Block any network requests to the specified URL patterns                                                     [array]
  --disable-storage-reset       Disable clearing the browser cache and other storage APIs before a run                                     [boolean]
  --disable-device-emulation    Disable Nexus 5X emulation                                                                                 [boolean]
  --disable-cpu-throttling      Disable CPU throttling                                                                    [boolean] [default: false]
  --disable-network-throttling  Disable network throttling                                                                                 [boolean]
  --extra-headers               Set extra HTTP Headers to pass with request                                                                 [string]

Examples:
  lighthouse <url> --view                                                   Opens the HTML report in a browser after the run completes
  lighthouse <url> --config-path=./myconfig.js                              Runs Lighthouse with your own configuration: custom audits, report
                                                                            generation, etc.
  lighthouse <url> --output=json --output-path=./report.json --save-assets  Save trace, screenshots, and named JSON report.
  lighthouse <url> --disable-device-emulation --disable-network-throttling  Disable device emulation
  lighthouse <url> --chrome-flags="--window-size=412,732"                   Launch Chrome with a specific window size
  lighthouse <url> --quiet --chrome-flags="--headless"                      Launch Headless Chrome, turn off logging
  lighthouse <url> --extra-headers "{"Cookie":"monster=blue"}"          Stringify'd JSON HTTP Header key/value pairs to send in requests
  lighthouse <url> --extra-headers=./path/to/file.json                      Path to JSON file of HTTP Header key/value pairs to send in requests

For more information on Lighthouse, see https://developers.google.com/web/tools/lighthouse/.
避免使用旧版CSS Flexbox

2009年的旧Flexbox规范已弃用,其速度比最新的规范慢2.3倍。将页面中的display:box及以box开头的每个属性替换成标准的Flexbox属性。

网站地图xml地图