CSS 和 JS 文件是否阻塞页面渲染

分析 CSS 和 JavaScript 文件的下载、解析对 DOM 渲染的阻塞关系

问题

HTML 文档渲染过程中,CSS 文件和 JS 文件的下载是否会阻塞渲染?

解答

浏览器渲染机制

浏览器渲染进程中,JS 引擎线程和 GUI 渲染线程是互斥的。执行 JS 时页面会停止解析和渲染,这是为了避免 JS 修改 DOM 时造成渲染冲突。由于线程间通信代价高,这也是 JS 操作 DOM 效率不高的原因。

CSS 阻塞情况

CSS 不阻塞 DOM 解析,但阻塞 DOM 渲染

因为 CSSOM Tree 要和 DOM Tree 合成 Render Tree 才能绘制页面。

<button class="btn btn-primary">test1</button>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css">
<div>test2</div>

上面代码中,test1 在 CSS 下载前显示默认样式,test2 在 CSS 下载完成前不会显示。

CSS 阻塞后续 JS 执行

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css">
<script>
    alert('ok')
</script>

alert 会在 CSS 下载并解析完成后才执行。

CSS 不阻塞前面的 JS 执行

<script>
    alert('ok')
</script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css">

alert 会在 CSS 下载前执行。因此,不操作 DOM 的 JS 可以放在 CSS 前面提前执行。

JS 阻塞情况

JS 阻塞 DOM 和 CSS 的解析与渲染

<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<div>test</div>

test 会在 JS 下载并执行完成后才显示。

JS 不阻塞前面的 HTML 和 CSS 解析

<div>test</div>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>

test 会在 JS 下载前就显示。

渲染时机

浏览器会尽早将内容呈现到屏幕上,不会等所有 HTML 解析完成。解析完一部分就显示一部分,同时继续下载其余内容。

<div>test1</div>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<div>test2</div>

test1 会在 JS 下载前渲染,test2 会在 JS 下载并执行后渲染。

文件下载

文件下载不会被阻塞。浏览器主线程会在页面解析前开启下载,即使在脚本执行前删除脚本标签,文件也会继续下载。

关键点

  • CSS 不阻塞 DOM 解析,但阻塞 DOM 渲染和后续 JS 执行
  • JS 阻塞 DOM 和 CSS 的解析与渲染
  • CSS 和 JS 都不阻塞前面内容的解析和渲染
  • 浏览器会渐进式渲染,解析一部分显示一部分
  • 文件下载不会被阻塞,浏览器会提前开启下载