如何通过浏览器应用CSS,并重新受其影响?

时间:2011-08-05 03:36:19

标签: html css browser repaint rendering-engine

假设我们有一个带有单个样式表<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本身一起下载或阻止它(如脚本标签那样)?这实际上是如何工作的?

我不是在寻找优化技巧,我正在寻找有关该主题的权威参考资料,以便我将来可以引用它们。如果不翻出大量不相关的材料,就很难搜索这些信息。总结:

  • 是否在应用任何之前下载了所有CSS内容? (请参考)
  • 这会受到@import,多个<link>,内联样式属性,头部<style>块以及不同呈现引擎等因素的影响?
  • CSS内容的下载会阻止HTML文档本身的下载吗?

3 个答案:

答案 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的树,它构建了应显示的所有对象,如矩形框。只有在完成渲染树后,它才会开始绘制到屏幕上。

总结:

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

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

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

时间轴图像的样本显示为here。我在本回答开头发布的链接解释了一切。