提高性能的方法有哪些?
- 合并css文件,如果页面加载10个css文件,每个文件1k,那么也要比加载一个100k的css文件慢
- 减少css嵌套,最好不要嵌套三层以上
- 不要在ID选择器前面进行嵌套,ID本来就是唯一的而且优先级很高(0100),嵌套完全是浪费性能
- 建立公共样式类,把相同样式提取出来作为公共类使用。
- 减少通配符*或者类似[hidden=”true”]这类选择器的使用,挨个查找所有…这性能能好吗?
- 巧妙运用css的继承机制,如果父节点定义了,子节点就无需定义。
- 拆分出公共css文件,对于比较大的项目可以将大部分页面的公共结构样式提取出来放到单独的css文件里,这样一次下载后就放到缓存里,当然这种做法会增加请求数(与第一点有点冲突),具体做法应以实际情况而定。
- 不要css表达式,表达式只是让你的代码显得更加酷炫,但是对性能的浪费可能是超乎你想象的。
- 少用css rest,可能会觉得重置样式是规范,但是其实其中有很多操作是不必要不友好的,有需求有兴趣,可以选择normolize.css。
- cssSprite,合成所有icon图片,用宽高加上background-position的背景图方式显现icon图,这样很实用,减少了http请求
- 善后工作,css压缩
- GZIP压缩,是一种流行的文件压缩算法.
性能优化
1、避免使用@import,外部的css文件中使用@import会使得页面在加载时增加额外的延迟。
首先,使用@import引入css会影响浏览器的并行下载.使用@import引用的css文件只有在引用它的那个css文件被下载,解析之后,浏览器才会知道还有另外一个css文件需要下载,这时才会去下载,然后下载后开始解析,构建render tree等一系列操作,这就导致浏览器无法并行下载所需的样式文件。
其次,多个@import会导致下载顺序紊乱,在IE中,@import会引发资源文件的下载顺序被打乱,即排列在@import后面的js文件优先于@import下载,并且打乱甚至破坏@import自身的并行下载。
所以不要使用这一方法,使用link标签就行了。
2、避免过分重排
- 浏览器为了重新渲染部分或整个页面,重新计算页面元素位置和几何结构的进程叫做reflow
- 浏览器根据定义好的样式来计算,并将元素放在该出现的位置上,这个过程叫做reflow
- 页面上任何一个节点触发来reflow,会导致它的子节点和祖先节点重新渲染
- 导致reflow发生的情况
- 改变窗口的大小
- 改变文字的大小
- 添加 删除样式表
- 内容的改变 输入框输入内容也会
- 伪类的激活
- 操作class属性
- 脚本操作dom js改变css类
- 计算offsetWidth和offsetHeight
- 设置style属性
- 改变元素的内外边距
常见重排元素
- 大小有关的 width,height,padding,margin,border-width,border,min-height
- 布局有关的 display,top,position,float,left,right,bottom
- 字体有关的 font-size,text-align,font-weight,font-family,line-height,white-space,vertical-align
- 隐藏有关的 overflow,overflow-x,overflow-y
减少reflow对性能的影响的建议
- 不要一条条的修改dom的样式,预先定义好class,然后修改dom的classname
- 不要修改影响范围较大的dom
- 为动画元素使用绝对定位
- 不要table布局,因为一个很小的改动会造成整个table重新布局
- 避免设置大量的style属性,通过设置style属性改变节点样式的话,每一次设置都会触发一次reflow,所以最好使用class属性
- 如果css里面有计算表达式,每次都会重新计算一遍,触发一次reflow
3、repaint(重绘)
1、当一个元素的外观被改变,但是布局没有改变的情况
2、当元素改变的时候,不影响元素在页面中的位置,浏览器仅仅会用新的样式重绘此元素
常见的重绘元素
- 颜色 color,background
- 边框样式 border-style,outline-color,outline,outline-style,border-radius,box-shadow,outline-width
- 背景有关 background,backgound-image,background-position,background-repeat,background-size
4、CSS动画
1、css动画启用GPU加速,应用GPU的图形性能对浏览器中的一些图形操作交给GPU完成。canvas2D、布局合成、css3转换、css3d变换、webGL、视频
2、2d加速
3、3d加速
文件压缩
性能优化时最容易想到的,也是最常见的方法,就是文件压缩,这一方案往往效果显著
文件的大小会直接影响浏览器的加载速度,这一点在网络较差时表现尤为明显,构建工具webpack,gulp/grunt,rollup,压缩之后能够明显减少,可以大大降低浏览器的加载时间。
去除无用css
虽然文件压缩能够降低文件大小,但css文件压缩通常只会去除无用的空格,这样就限制来css文件的压缩比例。如果压缩后的文件仍然超过来预期的大小,可以试着找到并删除代码中无用的css。
一般情况下,会存在这两种无用的CSS代码:
1、 不同元素或者其他情况下的重复代码,
2、 整个页面内没有生效的CSS代码
有选择地使用选择器
css选择器的匹配是从右向左进行的,这一策略导致来不同种类的选择器之间的性能也存在差异。相比于 #markdown-content-h3,显然使用 #markdown.content h3时,浏览器生成渲染树所要花费的时间更多。因为后者需要先找到DOM中的所有h3元素,再过滤掉祖先元素不是.content的,最后过滤掉.content不是#markdown的。试想,页面中的元素更多,那么匹配所要花费的时间代价自然更高。
显得浏览器在这一方面做了很多优化,不同选择器的性能差别并不明显,甚至可以说差别甚微,此外不同选择器在不同浏览器中的性能表现也不统一,在编写css的时候无法兼顾每种浏览器,鉴于这两点,在使用选择器时,尽量记住以下几点:
- 保持简单,不要使用嵌套过多过于复杂的选择器
- 通配符和属性选择器效率最低,需要匹配的元素最多,尽量避免使用。
- 不要使用类选择器和ID选择器修饰元素标签,如h3#markdown-content,这多此一举,还降低了效率
- 不要为了追求速度而放弃可读性和可维护性
为什么css选择器是从右向左匹配的?
我们知道浏览器解析html生成的DOM树会与解析css文件生成的CSSOM树合成生成Render树,这个操作实际上就是需要将css附着到dom树上,因此需要根据选择器提供的信息对dom树进行遍历,才能将样式成功附着到对应的dom元素上。
假设我们有这样一棵DOM树:
1 | .main |
我们定义这样一段css
1 | .main .desc p { |
如果浏览器从左到到解析:
- 遍历DOM树
- .main->section->h1 发现没有.desc回溯
- .main->section->.content->p 发现没有.desc回溯
- .main->aside->.desc->p成功找到了
如果从右向左解析
- 遍历DOM树
- 先找出p的所有节点
- 向上遍历p->.content->section->.main发现没有.desc换一个p
- p->.desc->aside->.main
当dom树比较复杂的时候,可以发现从右到左解析能够有效减少回溯次数提升性能。不过当从右往左解析时需要增加的性能消耗是如何在一棵树中找出所有的’p’节点,不过这一步增加的性能远小于回溯带来的性能损耗。
减少使用昂贵的属性
在浏览器绘制屏幕时,所有需要浏览器进行操作或计算的属性相对而言都需要花费更大的代价,而页面发生重绘时,它们会降低浏览器的渲染性能。所以在编写css时,应该尽量减少使用昂贵属性,如:
box-shadow, border-radius, filter, 透明度, :nth-child等
当然并不是不要使用这些属性,这些都是经常使用的属性,只是这里可以作为一个了解。当有其他方案可以选择的时候,可以优先选择没有昂贵属性或昂贵属性更少的方案,这一网站的性能会在不知不觉中得到一定的提升。