34

Let's say we have an HTML page with a single stylesheet <link>. How does the browser take the rules in this stylesheet and apply it to the HTML? I'm not asking about how to make it faster, I want to know how the rendering itself is handled.

Does it apply each rule one-by-one as it parses the stylesheet and render the result progressively? Or, are the CSS file's contents completely downloaded, then fully evaluated, and then applied to the HTML all at once? Or something else?

I ask this after posting an answer earlier on a question about CSS rule order affecting rendering speed, with the assumption that the styles were rendered as the stylesheet loaded, so the first rules would be applied before the last ones, and not all at once. I'm not sure where I picked up the idea, it's just something I have always thought.

I tried a demo on my server that looked like this:

<!DOCTYPE html>
<html>
<head>
   <title>Test</title>
   <link rel="stylesheet" href="test.css" />
</head>
<body></body>
</html>

test.css contents:

html { background:green }
/* thousands of lines of irrelevant CSS to make the download slow */
html { background:red }

Testing in Firefox 5, I expected to see green at first, then turn to red. It didn't happen. I tried with two separate stylesheets with conflicting rules and got the same results. After many combinations, the only way I got it to work was an inline <style> block in the <head>, with the conflicting rules coming from a <link> in the <body> (the body itself was completely empty except for the link tag). Even using an inline style attribute on the <html> tag, and then loading this stylesheet did not create the flicker that I expected.

Are repaints affected in any way by the CSS, or is the final output applied all at once after the entire stylesheet is downloaded and it's rules computed to what the final output should be? Do CSS files download in paralel with the HTML itself or block it (like script tags do)? How does this actually work?

I am not looking for optimization tips, I'm looking for authoritative references on the subject, so that I can cite them in the future. It's been very difficult to search for this information without turning up tons of unrelated material. Summary:

  • Is all CSS content downloaded before any of it is applied? (reference please)
  • How is this affected by things like @import, multiple <link>s, inline style attributes, <style> blocks in the head, and different rendering engines?
  • Does the download of CSS content block the downloading of the HTML document itself?
4

3 回答 3

16

浏览器如何获取此样式表中的规则并将其应用于 HTML?

通常这是以流方式完成的。浏览器将 HTML 标记作为流读取,并将它可以应用的规则应用于它目前看到的元素。(显然这是一种简化。)

一个有趣的相关问答:使用 CSS 选择器从流解析器(例如 SAX 流)中收集 HTML 元素 (当我搜索我想到的文章时,这是一种转移)。


啊,这就是:为什么我们没有父选择器

我们经常认为我们的页面是这些充满元素和内容的完整而完整的文档。但是,浏览器被设计为像流一样处理文档。他们开始从服务器接收文档,并且可以在文档完全下载之前呈现文档。每个节点在收到时都会被评估并渲染到视口。

看一下示例文档的正文:

<body>
   <div id="content">
      <div class="module intro">
         <p>Lorem Ipsum</p>
      </div>
      <div class="module">
         <p>Lorem Ipsum</p>
         <p>Lorem Ipsum</p>
         <p>Lorem Ipsum <span>Test</span></p>
      </div>
   </div>
</body>

浏览器从顶部开始并看到一个body元素。在这一点上,它认为它是空的。它没有评估其他任何东西。浏览器将确定计算的样式是什么并将它们应用于元素。什么是字体、颜色、行高?在它弄清楚这一点之后,它将它绘制到屏幕上。

接下来,它会看到一个divID 为 的元素content。同样,在这一点上,它认为它是空的。它没有评估其他任何东西。浏览器找出样式,然后div绘制。浏览器将确定是否需要重新绘制主体——元素是变宽了还是变高了?(我怀疑还有其他考虑因素,但宽度和高度的变化是子元素对其父元素最常见的影响。)

此过程继续进行,直到到达文档的末尾。

CSS 从右到左进行评估。

要确定一条 CSS 规则是否适用于特定元素,它从规则的右侧开始,并沿左侧运行。

如果你body div#content p { color: #003366; }对每个元素都有这样的规则——当它被渲染到页面上时——它会首先询问它是否是一个段落元素。如果是,它将沿着 DOM 向上运行,并询问它是否div具有内容 ID。如果它找到了它正在寻找的东西,它将继续沿着 DOM 向上,直到它到达body.

