CSS性能优化大全

186 阅读4分钟

前言

对于一个网站而言,性能至关重要,关系到用户体验效果和用户留存率。CSS作为页面渲染和内容展现的重要环节,是影响用户体验的第一道关卡。因此,CSS相关的性能优化不容忽视。在做优化之前,先理解以下几个点

  • 1.关键渲染路径(Critical Rendering Path):关键渲染路径是浏览器将 HTML、CSS、JavaScript 转换为在屏幕上呈现的像素内容所经历的一系列步骤。
  • 2.重绘(Repaint):当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility 等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。
  • 3.重排(Reflow):当渲染树(Render Tree)中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。
  • 4.CSS选择器匹配规则:从右向左匹配。原因是如果通过最右的选择器能准确匹配到对应的DOM节点,那么就停止查询,开始绘制;否则就继续往左查询,直到能准确匹配为止。这个匹配规则大大提升了渲染效率

下面根据以上几点来做对应的性能优化。

优化关键渲染路径

  • 1.减小CSS文件体积:压缩CSS文件,减少文件空白节点;封装公共代码,减少代码量,提高维护性;利用CSS部分代码能够继承的特性减少代码量
  • 2.异步加载CSS文件:对于不是必须第一时间加载的CSS文件使用异步加载<link rel="preload" href="mystyles.css" as="style">
  • 3.预先加载CSS文件:在浏览器空闲的时间偷偷预先加载<link rel="prefetch" href="url">
  • 4.避免使用@import引入CSS文件:无法和HTML并行加载,页面加载完毕后才被加载;多个@import会导致下载顺序紊乱
  • 5.避免使用CSS表达式:例如calc()
  • 6.必要时可以使用内联样式,通过减少HTTP请求来提高页面渲染效率

优化重绘

  • 1.尽量使用 transition 和 animation来实现CSS动画,而不是JS实现动画(运行在主线程对动画的流畅度有影响)
  • 2.动画尽量多用transfrom 和 opacity
  • 3.translateZ/translate3d 开启硬件加速
  • 4.规范CSS属性书写顺序,避免重复绘制,比如如下代码
/* bad */
span {
  /* 开始绘制width和height无效,当display为block会重新触发绘制 */
  width: 200px;
  height: 200px;
  background: red;
  display: block;
}
.box {
  width: 50%;
  height: 100px;
  background: blue;
  position: absolute;
}

动画测试小技巧:借助Chrome的开发者工具进行CPU降速,然后再进行相关的测试,降速方法如下图所示
CPU降速.png

优化重排

重排比重绘对页面性能的影响更大,会导致页面重排的操作有如下:

1.页面首次渲染
2.浏览器窗口大小发生改变
3.元素尺寸或位置发生改变元素内容变化(文字数量或图片大小等等)
4.元素字体大小变化
5.添加或者删除可见的 DOM 元素
6.激活 CSS 伪类(例如:hover

另外,我们可以通过CssTriggers查询哪些属性会触发重排与重绘。

因此,针对页面重排,我们可以做如下优化

  • 1.避免使用 table 布局
  • 2.避免频繁改变font-size和font-family
  • 3.避免频繁改变元素的内外边距
  • 4.避免频繁通过JS改变CSS类
  • 5.避免频繁激活CSS伪类
  • 6.将动画效果应用到 position 属性为 absolute 或 fixed 的元素上
  • 7.使用有更好重排性能的flex布局

优化选择器匹配

  • 1.避免使用通配符*和属性选择器:需要匹配元素多,匹配效率低
  • 2.避免嵌套过多、过于复杂的选择器:建议选择器的嵌套不超过三层,其实这涉及到了HTML结构代码的层级和class、id的命名技巧。有兴趣的可以去了解下CSS的设计模式。
<!-- bad -->
<div class='box'>
  <div class='header'>
    <p class='text'>文本</p>
  </div>
</div>
<style>
.box .header .text {}
</style>

<!-- good -->
<div class='box'>
  <div class='box-header'>
    <p class='box-header-text'>文本</p>
  </div>
</div>
<style>
.box-header-text {}
</style>