Skip to content

浏览器怎么把页面画出来? ​

HTML 解析成 DOM,CSS 解析成 CSSOM,两者合成渲染树,然后布局、绘制、合成。同步脚本会挡住 HTML 解析;CSS 会挡住渲染,也会挡住它后面的同步脚本。

原理 ​

解析 HTML 时遇到资源会交给预加载扫描器提前下载。构建出的渲染树只包含要显示的节点,display: none 的节点不在里面,visibility: hidden 仍占位置。

接下来三步:

  1. 布局(回流):算出每个节点的几何信息。
  2. 绘制(重绘):生成绘制指令,例如背景、文字、边框。
  3. 合成:把图层交给 GPU 合到屏幕上。transform 和 opacity 通常只走合成,不必重新布局和绘制。

改宽度、位置会触发布局,往往连带重绘。只改颜色通常只重绘。连续读 offsetWidth 又写 style,会迫使浏览器提前布局,这就是强制同步布局。

脚本的三种加载:

写法下载执行时机对解析的影响
默认 script遇到就下载马上执行挡住解析
async并行下载下完就执行,顺序不定执行时暂停解析
defer并行下载文档解析完后按顺序执行不挡住解析

DOMContentLoaded 在文档解析完成、defer 脚本执行完之后触发,不等图片。它前面的同步脚本、以及这些脚本所等待的样式表,会把它推迟。load 要等样式、图片等子资源都加载完。

追问 ​

CSS 放头部、JS 放底部,现在还对吗?

样式仍放头部,避免先画出没样式的 HTML。脚本优先用 defer 放在头部,既不挡解析,又能保证顺序。需要尽早执行的独立脚本才用 async。

display: none 和 visibility: hidden 的布局差别?

display: none 不生成盒子,不参与布局。visibility: hidden 看不见,但盒子还在。

易错点 ​

  • 渲染树不是 DOM 树的别名,它还要结合 CSS,并丢掉不显示的节点。
  • async 不能保证执行顺序,有依赖的脚本不要用它。
  • 动画能用 transform / opacity 解决时,不要改 top、left、width。

相关 ​