54

是否值得担心 CSS 渲染性能?或者我们是否应该完全不用担心 CSS 的效率,而只专注于编写优雅或可维护的 CSS?

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

现有证据

GoogleMozilla编写了关于编写高效 CSS 的指南,CSSLint 的规则集包括:

避免使用看起来像正则表达式的选择器 .. 不要使用复杂的相等运算符以避免性能损失

但他们都没有提供任何证据(我能找到)这些影响。

一篇关于高效 CSS 的 css-tricks.com 文章认为(在概述了大量效率最佳实践之后)我们现在应该not .. sacrifice semantics or maintainability for efficient CSS这样做。

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

知道你的手机测试了各种移动浏览器,发现它们都以同样的速度渲染 CSS3(在 12 毫秒内),但看起来他们在 PC 上进行了测试,所以我们无法推断手持设备在 CSS3 中的表现如何一般的。

互联网上有很多 关于如何编写高效 CSS 的文章。 然而,我还没有找到任何全面的证据表明,糟糕的 CSS 实际上会对网站的呈现时间或快速性产生重大影响。

背景

我为这个问题提供了赏金,试图利用 SO 的社区力量来创建一个有用的、经过充分研究的资源。

4

6 回答 6

48

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

这听起来很笼统,但在质疑 CSS 渲染/选择的效率时非常重要。例如,假设您的 CSS 文件中的第一条规则是:

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

因此,当一个非常基本的引擎看到这一点时(并且因为这是第一条规则),它会查看 DOM 中的每个元素,并检查每个元素中是否存在class1。更好的引擎可能会将类名映射到 DOM 元素列表,并使用哈希表之类的东西来进行有效查找。

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

我们的示例“基本引擎”将重新访问 DOM 中的每个元素以查找这两个类。更聪明的引擎会将 DOM 中的元素数量与 class 进行比较,并n('class1')取最小值;假设那是,然后传递所有元素并寻找也有的元素。n('class2')n(str)strclass1class1class2

无论如何,现代引擎都很聪明(比上面讨论的例子更聪明),闪亮的新处理器每秒可以执行数百万(数千万)次操作。您的 DOM 中不太可能有数百万个元素,因此任何选择 ( O(n)) 的最坏情况下的性能无论如何都不会太差。


更新:

为了获得一些实际实用的说明性证据,我决定做一些测试。首先,为了了解我们在实际应用程序中平均可以看到多少个 DOM 元素,我们来看看一些流行网站的网页有多少个元素:

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

总结这些,我们平均得到约 1500 个元素。现在是时候进行一些测试了。对于每个测试,我生成了 1500divs个(嵌套在其他divs一些测试中),每个测试都有适当的属性,具体取决于测试。


测试

样式和元素都是使用 PHP 生成的。我已经上传了我使用的 PHP,并创建了一个索引,以便其他人可以在本地测试:little link


结果:

每个测试在三个浏览器上执行 5 次(报告平均时间):Firefox 15.0 (A)、Chrome 19.0.1084.1 (B)、Internet Explorer 8 (C):

                                                                        A      B      C
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

类似的实验:

显然其他人也进行了类似的实验;这个也有一些有用的统计数据:little link


底线:

除非您关心在渲染时节省几毫秒(1ms = 0.001s),否则不要过多考虑这一点。另一方面,避免使用复杂的选择器来选择大型元素子集是一种很好的做法,因为这会产生一些明显的差异(正如我们从上面的测试结果中看到的那样)。在现代浏览器中,所有常见的 CSS 选择器都相当快。

假设您正在构建一个聊天页面,并且您想要设置所有消息的样式。您知道每条消息都在div具有 a 的 a 中title,并且嵌套在div带有 class的 a 中.chatpage。用于选择消息是正确.chatpage div[title]的,但在效率方面也是不好的做法。给所有消息一个类并使用该类选择它们更简单、更易于维护和更有效。


花哨的单行结论:

任何在“是的,这个 CSS 有意义”范围内的东西都可以

于 2012-09-05T10:50:10.097 回答
13

这里的大多数答案都集中在选择器性能上,好像它是唯一重要的事情。我将尝试介绍一些精灵琐事(剧透警告:它们并不总是一个好主意)、css 使用值性能和某些属性的渲染。

在我得到答案之前,让我先说一下 IMO:就个人而言,我强烈不同意对“基于证据的数据”的声明需求。它只是使性能声明看起来可信,而实际上渲染引擎领域的异构性足以使任何此类统计结论无法衡量并且无法采用或监控。

由于最初的发现很快就过时了,我宁愿看到前端开发人员了解基础原则及其相对于可维护性/可读性布朗尼点的相对价值——毕竟,过早的优化是万恶之源;)


让我们从选择器性能开始:

