引言💭
面试时被问到了性能优化方面的问题,一脸懵逼,要学习性能优化首先得先了解页面渲染规则。网页的渲染是一个复杂的过程,涉及多个阶段和机制。
基础知识📑
一、文档流与布局
1. 文档流
文档流是浏览器根据 HTML 结构逐步从上到下、从左到右地渲染元素。浏览器解析 HTML 时,元素的排列遵循文档流的规则:
- 块级元素 :独占一行,通常具有 100% 的宽度。例如:
<div>
,<p>
,<section>
等。 - 行内元素 :与其他行内元素排在同一行,宽高由内容决定。例如:
<span>
,<a>
,<strong>
等。
文档流的布局规则影响元素的展示位置和大小,它决定了网页的基本排版。代码示例如下:
css
<div>这是一个块级元素</div>
<span>这是一个行内元素</span>
<span>这是另一个行内元素</span>
效果:
<div>
占据一整行,接下来的内容会换行。<span>
元素会排在同一行内。
2. 盒模型
每个 HTML 元素都可以视为一个"盒子",盒模型定义了元素的尺寸和间距。标准盒模型和 IE 盒模型是两种常见的盒子计算方式:
- 标准盒模型(
content-box
) :元素的宽度和高度只计算内容区域,不包括 padding 和 border。 - IE 盒模型(
border-box
) :元素的宽度和高度包括了 padding 和 border,计算更为直观。
例如,假设我们有如下的 CSS:
css
div {
width: 200px;
padding: 20px;
border: 10px solid #000;
margin: 15px;
}
- 在
content-box
模式下,div
的总宽度为200px (width) + 40px (padding) + 20px (border)
。 - 在
border-box
模式下,div
的总宽度依然是200px
,包含了 padding 和 border。
理解盒模型有助于精确控制元素的尺寸与布局。
二、格式化上下文
1. 什么是格式化上下文?
格式化上下文(FC)是浏览器渲染元素的规则集合,决定了元素如何相互排列和展示。不同类型的格式化上下文会显著影响元素的布局行为。常见的格式化上下文包括 块级格式化上下文(BFC) 、弹性格式化上下文(FFC) 和 网格格式化上下文(GFC) 。
2.块级格式化上下文(BFC)
BFC 是一个独立的渲染区域,决定了其中元素的布局和其他元素的交互行为。BFC 的特点包括:
- 独立性:BFC 内的元素不会影响外部元素,外部元素也不会影响 BFC 内的元素。
- 布局规则:BFC 中的块级元素会从上到下垂直排列,行内元素则从左到右排列。
- Margin 重叠:同一 BFC 下相邻元素的 margin 会发生重叠,较大的 margin 会决定最终的间距。
要触发 BFC,可以通过设置 overflow: hidden
或 display: flow-root
等属性。例如:
css
.container {
overflow: hidden; /* 触发 BFC */
}
示例:
ini
<div class="container">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
</div>
css
.container {
overflow: hidden;
background-color: lightgray;
}
.item {
margin-top: 20px;
background-color: lightblue;
}
在这个示例中,overflow: hidden
会触发 BFC,保证 .container
内部元素的布局独立,不会受到外部影响。
3. 弹性格式化上下文(FFC)
Flexbox(弹性布局)创建了一种新的格式化上下文------弹性格式化上下文(FFC) 。在 FFC 中,元素可以自动适应容器的空间,且具有强大的对齐功能。通过 display: flex
或 display: inline-flex
创建弹性布局,使得子元素可以灵活地调整排列方式。
css
.container {
display: flex;
justify-content: space-between;
}
.item {
width: 100px;
height: 100px;
background-color: lightblue;
}
效果 :子元素 .item
会在 .container
中等距排列。
4. 网格格式化上下文(GFC)
CSS Grid(网格布局)创建了 网格格式化上下文(GFC) ,允许开发者设计复杂的二维布局。在 GFC 中,子元素根据网格模板进行布局,可以在行列中自由放置和对齐。示例代码:
css
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.item {
background-color: lightcoral;
height: 100px;
}
效果 :.container
内部的 .item
元素会均匀分布在 3 列网格中。
三、布局模型
- 块级布局:块级元素从上到下、占据整行,常用于布局的基本框架。
- 行内布局:行内元素不会占据整行,常用于文本排版和小组件。
- Flex 布局 :通过
display: flex
创建弹性布局,子元素可以在水平方向或垂直方向上灵活排列。 - Grid 布局 :通过
display: grid
创建网格布局,可以精确地控制元素的位置和大小,适用于复杂的二维布局。
示例:使用 Flexbox 和 Grid 布局的对比
Flexbox 示例:
css
.container {
display: flex;
justify-content: space-between;
}
.item {
width: 100px;
background-color: lightgreen;
}
Grid 示例:
css
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.item {
background-color: lightyellow;
height: 100px;
}
四、层叠上下文与 z-index
层叠上下文是一个三维概念,决定了页面上不同元素的堆叠顺序。元素的 z-index
属性用于控制元素的堆叠层次,值越大,元素越靠前。
- 堆叠上下文 :
z-index
不仅仅依赖于元素自身,还受父元素的影响。如果父元素创建了新的堆叠上下文,那么子元素的z-index
仅在这个上下文内有效。
css
.parent {
position: relative;
z-index: 10;
}
.child {
position: absolute;
z-index: 20;
}
效果 :child
元素会堆叠在 parent
元素上方。
五、CSS 样式书写方式
CSS 样式可以通过不同的方式书写,每种方式有其优缺点:
- 行内样式:直接写在 HTML 元素上,优先级最高,但不便于维护。
- 内嵌样式 :写在
<style>
标签中,适合小范围的页面样式,但不易复用。 - 外联样式 :通过
<link>
引入外部 CSS 文件,易于维护和复用,支持并发加载,提高页面加载速度。
此外,CSS 预处理器(如 Stylus 、Sass)提供了更强大的功能,如省略分号和花括号、使用变量和混合宏等,使得 CSS 的书写更简洁高效。 在文章中继续补充页面渲染规则相关的内容:
页面渲染💻
六、渲染过程概述
页面渲染是指浏览器从接收到 HTML 文档开始,到最终将内容显示在屏幕上的整个过程。
整个渲染过程大致可分为以下几个主要步骤:
1. 解析 HTML 构建 DOM 树
浏览器会逐行解析 HTML 文档,将其中的元素和结构转化为 DOM(文档对象模型)树。DOM 是 HTML 页面结构的树状表示,包含了页面中的所有元素、文本、属性等。

