哪些CSSselect器或规则可以显着影响现实世界中的前端布局/渲染性能?

CSS渲染性能值得担心吗? 或者我们应该不用担心CSS的效率问题,只关注编写优雅或可维护的CSS呢?

这个问题的目的是为前端开发人员提供一个有用的资源,在这些资源上CSS的某些部分实际上可能会对设备性能产生重大影响,以及哪些设备/浏览器或引擎可能受到影响。 这不是一个关于如何编写优雅或可维护的CSS的问题,它纯粹是关于性能(尽pipe希望这里写的可以通知更多关于最佳实践的一般性文章)。

现有的证据

Google和Mozilla已经编写了编写高效CSS的指导方针, CSSLint的规则包括:

避免看起来像正则expression式的select器。不要使用复杂的相等运算符来避免性能损失

但他们都没有提供任何证据(我能find)的影响。

关于高效CSS的css-tricks.com文章指出(在概述一系列效率最佳实践之后),我们不应该not .. sacrifice semantics or maintainability for efficient CSS

一个完美杀死博客文章build议border-radiusbox-shadow渲染比简单的CSS规则慢几个数量级。 这在Opera的引擎中是非常重要的,但在Webkit中是微不足道的。 此外,一个CSS杂志的基准testing发现,CSS3显示规则的渲染时间是微不足道的,并且比使用图像渲染等效效果要快得多。

知道你的手机testing了各种移动浏览器 ,发现他们都渲染CSS3同样微不足道(12毫秒),但它看起来像他们做了在PC上的testing,所以我们不能推断任何有关手持设备如何执行CSS3一般。

互联网上有 很多关于如何编写高效CSS的文章。 然而,我还没有find任何综合的证据,认为严重考虑CSS实际上对网站的渲染时间或活动有重大影响。

背景

退后一步,我要去尝试科学http://brightgreenscotland.org/wp-content/uploads/2010/09/stand-back-Im-going-to-try-science.png

我提出了这个问题的赏金,试图利用SO的社区力量来创造一个有用的研究资源。

首先想到的是:您使用的渲染引擎有多聪明?

这听起来很普通,在质疑CSS渲染/select的效率的时候很重要。 例如,假设你的CSS文件的第一条规则是:

 .class1 { /*make elements with "class1" look fancy*/ } 

所以当一个非常基本的引擎看到这个(并且因为这是第一个规则),它会查看DOM中的每个元素,并检查每个元素中是否存在class1 。 更好的引擎可能会将类名映射到DOM元素列表,并使用类似散列表的方式进行高效查找。

 .class1.class2 { /*make elements with both "class1" and "class2" look extra fancy*/ } 

我们的例子“基本引擎”会去并重新浏览DOM中的每个元素,寻找这两个类。 一个聪明的引擎将比较n('class1')n('class2') ,其中n(str)是DOM中str类的元素个数,取最小值; 假设是class1 ,然后传递所有具有class1的元素,寻找具有class2元素。

在任何情况下,现代引擎都是聪明的(比上面讨论的例子更聪明),shiny的新处理器每秒可以完成数百万次(数千万)的操作。 在DOM中有几百万个元素是不太可能的,所以对于任何select( O(n) )来说,最坏的情况都不会太糟糕。


更新:

为了得到一些实际的说明性certificate,我决定做一些testing。 首先,为了了解在实际应用程序中平均可以看到多less个DOM元素,让我们来看看一些热门网站的网页有多less元素:

Facebook: 〜1900个元素(在我的个人主页上testing过)。
Google :〜340个元素(在主页面上testing过,没有search结果)。
Google:约950个元素(在search结果页面上testing)。
雅虎 :1400个元素(在主页上testing)。
Stackoverflow: 〜680个元素(在问题页面上testing)。
AOL:约1060个元素(在主页上testing)。
维基百科: 〜6000个元素,其中2420不是spansanchors (在关于Glee的维基百科文章上testing过 )。
Twitter: 〜270个元素(在主页上testing)。

总结起来,我们平均得到1500个元素。 现在是时候做一些testing。 对于每个testing,我生成了1500个divs (嵌套在一些其他divs进行一些testing),每个testing都有相应的属性。


testing

样式和元素都是使用PHP生成的。 我已经上传了我使用的PHP,并创build了一个索引,以便其他人可以在本地进行testing: 小链接 。


结果:

