假设我们有一个带有单个样式表<link>
的HTML页面。浏览器如何获取此样式表中的规则并将其应用于HTML?我不是在问如何让它更快,我想知道如何处理渲染本身。
它是否逐个应用每个规则,因为它会解析样式表并逐步呈现结果?或者,CSS文件的内容是否已完全下载,然后进行全面评估,然后一次性应用于HTML?或其他什么?
我之前在a question about CSS rule order affecting rendering speed上发布了一个答案之后问我这个问题,假设样式已经作为加载了样式表,所以第一个规则将在最后一个之前应用,而不是一次全部。我不确定我在哪里接受这个想法,这只是我一直想到的。
我在我的服务器上尝试了一个看起来像这样的演示:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<link rel="stylesheet" href="test.css" />
</head>
<body></body>
</html>
test.css
内容:
html { background:green }
/* thousands of lines of irrelevant CSS to make the download slow */
html { background:red }
在Firefox 5中测试,我希望首先看到绿色,然后变成红色。它没有发生。我尝试使用两个具有冲突规则的单独样式表并获得相同的结果。经过多次组合之后,我使用它的唯一方法是在<style>
中使用内联<head>
块,其中的冲突规则来自<link>
中的<body>
(除了链接标记外,正文本身是完全空的。即使在style
标记上使用内联<html>
属性,然后加载此样式表也不会产生我预期的闪烁。
CSS是否以任何方式影响重新绘制,或者是在下载整个样式表后是否同时应用了最终输出,并根据最终输出计算规则? CSS文件是否与HTML本身一起下载或阻止它(如脚本标签那样)?这实际上是如何工作的?
我不是在寻找优化技巧,我正在寻找有关该主题的权威参考资料,以便我将来可以引用它们。如果不翻出大量不相关的材料,就很难搜索这些信息。总结:
@import
,多个<link>
,内联样式属性,头部<style>
块以及不同呈现引擎等因素的影响?答案 0 :(得分:16)
浏览器如何获取此样式表中的规则并将其应用于HTML?
通常,这是以流式方式完成的。浏览器将HTML标记作为流读取,并将其可以应用的规则应用到目前为止看到的元素。 (显然这是一种简化。)
一个有趣的相关Q&amp; A:Use CSS selectors to collect HTML elements from a streaming parser (e.g. SAX stream) (当我搜索我想到的文章时转移)。
啊,这是:Why we don't have a parent selector。
我们经常将我们的页面视为这些完整且完整的文档,其中包含元素和内容。但是,浏览器旨在处理像流一样的文档。他们开始从服务器接收文档,并可以在文档完全下载之前呈现文档。每个节点都会在收到时评估并呈现给视口。
查看示例文档的正文:
<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
元素。在此刻, 它认为它是空的。它尚未评估任何其他内容。浏览器 将确定计算出的样式是什么,并将它们应用于 元件。什么是字体,颜色,线高?之后 想出这个,它把它画在屏幕上。接下来,它会看到ID为
div
的{{1}}元素。再次,在这 点,它认为它是空的。它尚未评估任何其他内容。该 浏览器计算出样式,然后content
被绘制。该 浏览器将确定是否需要重新绘制正文 - 元素 变宽还是变高? (我怀疑还有其他考虑因素 宽度和高度的变化是子元素最常见的效果 对他们的父母有所帮助。)此过程一直持续到文档结束。
CSS从右到左进行评估。
确定CSS规则是否适用于特定元素 从规则的右边开始,然后继续工作。
如果您有
div
之类的规则 对于每个元素 - 当它被呈现到页面时 - 它将首先询问是否 这是一个段落元素。如果是的话,它会在DOM上运行起来 询问它是否是带有内容ID的body div#content p { color: #003366; }
。如果它找到它正在寻找的东西 因为它会继续向上移动,直到达到div
。通过从右到左工作,浏览器可以确定是否有规则 适用于它试图绘制的特定元素 视口快得多。确定哪个规则更多或更少 在性能方面,您需要确定需要评估的节点数量 确定样式是否可以应用于元素。
那么为什么样式表内容不是逐步应用的(先绿色,然后是红色)?
我认为答案是外部样式表在下载时解析,但在解析整个样式表之前不会应用。当然,在解析样式表时,浏览器会优化掉不必要的冗余CSS规则。
我现在没有任何证据证明这一点,但这种解释对我来说听起来很合理,并且同意你所看到的内容,包括外部和内联样式。
答案 1 :(得分:9)
要理解的第一个也是最重要的一点是,在下载所有CSS之前,浏览器无法开始绘制页面。 (请记住,W3C规范说CSS链接只允许在头部,所以当你开始链接到body标签中的样式表时,不同的浏览器会以不同的方式处理这种情况。)
现在,网页被视为一个流,并且当CSS元素被送入页面时,CSS规则将应用于HTML元素。引用下面链接的Google文章:
当浏览器解析HTML时,它会构造一个内部文档树,表示要显示的所有元素。然后根据标准的CSS级联,继承和排序规则,将元素与各种样式表中指定的样式进行匹配。
现在解决你的问题:
它是否逐个应用每个规则,因为它会解析样式表并逐步呈现结果?或者,CSS文件的内容是否已完全下载,然后进行全面评估,然后立即应用于HTML?或其他什么?
下载所有CSS,然后开始从上到下绘制文档。
在Firefox 5中测试,我希望首先看到绿色,然后变成红色。它没有发生。我尝试使用两个具有冲突规则的单独样式表并获得相同的结果。
这是因为CSS首先全部下载,然后当它遇到你的元素时它才会应用红色样式,因为级联的工作原理。
经过多次组合后,我使用它的唯一方法是
<style>
中的内联<head>
块,其中<link>
的{{1}}冲突来自<body>
}
虽然我不能确切地说出为什么会发生这种情况,但我认为浏览器并没有在body标签中寻找CSS,开始绘画,遇到了身体CSS,然后重新绘制。
CSS会以任何方式影响重拍吗?
老实说,我会更担心JS引起的重绘。但是如果你有一个非常大的DOM,那么构造你的CSS是有意义的,这样你就不会因为奇怪的定位而导致回流。 @Matt为您提供了一些涵盖该问题的良好链接 一些好的资源:
http://www.dayofjs.com/videos/22158462/web-browsers_alex-russel 关于webkit如何解析CSS,回流和重绘如何工作以及触发它们的原因,Alex Russell详细介绍了36分钟。
http://code.google.com/speed/page-speed/docs/rendering.html 这是关于如何优化CSS渲染的基础文章
答案 2 :(得分:1)
我不确定明确的答案。我怀疑它是否正确。 根据这个link from Google Developers,浏览器首先下载HTML文件,当它看到链接到外部资源的CSS文件时,它开始下载CSS文件,同时它同时为给定的HTML文件创建DOM结构,因为CSS不会影响DOM。请注意,当浏览器下载CSS文件时,它不会将任何样式应用于文档。
下载CSS文件(假设没有脚本文件)并且DOM构造完成后,浏览器开始将CSS属性映射到DOM树中的那些节点。在此之后,它创建了另一个名为Render tree的树,它构建了应显示的所有对象,如矩形框。只有在完成渲染树后,它才会开始绘制到屏幕上。
总结:
首先下载所有html文件,然后下载样式和脚本文件。
您可以使用chrome的开发者控制台来检查这些内容。使用时间线选项卡查看所有这些内容。
时间轴图像的样本显示为here。我在本回答开头发布的链接解释了一切。