全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-16 8 分钟 ✍️ juanwangdev

CSS渲染流水线

浏览器将HTML、CSS转换为屏幕像素的过程称为渲染流水线,理解其机制是性能优化的基础。

渲染流水线阶段

HTML
HTML/CSS → DOM/CSSOM → Render Tree → Layout → Paint → Composite

1. 构建DOM树

解析HTML,生成文档对象模型树。

CSS
HTML字符串
    ↓
Tokenizing(分词)
    ↓
Lexing(词法分析)
    ↓
DOM Tree(DOM树)
JavaScript
<html>
  <head>
    <title>示例</title>
  </head>
  <body>
    <div class="container">
      <p>文本</p>
    </div>
  </body>
</html>
HTML
Document
└── html
    ├── head
    │   └── title
    │       └── "示例"
    └── body
        └── div.container
            └── p
                └── "文本"

2. 构建CSSOM树

解析CSS,生成CSS对象模型树。

HTML
CSS字符串
    ↓
Tokenizing(分词)
    ↓
Lexing(词法分析)
    ↓
CSSOM Tree(CSSOM树)
JavaScript
body { font-size: 16px; }
.container { width: 100%; }
p { color: red; }
JavaScript
CSSOM
└── body: { font-size: 16px }
    └── .container: { width: 100% }
        └── p: { color: red }

3. 构建渲染树

合并DOM和CSSOM,生成渲染树。

JavaScript
DOM Tree + CSSOM Tree
        ↓
    Render Tree
特性说明
可见性只包含可见元素
计算样式每个节点有最终计算样式
排除元素display: none不进入渲染树
CSS
Render Tree
└── body
    └── div.container
        └── p
            └── "文本"

visibility: hidden的元素会进入渲染树但不可见,display: none完全不进入。

4. Layout(布局/回流)

计算元素在屏幕上的精确位置和大小。

JavaScript
Viewport大小
    ↓
元素位置计算
    ↓
Layout Tree(布局树)
CSS
// 触发Layout的操作
element.offsetWidth;
element.offsetHeight;
element.clientWidth;
element.clientHeight;
getComputedStyle(element);
element.getBoundingClientRect();

5. Paint(绘制)

将渲染树的每个节点绘制到位图。

JavaScript
渲染树节点
    ↓
绘制指令生成
    ↓
位图数据

绘制顺序(从后到前):

  1. 背景色/背景图
  2. 边框
  3. 子元素
  4. 轮廓

6. Composite(合成)

将多个图层合并为最终显示的图像。

text
多个图层
    ↓
GPU合成
    ↓
屏幕显示

关键渲染路径

从接收HTML到首次渲染的最短路径。

text
HTML → DOM → CSSOM → Render Tree → Layout → Paint → Composite

阻塞资源

资源类型是否阻塞渲染是否阻塞解析
CSS是(阻塞JS执行)
同步JS
async JS
defer JS

CSS阻塞优化

text
<!-- 关键CSS内联 -->
<head>
  <style>
    /* 首屏关键样式 */
    .header { height: 60px; }
    .content { max-width: 1200px; }
  </style>

  <!-- 非关键CSS异步加载 -->
  <link rel="preload" href="main.css" as="style" onload="this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="main.css"></noscript>
</head>

JS阻塞优化

text
<!-- defer:HTML解析完成后执行 -->
<script defer src="app.js"></script>

<!-- async:下载完成后立即执行 -->
<script async src="analytics.js"></script>

<!-- 动态加载 -->
<script>
  const script = document.createElement('script');
  script.src = 'module.js';
  script.async = true;
  document.head.appendChild(script);
</script>

渲染时机

DOMContentLoaded

DOM构建完成时触发,不等待样式表和图片。

text
document.addEventListener('DOMContentLoaded', () => {
  console.log('DOM构建完成');
});

load

所有资源加载完成时触发。

text
window.addEventListener('load', () => {
  console.log('页面完全加载');
});

requestAnimationFrame

下一帧渲染前执行,适合动画。

text
function animate() {
  // 更新样式
  element.style.transform = `translateX(${x}px)`;

  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

性能优化要点

减少回流重绘

text
/* 使用transform代替top/left */
.animated {
  transform: translateX(100px);
}

/* 使用opacity代替visibility */
.fade {
  opacity: 0;
}

批量DOM操作

text
// 错误:多次触发回流
elements.forEach(el => {
  el.style.width = '100px';
  el.style.height = '50px';
});

// 正确:使用class批量修改
elements.forEach(el => {
  el.classList.add('active');
});
text
.active {
  width: 100px;
  height: 50px;
}

脱离文档流操作

text
// 方法1:隐藏后操作
element.style.display = 'none';
// 执行DOM操作
element.style.display = 'block';

// 方法2:使用DocumentFragment
const fragment = document.createDocumentFragment();
items.forEach(item => fragment.appendChild(item));
container.appendChild(fragment);

// 方法3:clone后替换
const clone = element.cloneNode(true);
// 修改clone
element.parentNode.replaceChild(clone, element);

要点总结

  1. 渲染流水线:DOM → CSSOM → Render Tree → Layout → Paint → Composite
  2. CSS阻塞渲染,应内联关键CSS,异步加载非关键CSS
  3. JS阻塞解析,使用defer/async优化
  4. 减少回流重绘是性能优化核心
  5. 使用transform/opacity触发合成层,避免Layout和Paint

📝 发现内容有误?点击此处直接编辑

← 上一篇 重排与重绘
下一篇 → 合成层与渲染性能
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库