每个testing在三个浏览器上进行5次(平均时间被报告): Firefox 15.0 (A), Chrome 19.0.1084.1 (B), Internet Explorer 8 (C):

  ABC 1500 class selectors (.classname) 35ms 100ms 35ms 1500 class selectors, more specific (div.classname) 36ms 110ms 37ms 1500 class selectors, even more specific (div div.classname) 40ms 115ms 40ms 1500 id selectors (#id) 35ms 99ms 35ms 1500 id selectors, more specific (div#id) 35ms 105ms 38ms 1500 id selectors, even more specific (div div#id) 40ms 110ms 39ms 1500 class selectors, with attribute (.class[title="ttl"]) 45ms 400ms 2000ms 1500 class selectors, more complex attribute (.class[title~="ttl"]) 45ms 1050ms 2200ms 

类似的实验:

其他人显然也进行过类似的实验, 这一个也有一些有用的统计数据: 小链接 。


底线:

除非您在渲染时节省几毫秒(1ms = 0.001s),否则不要打扰到这个太多的想法。 另一方面,避免使用复杂的select器来select大的元素子集是一个很好的做法,因为这可以产生一些明显的差异(正如我们从上面的testing结果中可以看到的那样)。 所有常见的CSSselect器在现代浏览器中都相当快速。

假设您正在构build一个聊天页面,并且想要设置所有消息的样式。 你知道每个消息是在一个div中有一个title ,并且嵌套在一个带有.chatpage类的div 。 使用.chatpage div[title]来select消息是正确的,但是效率方面也是不好的做法。 给所有消息一个类,并且使用这个类来select它们更简单,更可维护,更高效。


花哨的单线结论:

任何在“是的,这个CSS是有意义的”的限制是没有问题的。

这里的大部分答案集中在select器的性能,就好像它是唯一重要的东西。 我会尝试涵盖一些spriting琐事( 扰stream警报:他们并不总是一个好主意 ),CSS使用价值的性能和某些属性的渲染。

在我find答案之前,让我把一个国际海事组织排除在外: 我个人非常不同意“证据数据”的需求 。 它只是使得性能声明显得可信,而实际上渲染引擎的领域是非常不够的,使得任何这样的统计结论不准确以及不切实际的采用或监控。

原来的发现很快就过时了,我宁愿看到前端开发者对于可维护性/可读性布朗尼点的基础原理及其相对价值的理解 – 毕竟, 不成熟的优化是万恶的根源 ;)


让我们从select器性能开始:

