大家好,我是徐徐。今天我们谈谈前端性能优化之执行渲染优化。
前言
前端执行渲染优化是提升网页加载速度和用户体验的关键步骤。随着网页内容和功能的复杂化,如何在保证视觉效果和交互体验的同时,提高页面的渲染效率,成为前端开发中不可忽视的任务。通过优化 CSS、JavaScript、DOM 操作、以及布局和渲染策略等方法,开发者可以有效减少页面的渲染时间,降低性能瓶颈,从而为用户提供更加流畅、快速的浏览体验。下面我们就来看看一些具体的优化方案。
1. CSS优化
CSS 是影响页面渲染性能的重要因素,优化 CSS 可以显著提升页面的渲染效率。通过合理调整 CSS 代码的编写和使用方式,可以有效的达到优化的目的,以下是一些具体的优化措施。
选择器优化
CSS 选择器是浏览器解析样式的基础,复杂的选择器会增加解析的时间。因此:
- 使用简单、高效的选择器:例如尽量使用 ID 选择器 (
#id) 或类选择器 (.class) 而不是复杂的嵌套选择器,选择器越短越好。 - 避免过度嵌套:嵌套选择器会导致浏览器逐层解析,影响性能。应尽量减少选择器的嵌套层级,保持结构简单。
启用 GPU 加速
某些 CSS 属性可以触发 GPU 加速,利用 GPU 加速可以显著提高动画和过渡效果的性能。
- 使用
transform和opacity:这些属性在变换时不会触发重排和重绘,而是直接由 GPU 处理,能大幅提升性能。 - 合理使用
will-change属性:提前告诉浏览器某个元素将要发生哪些变化(如transform或opacity),浏览器可以为这些变化做优化准备,但不应滥用will-change,否则会消耗过多资源。
避免使用 CSS 表达式
CSS 表达式(如在 expression 中写 JavaScript 代码)虽然强大,但会在每次重绘时重新计算,严重影响性能。应尽量避免使用,改用 CSS 变量或其他更高效的方法。
优化重绘
重绘(Repaint)指的是元素的外观改变而导致的重新绘制,不涉及元素布局的变化。通过以下方式减少不必要的重绘:
- 优先使用
transform和opacity:这些属性改变时不会触发重排,只会触发重绘且直接由 GPU 处理,是性能优化的好选择。
利用 CSS contenteditable
对于需要频繁更新的文本内容,使用 contenteditable 属性可以让元素直接在页面上编辑,减少对 DOM 的操作,从而提升性能。需要注意,contenteditable 会带来一些额外的管理工作,如处理输入事件。
2. JavaScript 优化
JavaScript 的执行效率直接影响页面的渲染性能。我们可以通过提升代码执行效率、减少主线程阻塞、合理管理资源加载等方式,来改善网页的渲染性能和用户体验,以下是一些具体的 JavaScript 优化措施。
使用 requestAnimationFrame
requestAnimationFrame 是浏览器专门为高效执行动画而提供的 API。它会在下一次屏幕刷新前调用指定的回调函数,确保动画流畅并且节省资源。
- 使用场景:动画更新、页面滚动等。通过
requestAnimationFrame调整动画的每一帧,可以确保动画在最佳的时机更新,避免画面撕裂和卡顿。
降低复杂度或使用 Web Worker
JavaScript 运行在浏览器的主线程上,与页面渲染共享资源。如果 JavaScript 执行过于复杂,可能导致页面卡顿。以下是优化方案:
- 降低 JavaScript 复杂度:优化算法,减少计算量。
- 使用 Web Worker:将复杂的计算任务(如数据处理、图像处理)放在 Web Worker 中执行,避免阻塞主线程,提高页面响应速度。
输入处理程序防抖
对于高频率触发的事件(如 scroll、resize 等),频繁执行事件处理函数会降低性能。防抖技术可以减少不必要的触发:
- 使用防抖:在事件被连续触发时,只执行最后一次触发后的处理逻辑,减少性能消耗。常用防抖方法是设置一个延时器,当事件持续触发时延时器不断重置,直到用户停止触发一段时间后再执行操作。
避免强制同步布局
强制同步布局(Forced Synchronous Layout)是指 JavaScript 代码强制让浏览器立即计算布局(如获取元素的宽高、位置等),可能导致多次布局计算,影响性能:
- 合理安排 DOM 的读写操作:将 DOM 的读取和写入操作分别放在不同的代码块中,避免交替进行,减少强制同步布局的发生。
使用 requestIdleCallback
requestIdleCallback 允许在浏览器空闲时执行非关键任务,这些任务不会阻塞页面的渲染或响应:
- 使用场景:可以用于延迟执行非关键任务,如统计、日志、预加载等操作。
requestIdleCallback可以根据浏览器的空闲时间来安排任务,确保关键渲染任务优先执行。
3. DOM操作优化
DOM 操作往往是性能瓶颈,优化 DOM 操作可以显著提升渲染性能,下面总结了三种方式。
避免大型、复杂的布局
复杂的布局结构会增加浏览器的计算负担,影响页面渲染速度:
- 简化布局:通过合理的布局设计,减少不必要的嵌套和复杂性。例如,避免在表格等复杂结构中嵌套大量元素。
防止布局抖动
布局抖动(Layout Thrashing)是指在短时间内频繁改变影响布局的属性,导致多次重排:
- 避免多次触发布局计算:将需要改变的样式集中到一次修改中,避免连续触发多次重排操作。
批量修改 DOM
每次 DOM 操作都会触发重排和重绘,因此应该将多次 DOM 操作合并为一次,以减少重排重绘的次数:
- 使用
DocumentFragment:在内存中创建一个文档片段,将多次 DOM 操作集中在文档片段中完成,然后一次性将结果添加到实际 DOM 中,减少不必要的渲染。
4. 渲染策略优化
优化渲染策略可以从根本上提升页面性能,指通过减少简化绘制复杂度、以及合理利用分层渲染等技术,来提高浏览器的渲染效率和页面加载性能,下面这些方法你可能用得到。
简化绘制复杂度
复杂的 CSS 效果会增加浏览器的绘制负担,因此应避免使用性能消耗大的效果:
- 避免使用复杂效果:如阴影、渐变、模糊效果等,这些效果在渲染时需要消耗大量计算资源。可以使用更轻量的效果替代。
减少绘制区域
减少浏览器每次绘制的区域可以提升渲染性能:
- 使用
clip-path:限制元素的绘制区域,只绘制可见部分,从而减少不必要的绘制工作。
实现虚拟滚动
对于包含大量数据的长列表,可以使用虚拟滚动技术,只渲染可视区域内的元素,其他部分的元素不会在 DOM 中渲染:
- 虚拟滚动:通过动态加载和卸载列表项,显著减少 DOM 节点数量,提升渲染性能。
分层渲染
将页面元素分成不同图层,独立处理每个图层的渲染,减少重绘区域:
- 分层渲染:通过 CSS 属性(如
transform,opacity)触发图层的创建,将复杂的动画或滚动内容分层处理,提高渲染性能。
离屏渲染
将复杂的绘制任务放到屏幕外完成,绘制完成后再将结果复制到屏幕上显示:
- 离屏渲染:例如使用
Canvas元素在屏幕外绘制图形,绘制完成后再将结果复制到实际显示区域,避免频繁更新显示区域。
5. 布局优化
优化页面布局可以减少浏览器的计算负担,提升渲染效率,下面列举两种方法。
使用绝对定位
绝对定位的元素脱离了文档流,不会影响其他元素的布局,因此可以减少页面重排的次数:
- 绝对定位:将那些不会影响整体布局的元素使用
position: absolute或fixed定位,减少重排开销。
避免回流
回流(Reflow)是指当 DOM 发生变化,导致元素尺寸、布局或位置变化时,浏览器需要重新计算元素的位置和大小。避免回流可以减少浏览器的计算负担:
- 减少布局影响:尽量避免频繁修改影响布局的属性,如
width,height,margin等。如果必须修改这些属性,尽量合并为一次操作。
6. 可见性和懒加载优化
提高页面初次加载速度,并优化用户体验,可以使用可见性和懒加载技术。
使用 Intersection Observer
Intersection Observer 是一个浏览器 API,可以高效地检测元素是否进入视口,从而实现懒加载等功能:
- 懒加载图像:只有当图像进入视口时才加载图像文件,减少初始加载时间。
- 懒加载其他资源:例如延迟加载不在视口中的视频、广告等内容,避免阻塞页面渲染。
通过以上这些优化措施,可以显著提高页面的渲染性能,提升用户的浏览体验。
结语
上面提到的一些执行渲染优化方案是比较常见的一些方案,至于在实际使用的过程中可根据自己的应用场景去使用,不过大体的方向可以从上面 6 个大方向去思考。不知道你在日常开发中是否有用到这些方案,欢迎和我一起讨论。