文章中英模式
常見的前端面試題目 - 頁面載入 - 解釋網頁的渲染過程(CRP路徑)
深入解析瀏覽器的關鍵渲染路徑(CRP),包含 DOM、CSSOM、渲染樹的構建過程,以及重排、重繪的優化策略和面試常見問題的完整解答。
文章中英模式

懶得看文章?那就來看影片吧
基本概念
瀏覽器將 HTML、CSS 和 JavaScript 轉換為像素的過程稱為關鍵渲染路徑(Critical Rendering Path,簡稱 CRP)。理解這個過程對於優化網頁效能至關重要。
使用者請求 URL ex: https://www.google.com
│
↓
伺服器處理請求 ─────────────────────────────┐
│ │
├─→ SSR (Server-Side Rendering) │
│ 伺服器生成完整 HTML │
│ │
├─→ SSG (Static Site Generation) │
│ 返回預先生成的靜態 HTML │
│ │
└─→ SPA (Single Page Application) │
返回基礎 HTML 框架 │
│ │
↓ │
HTML 返回瀏覽器 ◄───────────────────────────┘
│
↓
HTML ──────┐
↓
DOM Tree CSS ──────┐
│ ↓
│ CSSOM Tree
│ │
└─────────┬─────────┘
↓
Render Tree ◄─── JavaScript 執行
│ (可修改 DOM 和 CSSOM)
↓
Layout
│
↓
Paint
│
↓
Composite1. HTML 解析 → DOM Tree
瀏覽器將 HTML 轉換為 DOM (Document Object Model),作為網頁的物件表示和 JavaScript 操作介面。解析過程是漸進式的,允許逐步處理內容。
2. CSS 解析 → CSSOM Tree
CSS 被解析為 CSSOM (CSS Object Model),這是渲染阻塞資源,必須完成構建才能進行下一步。
3. JavaScript 執行
JavaScript 是解析阻塞資源,當瀏覽器遇到 script 標籤時,會暫停 DOM 構建,先下載並執行 JavaScript。JavaScript 可以修改 DOM 和 CSSOM,因此必須等待前面的 CSS 解析完成。使用 async 或 defer 屬性可改變執行時機。
4. DOM + CSSOM → Render Tree
結合 DOM 和 CSSOM 形成渲染樹,只包含可見元素(display: none 的元素會被排除)及其樣式信息。
5. Layout(Reflow)
計算每個可見元素的精確位置和大小,確定其在視窗中的定位。視窗大小改變時會觸發重新布局。
6. Paint(Repaint)
將布局轉換為實際像素,包括文字、顏色、邊框、陰影等視覺效果,通常在多個層上進行。
7. Composite
將不同繪製層合成最終畫面,處理層疊順序和透明度。使用 GPU 加速可提升性能。
效能優化建議
最小化關鍵資源
- •減少 HTML、CSS、JavaScript 檔案大小
- •移除未使用的 CSS/JavaScript
- •使用 Code Splitting 和延遲加載
減少重排和重繪
- •批量修改 DOM
- •使用 CSS Transform 和 Opacity 進行動畫
- •避免頻繁改變元素位置和大小
🔥 常見面試題目
(一)什麼是 Reflow 和 Repaint?它們的區別是什麼?
解答:
- •Reflow(重排):當元素的大小、位置或文檔流中的位置發生改變時觸發
- •Repaint(重繪):當元素外觀改變但不影響佈局時觸發,如顏色、背景等變化
- •Reflow 一定會導致 Repaint,但 Repaint 不一定會導致 Reflow
(二)為什麼說 CSS 是渲染阻塞資源?
解答:
- •CSS 被視為渲染阻塞資源是因為瀏覽器需要等待 CSSOM 完全構建後才能進行渲染樹的構建
- •即使 JavaScript 不依賴 CSS,如果存在未完成下載的樣式表,JavaScript 執行也會被阻塞
- •這是為了確保頁面渲染的正確性和一致性
(三)會影響 Reflow 和 Repaint 的 CSS 屬性有哪些?如何避免頻繁觸發?
解答:
- •觸發 Reflow 的屬性:width、height、margin、padding、border、position、top、left、right、bottom、font-size、font-family、display、float
- •主要觸發 Repaint 的屬性:color、background、visibility、text-decoration、box-shadow、outline
- •高效能屬性:transform、opacity、filter(這些屬性通常只觸發合成層,由 GPU 加速處理,不觸發 CPU 密集的 Reflow 操作)
避免頻繁觸發的策略:
// ------------------------- 1. 批量修改 DOM 而非逐個修改 -------------------------
// 不好的做法 - 多次觸發 Reflow
const element = document.getElementById('myElement');
element.style.width = '100px';
element.style.height = '200px';
element.style.margin = '10px';
// 好的做法 - 只觸發一次 Reflow
const element = document.getElementById('myElement');
element.classList.add('new-layout');
// 或使用 style.cssText
element.style.cssText = 'width: 100px; height: 200px; margin: 10px;';
/* CSS */
.new-layout {
width: 100px;
height: 200px;
margin: 10px;
}
// ------------------------- 2. 使用 DocumentFragment 批量添加多個元素 -------------------------
const fragment = document.createDocumentFragment();
for (let i = 0; i < 10; i++) {
const li = document.createElement('li');
li.textContent = `Item ${i}`;
fragment.appendChild(li);
}
document.getElementById('myList').appendChild(fragment);
// ------------------------- 3. 使用 transform 代替位置調整 -------------------------
// 不好的做法 - 觸發 Reflow
element.style.left = '10px';
element.style.top = '20px';
// 好的做法 - 只觸發合成
element.style.transform = 'translate(10px, 20px)';
// ------------------------- 4. 先設置 display: none,修改後再顯示 -------------------------
element.style.display = 'none';
// 進行多次修改...
element.style.width = '100px';
element.style.height = '200px';
element.style.margin = '10px';
// 最後再顯示,只觸發一次 Reflow
element.style.display = 'block';