通过从右到左工作,浏览器可以确定规则是否适用于它试图更快地绘制到视口的特定元素。要确定哪个规则的性能更高或更低,您需要确定需要评估多少个节点才能确定是否可以将样式应用于元素。


那么为什么没有逐步应用样式表内容(先是绿色,然后是红色)?

认为答案是外部样式表在下载时被解析,但直到整个样式表被解析后才应用。当然,在解析样式表时,浏览器会优化掉不必要和多余的 CSS 规则。

我现在没有任何证据支持这一点,但这种解释对我来说听起来很合理,并且与您所看到的一致,无论是外部样式还是内联样式。

于 2011-08-05T03:45:00.003 回答
9

首先要理解的最重要的事情是,浏览器在下载所有 CSS 之前无法开始绘制页面。(记住,W3C 规范说 CSS 链接只允许在头部,所以当你开始链接到 body 标签中的样式表时,不同的浏览器会以不同的方式处理这种情况。)

现在,将网页作为流读取,并将 CSS 规则应用于 HTML 元素,因为它们被馈送到页面中。引用下面链接的谷歌文章:

当浏览器解析 HTML 时,它会构建一个内部文档树来表示要显示的所有元素。然后,它根据标准 CSS 级联、继承和排序规则将元素与各种样式表中指定的样式进行匹配。

所以现在解决你的问题:

它在解析样式表并逐步呈现结果时是否逐个应用每个规则?或者,是否完全下载了 CSS 文件的内容,然后完全评估,然后一次性应用到 HTML?或者是其他东西?

下载所有 CSS,然后开始从上到下绘制文档。

在 Firefox 5 中测试,我希望一开始会看到绿色,然后变成红色。它没有发生。我尝试使用两个具有冲突规则的单独样式表并得到相同的结果。

这是因为 CSS 是首先下载的,然后当它遇到你的元素时,它只应用红色样式,因为级联是如何工作的。

经过多次组合后,我让它工作的唯一方法是 中的内联块<style><head>冲突规则来自<link><body>

虽然我无法确切说明为什么会发生这种情况,但我想浏览器并没有在 body 标记中查找 CSS,而是开始绘制,遇到 body CSS,然后重新绘制。

重绘是否会受到 CSS 的任何影响?

老实说,我会更担心 JS 导致的重绘。但是,如果您有一个非常大的 DOM,那么以一种不会因为奇怪的定位而导致重排的方式来构建您的 CSS 是有意义的。@Matt 为您提供了一些很好的链接,涵盖了该问题一些很好的资源:

http://www.dayofjs.com/videos/22158462/web-browsers_alex-russel Alex Russell 在大约 36 分钟内详细介绍了 webkit 如何解析 CSS、重排和重绘如何工作以及触发它们的原因。

http://code.google.com/speed/page-speed/docs/rendering.html 这是一篇关于如何优化 CSS 渲染的基础文章

于 2011-08-05T04:19:09.717 回答
1

我不确定标记的答案。我怀疑它的正确性。根据Google Developers的此链接,浏览器首先下载 HTML 文件,当它看到链接到外部资源的 CSS 文件时,它开始下载 CSS 文件,同时为给定的 HTML 文件创建 DOM 结构,因为 CSS 不会影响DOM。请注意,当浏览器下载 CSS 文件时,它不会对文档应用任何样式。

下载 CSS 文件后(假设没有脚本文件)并且如果 DOM 构建完成,浏览器开始将 CSS 属性映射到 DOM 树中的那些节点。在此之后,它会创建另一个名为 Render tree 的树,它将所有应该显示的对象构建为矩形框。只有在完成渲染树后,它才会开始在屏幕上绘画。

总结一下:

  • 浏览器完全下载 CSS 文件。
  • 浏览器在下载时不会对页面应用任何样式。只有在下载完成后,它才会开始映射规则。
  • 这些规则仅在渲染树构建阶段应用。
  • 下载 CSS 文件不会阻止 HTML 下载。你要注意浏览器

首先下载所有 html 文件,然后下载样式和脚本文件。

您可以使用 chrome 的开发者控制台来检查这些。使用时间线选项卡查看所有这些。

此处显示了时间线图像的示例。我在此答案开头发布的链接解释了一切。

于 2015-06-12T04:12:43.533 回答