css如何做性能优化
日期:2019-05-20
来源:程序思维浏览:1350次
我们在做优化网站的性能时,CSS的优化往往是最后的选择.因为有更多的优化方案可以带来比CSS优化更显著更快速的收益。
然而,对一个CSS库进行优化却可以为用户带来更好的体验
每当大家讨论CSS的速度时,往往大家会引用Steve Souders的属性选择器慢或者是伪类选择器慢的结论.然而随着现代浏览器的发展,我觉得验证诸如"属性选择器慢"或"伪选择器慢"之类的反而变得没有太大的意,应该把性能的提升放在括号内而不是括号外才是我们应该关心的事情。
但是除了引用Nicole Sullivand的文章来支持我的假设,选择器不同并不重要,在这之前我从来没有真正测试过这个理论;因为我的天赋不足和缺乏完美的分析头脑使我无法尝试,我只能进行一些简单的尝试
选择器测速
<script type="text/javascript">
;(function TimeThisMother() {
window.onload = function(){
setTimeout(function(){
var t = performance.timing;
alert("Speed of selection is: " + (t.loadEventEnd - t.responseEnd) + " milliseconds");
}, 0);
};
})();
</script>
并且,我设置了一个非常简单的测试。20个不同的选择器,都有一个相同的、巨大的DOM,由下面1000个相同的DOM组成
<div class="tagDiv wrap1">
<div class="tagDiv layer1" data-div="layer1">
<div class="tagDiv layer2">
<ul class="tagUl">
<li class="tagLi"><b class="tagB"><a href="/" class="tagA link" data-select="link">Select</a></b></li>
</ul>
</div>
</div>
</div>
测试的方式就是通过不同规则的选择器来让最内部的a标签的字体变为红色,每次测试的结果为每个浏览器的5次平均值.在测试中,我实际是运行了十次,而因为前五次的结果往往是有异常的,所以我们只取后5次的结果.
需要注意的是,我们关注点是不同选择器在同一浏览器上的表现,而不是浏览器之间相互的PK.所以在关注下面表格时,从上往下一列一列的看才是合适的.
这意味着这什么?
经过我多次的测试,尽管同浏览器下,不同的选择器确实会有一定速度差异,但还是无法从得到的结果中推断出哪个选择器最慢.
不过我们可以确定的是,使用类选择器,不仅可以和选择其他选择器拥有一样的速度拥有一样的运行速度,而且还可以使你的CSS更具模块化的特征.
对于我们来说,上述测试中拥有1000个DOM,并且对于用户访问网站时最快与最慢的选择器之间差别也并不足以影响体验,它已经证实了担心使用何种选择器类型是一件浪费时间的事情,因为我们还有更加重要的事情去做。
作者与WebKit工程师本杰明普尔的探讨是非常有趣的,下面引用了一些信息:
对于加载一个页面来说,有太多其他的因素参与,而CSS的加载只是其中的一小部分。
咱们以测试10的 [class^=”wrap”] 选择器为例
剩下来的时间分布在一些小的函数上
通过上面的测试,我们假设最快的选择器的速度为100ms。其中,5 ms将被用于收集样式。
假设下载另外一个选择器的速度比第一个选择器慢3倍,那么它的加载时间就应该为110ms.
那么,在测试报告中应该为300%的差异,而不是现在的10%
基于这一点,原文作者回答说,虽然我理解本杰明所指的是什么,但我的测试只是为了说明我在这篇文章中的观点 ——
在其他条件不变的情况下,不同的选择器的使用并不会影响性能
本杰明花时间回答了更多的细节:
我完全同意优化选择器没有太多的必要,不过我跟你的原因并不相同:
通过检查选择器,几乎不可能预测给定选择器的最终性能影响。在引擎中,选择器被重新排序、分割、收集和编译。要知道给定选择器的最终性能,您必须知道选择器是如何收集的,它是如何编译的,最后是DOM树是什么样子的?
所有这些在不同的引擎之间是非常不同的,这使得整个过程更加难以预测。
我反对web开发人员优化选择器的第二个理由是,它们可能会使事情变得更糟。关于选择器的错误信息比正确的浏览器兼容信息要多。想要把它做好几乎不可能
然而在开发中,人们会发现CSS的性能问题,并开始一个接一个地删除样式规则,直到问题解决。我认为这是正确的做法,这很容易,而且会带来正确的结果。
原因与结果
如果页面上的DOM元素数量减少了一半,那么所有测试的速度理应都是相对应的减少.但是,很多时候DOM对象的数量并不能大幅度的减少.这让我想知道CSS中未使用的样式的数量会不会对性能产生影响?
另一个测试:我从fiatuk网站抓取了一个臃肿的样式表。它大约有3000行CSS。所有这些不相关的样式都被插入到一个最终的文件中,这个文件中的样式是将我们的DOM对象中的所有的内部a节点变成红色。我在每个浏览器上都做了相同的平均结果
然后我把一半的规则去掉,然后重复测试来进行比较。这里是结果(单位:ms):
当一半的样式被删除时,你可以看到Firefox的东西下降了很多(大约1500行)。在这一点上,Android设备的速度也接近于最慢的选择器的速度。
删除未使用的样式
这种恐怖场景对你来说是不是很熟悉?具有各种选择器的巨大的CSS文件(通常使用的选择器甚至都不工作),更具体的选择器的块更大,更深入,不适用的前缀,杂乱的id,文件大小为50-80KB(有时更多)。
如果您正在处理一个有一个像这样臃肿的CSS文件的代码库,那么没有人确切地知道所有的样式实际上是干什么的
处理这个问题似乎比对所使用的选择器吹毛求疵更有意义。它将产生双倍的影响;用户下载的代码更少,这是一个速度提升。
但是同样,这对CSS的实际性能也没有帮助
括号内的性能
我运行的最后一个测试是配置一堆“昂贵”的CSS来访问页面
.link {
background-color: red;
border-radius: 5px;
padding: 3px;
box-shadow: 0 5px 5px #000;
-webkit-transform: rotate(10deg);
-moz-transform: rotate(10deg);
-ms-transform: rotate(10deg);
transform: rotate(10deg);
display: block;
}
以下是结果:
在这里,所有的浏览器都至少比最慢的选择器测试慢了1.5倍,而Android设备比最慢的选择器测试慢了1.3倍,但这还不是全部。 试试看滚动浏览器,页面的样式重绘会让你的电脑崩溃.
实际上,我们在括号里的属性才是真正影响性能的。这是有理由的,一直滚动一个拥有”昂贵”的,不停需要重绘的并且布局一直在变化的页面将会给电脑带来压力。
什么是”昂贵”的样式?
我们怎么知道什么是“昂贵”的样式?值得庆幸的是,我们可以将平时的经验应用到这一点上.任何需要浏览器在绘图前进行操作/计算的东西都将更加昂贵。例如,框阴影、圆角、透明度、过度之类的样式——如果性能是您的优先级,那么任何类似的东西都是您最大的敌人
结论
然而,对一个CSS库进行优化却可以为用户带来更好的体验
每当大家讨论CSS的速度时,往往大家会引用Steve Souders的属性选择器慢或者是伪类选择器慢的结论.然而随着现代浏览器的发展,我觉得验证诸如"属性选择器慢"或"伪选择器慢"之类的反而变得没有太大的意,应该把性能的提升放在括号内而不是括号外才是我们应该关心的事情。
但是除了引用Nicole Sullivand的文章来支持我的假设,选择器不同并不重要,在这之前我从来没有真正测试过这个理论;因为我的天赋不足和缺乏完美的分析头脑使我无法尝试,我只能进行一些简单的尝试
选择器测速
<script type="text/javascript">
;(function TimeThisMother() {
window.onload = function(){
setTimeout(function(){
var t = performance.timing;
alert("Speed of selection is: " + (t.loadEventEnd - t.responseEnd) + " milliseconds");
}, 0);
};
})();
</script>
并且,我设置了一个非常简单的测试。20个不同的选择器,都有一个相同的、巨大的DOM,由下面1000个相同的DOM组成
<div class="tagDiv wrap1">
<div class="tagDiv layer1" data-div="layer1">
<div class="tagDiv layer2">
<ul class="tagUl">
<li class="tagLi"><b class="tagB"><a href="/" class="tagA link" data-select="link">Select</a></b></li>
</ul>
</div>
</div>
</div>
测试的方式就是通过不同规则的选择器来让最内部的a标签的字体变为红色,每次测试的结果为每个浏览器的5次平均值.在测试中,我实际是运行了十次,而因为前五次的结果往往是有异常的,所以我们只取后5次的结果.
需要注意的是,我们关注点是不同选择器在同一浏览器上的表现,而不是浏览器之间相互的PK.所以在关注下面表格时,从上往下一列一列的看才是合适的.
下面就是测试的结果(单位ms):
序号 | CSS测试用例 | IE11 | Google Chrome 65 | Mozilla Firefox 55 |
---|---|---|---|---|
1 | [data-select] | 69 | 73.2 | 121.4 |
2 | a[data-select] | 87.8 | 59.8 | 116.4 |
3 | [data-select=”link”] | 98.4 | 56.6 | 108 |
4 | a[data-select=”link”] | 95.5 | 55 | 104.4 |
5 | div[data-div=”layer1”] a[data-select=”link”] | 82.6 | 56.6 | 104 |
6 | a:after | 105 | 68.2 | 121 |
7 | .tagA.link | 79.2 | 59 | 108 |
8 | .tagUl .link | 95.2 | 55.4 | 109.8 |
9 | .tagB > .tagA | 82.4 | 54.2 | 107.8 |
10 | [class^=”wrap”] | 85.2 | 57.6 | 119.2 |
11 | div:nth-of-type(1) a | 79 | 54 | 104.4 |
12 | div:nth-of-type(1) div:nth-of-type(1) a | 93.8 | 54 | 96.6 |
13 | div.wrapper > div.tagDiv > div.tagDiv.layer1 > div.tagDiv.layer2 > ul.tagUl > li.tagLi > b.tagB > a.tagA.link | 94.2 | 52.8 | 101.4 |
14 | .tagLi .tagB a.tagA.link | 80.6 | 57 | 103.4 |
15 | * | 78.6 | 53.6 | 98.3 |
16 | a | 96.6 | 55.2 | 103.8 |
17 | div a | 95.8 | 59.6 | 122.8 |
18 | div ul a | 82 | 60.8 | 120.8 |
19 | div ul a:after | 102.8 | 69.6 | 130.2 |
20 | .link | 79.6 | 57 | 119 |
最大的差异 | 36 | 20.4 | 34 | |
最慢的选择器序号 | 19 | 1 | 19 |
经过我多次的测试,尽管同浏览器下,不同的选择器确实会有一定速度差异,但还是无法从得到的结果中推断出哪个选择器最慢.
不过我们可以确定的是,使用类选择器,不仅可以和选择其他选择器拥有一样的速度拥有一样的运行速度,而且还可以使你的CSS更具模块化的特征.
对于我们来说,上述测试中拥有1000个DOM,并且对于用户访问网站时最快与最慢的选择器之间差别也并不足以影响体验,它已经证实了担心使用何种选择器类型是一件浪费时间的事情,因为我们还有更加重要的事情去做。
作者与WebKit工程师本杰明普尔的探讨是非常有趣的,下面引用了一些信息:
对于加载一个页面来说,有太多其他的因素参与,而CSS的加载只是其中的一小部分。
咱们以测试10的 [class^=”wrap”] 选择器为例
- ~10% 的时间用于光栅化图元
- ~21% 的时间用于元素放置布局
- ~48% 的时间用于解析与DOM树的构建
- ~8% 的时间用于CSS解析
- ~5% 的时间用于收集样式 – 而这一部分才是我们应该测试的地方
剩下来的时间分布在一些小的函数上
通过上面的测试,我们假设最快的选择器的速度为100ms。其中,5 ms将被用于收集样式。
假设下载另外一个选择器的速度比第一个选择器慢3倍,那么它的加载时间就应该为110ms.
那么,在测试报告中应该为300%的差异,而不是现在的10%
基于这一点,原文作者回答说,虽然我理解本杰明所指的是什么,但我的测试只是为了说明我在这篇文章中的观点 ——
在其他条件不变的情况下,不同的选择器的使用并不会影响性能
本杰明花时间回答了更多的细节:
我完全同意优化选择器没有太多的必要,不过我跟你的原因并不相同:
通过检查选择器,几乎不可能预测给定选择器的最终性能影响。在引擎中,选择器被重新排序、分割、收集和编译。要知道给定选择器的最终性能,您必须知道选择器是如何收集的,它是如何编译的,最后是DOM树是什么样子的?
所有这些在不同的引擎之间是非常不同的,这使得整个过程更加难以预测。
我反对web开发人员优化选择器的第二个理由是,它们可能会使事情变得更糟。关于选择器的错误信息比正确的浏览器兼容信息要多。想要把它做好几乎不可能
然而在开发中,人们会发现CSS的性能问题,并开始一个接一个地删除样式规则,直到问题解决。我认为这是正确的做法,这很容易,而且会带来正确的结果。
原因与结果
如果页面上的DOM元素数量减少了一半,那么所有测试的速度理应都是相对应的减少.但是,很多时候DOM对象的数量并不能大幅度的减少.这让我想知道CSS中未使用的样式的数量会不会对性能产生影响?
另一个测试:我从fiatuk网站抓取了一个臃肿的样式表。它大约有3000行CSS。所有这些不相关的样式都被插入到一个最终的文件中,这个文件中的样式是将我们的DOM对象中的所有的内部a节点变成红色。我在每个浏览器上都做了相同的平均结果
然后我把一半的规则去掉,然后重复测试来进行比较。这里是结果(单位:ms):
Test | Chrome 34 | Firefox 29 | Opera 19 | IE9 | Android 4 |
---|---|---|---|---|---|
所有的样式 | 64.4 | 237.6 | 74.2 | 436.8 | 1714.6 |
一半的样式 | 51.6 | 142.8 | 65.4 | 358.6 | 1412.4 |
当一半的样式被删除时,你可以看到Firefox的东西下降了很多(大约1500行)。在这一点上,Android设备的速度也接近于最慢的选择器的速度。
删除未使用的样式
这种恐怖场景对你来说是不是很熟悉?具有各种选择器的巨大的CSS文件(通常使用的选择器甚至都不工作),更具体的选择器的块更大,更深入,不适用的前缀,杂乱的id,文件大小为50-80KB(有时更多)。
如果您正在处理一个有一个像这样臃肿的CSS文件的代码库,那么没有人确切地知道所有的样式实际上是干什么的
处理这个问题似乎比对所使用的选择器吹毛求疵更有意义。它将产生双倍的影响;用户下载的代码更少,这是一个速度提升。
但是同样,这对CSS的实际性能也没有帮助
括号内的性能
我运行的最后一个测试是配置一堆“昂贵”的CSS来访问页面
.link {
background-color: red;
border-radius: 5px;
padding: 3px;
box-shadow: 0 5px 5px #000;
-webkit-transform: rotate(10deg);
-moz-transform: rotate(10deg);
-ms-transform: rotate(10deg);
transform: rotate(10deg);
display: block;
}
以下是结果:
Test | Chrome 34 | Firefox 29 | Opera 19 | IE9 | Android 4 |
---|---|---|---|---|---|
” 昂贵的样式” | 65.2 | 151.4 | 65.2 | 259.2 | 1923 |
在这里,所有的浏览器都至少比最慢的选择器测试慢了1.5倍,而Android设备比最慢的选择器测试慢了1.3倍,但这还不是全部。 试试看滚动浏览器,页面的样式重绘会让你的电脑崩溃.
实际上,我们在括号里的属性才是真正影响性能的。这是有理由的,一直滚动一个拥有”昂贵”的,不停需要重绘的并且布局一直在变化的页面将会给电脑带来压力。
什么是”昂贵”的样式?
我们怎么知道什么是“昂贵”的样式?值得庆幸的是,我们可以将平时的经验应用到这一点上.任何需要浏览器在绘图前进行操作/计算的东西都将更加昂贵。例如,框阴影、圆角、透明度、过度之类的样式——如果性能是您的优先级,那么任何类似的东西都是您最大的敌人
结论
- 在现代浏览器中大多数的选择器速度都非常快,因此使用不同的选择器来优化性能是没有必要的;
- 过度使用的样式与从未使用的样式所占比例比选择任何选择器消耗的性能更多.所以将CSS库进行拆分,那可能是更好的选择;
- 如果你的CSS库由多人编写,那么可以使用UnCSS或是PurifyCSS这样的工具来自动删除未被使用的样式;
- 明智的使用花括号内的属性才能赢的性能上的收益.在优化时,首先寻找”昂贵”的样式,会为你和用户带来最大的收益
精品好课