2. 解析 CSS 构建 CSSOM 树
浏览器会同时解析页面中的 CSS(包括外部样式表、内联样式和样式标签等),并根据 CSS 规则构建 CSSOM(CSS 对象模型)树。CSSOM 描述了元素的样式,如字体、颜色、位置、大小等。

3. 构建渲染树
DOM 树和 CSSOM 树会合并,生成渲染树。渲染树是页面渲染的关键,描述了需要展示的元素以及它们的样式。通过渲染树,浏览器可以知道哪些元素是需要显示的,哪些元素是隐藏的。

4. 布局(Layout)
布局阶段,浏览器根据渲染树中每个元素的样式信息(如尺寸、位置等)进行计算,确定每个元素在屏幕上的准确位置。布局过程是影响页面性能的重要因素,特别是在页面内容多、样式复杂时,浏览器可能会执行大量的回流操作。

5. 绘制(Paint)
绘制阶段,浏览器根据布局信息将渲染树中的每个元素转化为图层,并进行绘制。这些图层最终形成屏幕上显示的内容。
- 分层 根据元素的属性(如
position
,opacity
,transform
等),浏览器决定哪些元素需要分配到独立的图层中,这些图层可以独立绘制和合成。 - 生成绘制指令 浏览器为每个图层生成绘制指令,这些指令决定了每个图层如何在屏幕上显示。
6. 合成(Composite)
是将各个图层合并成最终图像的过程。在合成阶段,浏览器将每一层的绘制结果合成在一起,最后将图层显示到屏幕上。
渲染主线程 和合成线程是两个不同的线程,它们在浏览器渲染过程中的作用和职责不同。浏览器通常会利用多线程来提高渲染效率,尤其是在处理复杂页面时,渲染主线程和合成线程的分工有助于加快页面的显示速度。
七、渲染过程中的优化
现代浏览器采用多种优化技术来提高页面的加载速度和渲染效率。常见的优化方法包括:
- 懒加载:对于不需要立即显示的资源(如图片、视频等),浏览器会延迟加载,这样可以加快页面初次渲染速度。
- 异步加载 JavaScript :使用
async
或defer
属性异步加载 JavaScript,避免 JavaScript 阻塞页面渲染。 - 资源合并与压缩:通过合并 CSS 和 JavaScript 文件,并进行压缩,减少请求次数和资源体积,提高加载效率。
- GPU 加速:对于复杂的图形渲染,浏览器可以将渲染过程交给 GPU 进行加速,从而提高性能。
- 渲染树优化:一些元素的渲染并不会立即影响到其他元素,这些元素可以被延迟渲染或在后台处理,减少不必要的计算。
八、常见的性能瓶颈
在页面渲染过程中,一些操作可能会导致性能问题,常见的瓶颈包括:
- 强制回流(Reflow)和重绘(Repaint) :频繁的 DOM 操作(如改变元素尺寸、位置或样式)会导致浏览器频繁计算布局和重绘页面,这会影响性能。尤其是在动画和复杂布局中,频繁触发回流可能导致页面卡顿。
- 大量的 HTTP 请求:如果页面包含大量的资源(如图片、字体、JS 文件等),浏览器需要发送大量请求,增加了网络延迟和加载时间。
- JavaScript 执行阻塞:如果 JavaScript 脚本没有进行异步加载,它会阻塞浏览器渲染进程。尤其是在 DOM 操作和样式计算之前执行的 JavaScript,会增加页面加载的等待时间。
九、影响渲染的因素
页面的渲染效率受到多种因素的影响,包括但不限于:
- 资源大小:图片、字体和视频等资源的大小直接影响页面加载速度。通过合理的压缩和优化,能够减少这些资源的体积,提高页面加载速度。
- DOM 和 CSS 的复杂度:过于复杂的 DOM 结构和大量的 CSS 样式会增加渲染时间,尤其是当页面上有大量的嵌套元素时,渲染引擎需要更多的时间来计算布局和绘制。
- JavaScript 代码的执行时间:JavaScript 的执行会影响渲染流程,尤其是阻塞式的 JavaScript,可能导致页面显示卡顿。
- 浏览器兼容性:不同的浏览器可能对渲染规则有所不同,因此开发者需要确保网页在不同的浏览器和设备上有一致的表现。
结语
网页渲染过程是一个复杂且多层次的过程,从 HTML 的解析、布局模型的选择到最终的绘制和合成,每个步骤都对页面的呈现效果和性能产生影响。
