浏览器加载html、css、js的顺序
最近在回顾基本知识,就顺便记录下浏览器从加载 HTML → CSS → JS 到页面渲染的过程,简单说下。
为什么要了解浏览器加载流程?
前端性能优化、SEO、首屏渲染速度、闪烁问题、Hydration mismatch 这些常见问题,本质上都与浏览器加载顺序有关,特别是排查的时候会心态爆炸。
例如实际上用 nuxtjs3 写项目的时候,首页加载老是会出现 Hydration completed but contains mismatches.,diu查了好久,把页面渲染顺序都进行调式,最后发现不是页面问题,而是在 nuxt.config.ts 多配置了首页缓存的,导致每次两端渲染不同:
nitro.prerender.routes: ['/']
routeRules: {
"/": { prerender: true },
},
虽说不是加载流程问题,但是好歹还是能排查一些问题的,掌握的话查起来还是很快的。
浏览器加载网页的完整过程
下面是简化但准确的流程:
HTML 下载 → 解析 HTML → 下载/解析 CSS → 构建渲染树 → Layout → Paint
JavaScript 则会在关键步骤中插入“阻塞点”,它会影响解析顺序与渲染顺序。
一、浏览器加载 HTML(构建 DOM)
浏览器首先从服务器下载 HTML 文件,然后:
- 从 上到下 解析
- 一边读一边构建 DOM 树
在解析 HTML 的过程中,如果遇到外部资源,就会触发对应行为:
遇到 <link rel="stylesheet">
- 浏览器会并行下载 CSS
- 不会阻塞 HTML 解析
- 但 CSS 解析未完成前无法渲染页面(渲染阻塞)
遇到 <script>(无 async/defr)
- 阻塞 HTML 解析
- 下载 JS
- 执行 JS
- 继续解析 HTML
也就是 普通 script 会暂停 DOM 的构建。
二、CSS 加载与解析(构建 CSSOM)
CSS 文件下载后需要被解析成 CSSOM(CSS 对象模型)。
CSS 是渲染阻塞的:
CSSOM 未构建完成 → 浏览器无法进行首次渲染
但 CSS 不会阻塞 HTML 的解析,只会阻塞渲染阶段。
三、DOM + CSSOM → Render Tree(渲染树)
当 DOM 和 CSSOM 都准备好后,浏览器把它们合成 Render Tree:
- DOM 决定页面结构
- CSS 决定页面样式
两者合成渲染树后,才可以进行 Layout & Paint。
四、Layout(布局计算)
浏览器计算每个节点的:
- 大小
- 位置
- 盒模型
五、Paint(绘制)
将渲染树绘制到屏幕像素上。
此时用户才看到页面。
六、JavaScript 对加载顺序的影响
JavaScript 的三种加载方式:
1. 普通 <script>(最慢)
阻塞 HTML 解析 → 下载 JS → 执行 JS → 继续解析 HTML
2. <script defer>(推荐)
并行下载 JS
HTML 完成后按顺序执行
不阻塞解析
在 DOMContentLoaded 之前执行
3. <script async>(最快,但不稳定)
并行下载
下载完立即执行(可能打断 HTML 解析)
执行顺序无法保证
浏览器加载流程
sequenceDiagram
participant B as Browser
participant H as HTML Parser
participant C as CSS Parser
participant J as JS Engine
B->>H: 下载并解析 HTML
H->>C: 遇到 <link> 开始下载 CSS(不阻塞 HTML)
C->>C: 解析 CSS(阻塞渲染)
H->>J: 遇到普通 <script> 下载并执行(阻塞 HTML)
H->>H: DOM Tree 构建完毕
C->>C: CSSOM 构建完毕
H->>B: DOM + CSSOM → Render Tree
B->>B: Layout(布局计算)
B->>B: Paint(绘制)
B->>User: 页面显示
最终总结(记住这 7 句话就够了)
- HTML 自上而下解析,构建 DOM
- CSS 加载不阻塞 HTML,但阻塞渲染
- 普通 script 会阻塞 HTML 解析
- async 脱离顺序执行
- defer 按顺序、在 HTML 完成后执行
- DOM + CSSOM 才能进行渲染
- Layout → Paint 才真正显示页面

浙公网安备 33010602011771号