浅层的,最好是一级的,特定的选择器处理得更快。原始答案中缺少明确的性能指标,但关键点仍然存在:在运行时,HTML 文档被解析为 DOM 树,其中包含N具有平均深度的元素,D并且应用了所有SCSS 规则。为了降低计算复杂度O(N*D*S),您应该

  1. 让最右边的键匹配尽可能少的元素- 选择器从右到左匹配^以获取单个规则资格,因此如果最右边的键与特定元素不匹配,则无需进一步处理选择器和它被丢弃。

    人们普遍认为*应避免选择器,但应进一步考虑这一点。事实上,“正常”的 CSS 重置确实匹配大多数元素 - 当分析此 SO 页面时,重置负责所有选择器匹配时间的大约 1/3,因此您可能更喜欢normalize.css(不过,这只会加起来到3.5 毫秒- 反对过早优化的观点很明显

  2. 避免使用后代选择器,因为它们最多~D需要迭代元素。这主要影响不匹配确认——例如,对于父子关系中的元素,肯定匹配可能只需要一步,但在确认否定匹配之前.container .content,需要遍历 DOM 树。html

  3. 将 DOM 元素的数量最小化,因为它们的样式是单独应用的(值得注意的是,这会被浏览器逻辑所抵消,例如引用缓存和从相同元素回收样式 - 例如,当设置相同同级元素的样式时

  4. 删除未使用的规则,因为浏览器最终不得不评估它们对每个渲染元素的适用性。说得够多了-最快的规则是不存在的规则:)

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


接下来,CSS3的属性表现:

CSS3(除其他外)给我们带来了圆角、背景渐变和阴影变化——随之而来的是一大堆问题。想一想,根据定义,预渲染的图像比必须先渲染的一组 CSS3 规则表现得更好。来自webkit 维基

CSS 中的渐变、阴影和其他装饰应仅在必要时使用(例如,当形状根据内容动态时)——否则,静态图像总是更快。

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


接下来,精灵表现:

避免使用又高又宽的精灵,即使它们的流量足迹相对较小。人们通常会忘记渲染引擎不能与 gif/jpg/png 一起使用,并且在运行时所有图形资源都作为未压缩的位图进行操作。至少它很容易计算:这个精灵的宽度乘以高度乘以每像素四个字节 (RGBA) 是238*1073*4≅1MB. 在同时打开的不同选项卡中的几个元素上使用它,它很快就会产生显着的价值。

在 mozilla webdev 上发现了一个相当极端的例子,但是当使用对角线精灵等有问题的做法时,这一点也不意外。

可以考虑的替代方法是将单独的 base64 编码图像直接嵌入到 CSS 中。


接下来,重排和重绘:

认为回流只能通过 JS DOM 操作触发是一种误解——事实上,任何影响布局的样式的应用程序都会触发它影响目标元素、其子元素和跟随它的元素等。防止不必要的迭代的唯一方法就是尽量避免渲染依赖。一个简单的例子是渲染表

在完全建立布局之前,表格通常需要多次传递,因为它们是元素会影响在 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/

于 2012-09-15T08:24:14.210 回答
5

虽然这是真的

10 年前,计算机速度要慢得多。

如今,您还有更多种类的设备可以访问您的网站。虽然台式机/笔记本电脑已经突飞猛进,但中低端智能手机市场的设备在许多情况下并不比我们十年前的台式机强大多少。

但话虽如此,在为尽可能广泛的设备范围提供良好体验方面,CSS 选择速度可能接近于您需要担心的事情列表的底部。

在此基础上,我无法找到与更现代的浏览器或移动设备相关的特定信息,这些信息与低效的 CSS 选择器苦苦挣扎,但我能够找到以下信息:

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

    现在已经过时了(IE8,Chrome 2),但在某些浏览器中建立各种选择器的效率方面做出了不错的尝试,并且还尝试量化 CSS 规则的 # of CSS 规则如何影响页面呈现时间。

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

    再次过时(IE8,Chrome 6),但在低效的 CSS 选择器中走极端以* * * * * * * * * { background: #ff1; }造成性能下降。

于 2012-09-05T11:08:29.027 回答
4

对于这么大的赏金,我愿意冒着空回答的风险:没有官方的 CSS 选择器会导致渲染明显减慢,并且(在当今快速计算机和快速浏览器迭代的时代)任何找到的东西都很快由浏览器制造商解决。即使在移动浏览器中也没有问题,除非粗心的开发人员愿意使用非标准的 jQuery 选择器。jQuery 开发人员将这些标记为有风险的,并且确实可能​​存在问题。

在这种情况下,缺乏证据就是缺乏问题的证据。因此,请使用语义标记(尤其是 OOCSS),并报告在晦涩的浏览器中使用标准 CSS 选择器时发现的任何减速。

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

于 2012-09-13T19:12:46.410 回答
1

不是 css 是一种无关紧要的让它更快的方法,它一定是你看性能时最后要看的东西。以适合您的方式制作您的 css,编译它。然后把它放在头上。这可能很粗糙,但是当您查看浏览器性能时,它们还有很多其他需要寻找的东西。如果你在数字局工作,你不会因为加载时间增加 1 毫秒而获得报酬。

正如我评论的那样,使用 pagespeed for chrome 它是一个谷歌工具,可以用 27 个参数 css 分析网站,其中之一。

我的帖子只是关注,不希望大约 99% 的网络用户能够打开网站并正确查看,即使是使用 IE7 等的人。比使用 css3 关闭大约10%,(如果事实证明你可以获得额外的 1-10 毫秒的性能)。

大多数人至少有 1mbit/512kbit 或更高,如果你加载一个沉重的网站,加载大约需要 3 秒,但你可以在 css 上节省 10ms?

当涉及到移动设备时,您应该只为移动设备制作网站,因此当您的设备屏幕尺寸小于“宽度”像素时,您就有了一个单独的网站

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

于 2012-09-11T11:19:19.167 回答
0

虽然不直接与代码相关,但使用<link>over@import包含样式表可提供更快的性能。

通过 stevesouders.com “不要使用@import”

本文包含各种类型之间的大量速度测试示例,以及一种类型与另一种类型(例如:一个名为 via 的 CSS 文件<link>也包含@import另一个 css 文件)。

于 2012-09-14T13:38:28.533 回答