浅,最好是一个级别的特定select器处理得更快。 原始答案中缺less明确的性能指标,但关键点仍然是:在运行时,HTML文档被parsing为包含N个平均深度为D元素的DOM树,并且总共应用了S CSS规则。 为了降低计算复杂度O(N*D*S) ,您应该

  1. 使最右边的键匹配尽可能less的元素 – select器从右到左匹配个别规则资格,所以如果最右边的键不匹配特定元素,则不需要进一步处理select器,它被丢弃。

    人们普遍认为应该避免*select器,但应该进一步考虑这一点。 实际上,“正常”的CSS重置确实与大多数元素相匹配 – 当这个SO页面被分析时,重置是所有select器匹配时间的三分之一,所以你可能更喜欢normalize.css ( 仍然只是加起来到3.5ms – 反对过早优化的观点很强

  2. 避免后代select器,因为它们需要重复达到〜D个元素。 这主要影响了不匹配的确认 – 例如,正面的.container .content匹配可能只需要一个父 – 子关系中的元素的一个步骤,但是在负匹配之前,需要将DOM树一直遍历到html证实。

  3. 尽量减lessDOM元素的数量,因为它们的样式是单独应用的( 值得注意的是,这被浏览器逻辑所抵消,例如引用caching和来自相同元素的回收样式 – 例如,样式相同的同胞

  4. 删除不使用的规则,因为浏览器不得不评估每个元素的适用性。 足够的说 – 最快的规则是不在那里:)

从渲染引擎性能的angular度来看,这些会导致可量化的(但是,取决于页面,不一定是可感知的)改进,然而总是有额外的因素,例如stream量开销和DOMparsing等等。


接下来,CSS3属性的performance:

CSS3给我们带来了(除其他外)圆angular,背景渐变和阴影变化 – 与他们一起,一大堆的问题。 想想看, 根据定义 ,预渲染的图像比首先渲染的一组CSS3规则要好。 来自webkit wiki :

CSS中的渐变,阴影和其他装饰应该仅在必要时使用(例如,当形状是基于内容的dynamic的时候) – 否则静态图像总是更快。

如果这还不够糟糕,则可能必须在每次重绘/重排事件时重新计算渐变等(下面会有更多详细信息)。 记住这一点,直到大多数用户可以像这样浏览一个css3重的页面,没有明显的滞后。


接下来,精神performance:

即使他们的交通足迹相对较小,也要避免高高在上的精灵 。 通常我们会忘记渲染引擎不能使用gif / jpg / png,而在运行时,所有graphics资源都以未压缩位图的forms运行。 至less它很容易计算: 这个精灵的宽度乘以每个像素四个字节(RGBA)的高度是238*1073*4≅1MB 。 在不同的同时打开的选项卡上使用它几个元素,并迅速增加一个重要的价值。

一个相当极端的情况已经在mozilla webdev上find了 ,但是当使用像对angular线精灵这样的可疑实践时,这并不意外。

另一个需要考虑的是直接embedded到CSS中的单独的base64编码图像。


接下来,回stream和重绘:

这是一个错误的概念, 回stream只能触发JS DOM操作 – 事实上,任何影响布局的应用程序的应用程序会触发它影响目标元素,其子元素和后面的元素等。唯一的方法来防止不必要的迭代这是尝试和避免渲染依赖 。 一个简单的例子就是渲染表格 :

在布局完全build立之前,表格通常需要多次传递,因为它们是元素可能影响DOM之前出现的其他元素的显示的罕见情况之一。 想象一下,表格末尾的单元格内容非常宽,导致列的大小被完全调整。 这就是为什么表不在所有浏览器中逐步呈现的原因。


如果我记起一些重要的东西,我会进行编辑。 一些链接完成:

http://perfectionkills.com/profiling-css-for-fun-and-profit-optimization-notes/

http://jacwright.com/476/runtime-performance-with-css3-vs-images/

https://developers.google.com/speed/docs/best-practices/payload

https://trac.webkit.org/wiki/QtWebKitGraphics

https://blog.mozilla.org/webdev/2009/06/22/use-sprites-wisely/

http://dev.opera.com/articles/view/efficient-javascript/

虽然这是事实

十年前电脑的速度比较慢。

您还有更多的设备可以访问您的网站这些天。 虽然台式机/笔记本电脑突飞猛进,但是中低端智能手机市场的设备在很多情况下并不比十年前的台式机强大。

但是说了CSSselect速度可能接近您需要担心的事情列表的底部,从尽可能广泛的设备范围提供良好的体验。

在这方面进行扩展,我无法find有关更现代的浏览器或移动设备与低效的CSSselect器苦苦挣扎的具体信息,但我能find以下内容:

  1. http://www.stevesouders.com/blog/2009/03/10/performance-impact-of-css-selectors/

    现在已经过时了(IE8,Chrome 2),但在某些浏览器中尝试build立各种select器的效率,并试图量化CSS规则如何影响页面渲染时间。

  2. http://www.thebrightlines.com/2010/07/28/css-performance-who-cares/

    再次相当过时(IE8,Chrome 6),但在效率低下的CSSselect器进入极端* * * * * * * * * { background: #ff1; } * * * * * * * * * { background: #ff1; }build立性能下降。

对于这样一个巨大的奖金,我愿意冒着空的答案:没有官方的CSSselect器,导致任何可观的减速在渲染,并且(在这一天的快速计算机和快速浏览器迭代)任何发现很快由浏览器制造商解决。 即使在移动浏览器中也没有问题,除非不情愿的开发人员愿意使用非标准的jQueryselect器。 这些被jQuery开发人员标记为风险,确实可能是有问题的。

在这种情况下,缺乏证据certificate缺乏问题。 因此,使用语义标记(尤其是OOCSS),并报告在隐蔽浏览器中使用标准CSSselect器时发现的任何放慢速度。

未来的人们:2012年的CSS性能问题已经成为过去。

是不是一个无关紧要的方式来使其更快,它必须是你看性能的最后一件事情。 让你的CSS,以任何方式套房你,编译它。 然后把它放在头上。 这可能是粗略的,但是当你寻找浏览器的性能的时候,它们还有很多其他的东西需要去寻找。 如果你在一个数字局工作,你不会在加载时间内获得额外的1ms。

正如我评论使用页面速度铬它的谷歌工具,分析27个参数网站的CSS是其中之一。

我的post正好关心,不愿意有99%左右的网民可以打开网站看看吧,甚至IE7的人也这样。 比使用css3closures10%左右,(如果事实certificate你可以得到额外的1-10ms的性能)。

大多数人拥有至less1mbit / 512kbit或更高,如果你加载一个重的网站需要大约3 secounds来加载,但你可以节省10ms,也许在CSS?

而当涉及到移动设备,你应该只为手机网站,所以当你有一个屏幕尺寸小于“宽度”px的设备,你有一个单独的网站

请在下面评论这是我的观点和我个人的web开发经验

尽pipe不直接与代码相关,但使用@import上的<link>来包含样式表会提供更快的性能。

'不要通过stevesouders.com使用@import'

文章包含了各种types之间的速度testing示例,以及包含另一种types(例如:通过<link>调用的CSS文件还包含到另一个css文件的@import )。