1

我仍然无法非常清楚地理解“CSS 是渲染阻塞”的概念。我非常了解 JS 是如何阻止解析器的。但是,前者对我来说仍然有点不清楚。

举个例子:

索引.html:

<!DOCTYPE html>
<html>
<head>
  <title>Some Document</title>
  <link href='cdn1.com/styles1.css' rel="stylesheet"/>
  <link href='cdn2.com/styles2.css' rel="stylesheet"/>
</head>
<body>
   ...
   ...
</body>
</html>

style1.css(来自 cdn1):

body { background: blue }

style2.css(来自 cdn2):

body { background: red }

现在,让我们假设来自 cdn1 的 style1.css 需要1 秒才能加载,而来自 cdn2 的 style2 需要500ms。我想知道最终用户会在以下时间线之间在浏览器中看到的所有事情:

  1. 在时间T < 500 毫秒:是否会有 FOUC 或空白页面,因为 CSS 是渲染阻塞的,并且在我们拥有 styles1.css 文件之前不会构建渲染树
  2. 在时间500ms < T < 1sec 时:是否会出现红色页面(因为 style2.css 已经加载)、FOUC 或仍然是空白页面,原因在第 1 点中提到。

此外,结果在所有浏览器上是否一致,主要是 Edge、Chrome、Firefox 和 Safari?

4

2 回答 2

3

以下示例使用故意延迟的资源来显示发生的情况。因为它每次都使用动态资源来显示不同的 id 并提供缓存清除,所以我不能使用堆栈片段,但我会向您展示关键代码和工作示例的链接。

在第一个示例中,我们有您描述的情况。

<!DOCTYPE html>
<html>
<head>
  <title>Render Blocking Test - A</title>
  <link href='/css/styles1.css?delay=1000&x={cachebuster}' rel="stylesheet"/>
  <link href='/css/styles2.css?delay=5000&x={cachebuster}' rel="stylesheet"/>
</head>
<body>
   <h1>Render Blocking Test - A</h1>
   <b>{cachebuster}</b>
</body>
</html>

每次刷新时,占位符“{cachebuster}”都会被不同的 GUID 替换。两个 CSS 资源的延迟分别为 1 秒和 5 秒,以便更清楚地显示延迟

styles1.css 包含

body { background: blue }

styles2.css 包含

body { background: red }

看到它在这里工作:http: //alohci.net/text/html/render-blocking-a.htm

你会看到页面是空白的,直到 5 秒过去了,所有的 css 资源都被下载了。或者在刷新时,前一页会一直显示,直到 5 秒过去(GUID 在 5 秒后更改)。背景,当它和新内容出现时,立即是红色,而不是白色或蓝色。这就是渲染阻塞的意思——在渲染阻塞资源可用之前,不会完成页面的新渲染。


为了比较,请参见第二个示例。

<!DOCTYPE html>
<html>
<head>
  <title>Render Blocking Test - B</title>
  <link href='/css/styles1.css?delay=1000&x={cachebuster}' rel="stylesheet"/>
</head>
<body>
   <h1>Render Blocking Test - B</h1>
   <b>{cachebuster}</b>
   <script src="/js/script1.js?delay=4000&x={cachebuster}"></script>
   <link href='/css/styles2.css?delay=5000&x={cachebuster}' rel="stylesheet"/>
</body>
</html>

看到它在这里工作:http: //alohci.net/text/html/render-blocking-b.htm

我们在这里得到的是一秒钟的单个渲染阻止资源,然后是一些内容 - 标题和 GUID - 然后是一个需要 4 秒下载的脚本,然后是第二个渲染阻止资源。

在这种情况下,文本和蓝色背景会在 1 秒后出现。加载 parser-blocks 的脚本,所以第二个 css 资源还没有被解析,因此它不能阻止渲染。因此,可以看到蓝色背景。然后脚本加载,第二个 css 资源被解析,渲染块直到它也被加载,此时背景从蓝色变为红色。

最后,您可能会注意到红色背景只需要 5 秒即可出现,而不是您想象的 9 秒。那是因为当解析器被阻塞时解析器仍然可以向前看,认识到它可能需要下载第二个 css 资源并主动获取它,即使在解析器解除阻塞之前它不能使用它。

于 2020-03-21T03:49:54.397 回答
0

你需要知道的是“CSS 对象模型”。CSS 的渲染与 JS 的渲染不一样。当所有的 CSS 被下载后,“主树”就被制作出来了,并且决定了所有inline CSS, internal CSS, external CSS的 - 最终的规则是什么,这些规则将被应用。

这个最终的树被称为https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model

使用 Angular、React、Vue 等 SPA(单页应用程序)的好处是整个页面不会刷新,因此各种步骤如:

  1. 重新加载 HTML Dom
  2. 重新加载 CSS 文件
  3. 制作“CSS 对象模型”
  4. 将“这个 CSS 模型”映射到 HTML-Doms

被保存,这就是为什么这些更快。

  • 希望这个对你有帮助!
于 2020-03-20T13:24:17.813 回答