渲染优化(计算样式优化)

计算样式优化

在JavaScript处理过后,若发生了添加和删除元素,对样式属性和类进行了修改,就都会导致浏览器重新计算所涉及元素的样式,某些修改还可能会引起页面布局的更改和浏览器的重新绘制,本节就着眼于样式相关的优化点,来看看如何提升前端渲染性能。

一、减少要计算样式的元素数量

​ 首先我们需要知道与计算样式相关的一条重要机制: CSS 引擎在查找样式表时,对每条规则的匹配顺序是从右向左的,这与我们通常从左向右的书写习惯相反。举个例子,如下CSS规则:

.product-list li {}

​ 如果不知道样式规则查找顺序,则推测这个选择器规则应该不会太费力,首先类选择器product-list的数量有限应该很快就能查找到,然后缩小范围再查找其下的 li 标签就顺理成章。

​ 但CSS选择器的匹配规则实际上是从右向左的,这样再回看上面的规则匹配,其实开销相当高,因为CSS引擎需要首先遍历页面上的所有 li 标签元素,然后确认每个 li 标签有包含类名为product-list的父元素才是目标元素,所以为了提高页面的渲染性能,计算样式阶段应当尽量减少参与样式计算的元素数量,这里总结了如下几点实战建议:

​ 使用类选择器替代标签选择器,对于上面 li 标签的错误示范,如果想对类名为product-list下的 li 标签添加样式规则,可直接为相应的 li 标签定义名为product-list_li的类选择器规则,这样做的好处是在计算样式时,减少了从整个页面中查找标签元素的范围,毕竟在CSS选择器中,标签选择器的区分度是最低的。

​ 避免使用通配符做选择器,对于刚入门前端的小伙伴,通常在编写CsS样式之前都会有使用通配符去清楚默认样式的习惯,如下所示:

* {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
}

​ 这种操作在标签规模较小的demo项目中,几乎看不出有任何性能差异。但对实际的工程项目来说,使用通配符就意味着在计算样式时,浏览器需要去遍历页面中的每一个元素,这样的性能开销很大,应当避免使用。

二、降低选择器的复杂性

​ 随着项目不断迭代,复杂性会越来越高,或许刚开始仅有一个名为content的类选择元素,但慢慢地单个元素可能会并列出列表,列表又会包裹在某个容容元素下,甚至该列表中的部分元素的样式又写其他兄弟元素有所差异,这样原本的个类选择器就会被扩展成如下形式:

.container:nth-child(-n+1) .content{/*样式属性*/}

​ 浏览器在计算上述样式时,首先就需要查询有哪些应用了content 类的元素,并且其父元素怡好带有container类的倒数第n+1个元素,这个计算过程可能就会花费许多时间,如果仅对确定的元素使用单一的类名选择器,那么浏览器的计算开销就会大幅度降低。

​ 比如使用名为final-container-content 的类选择替代上述的复杂样式计算,直接漆加到目标元素上。而且复杂的匹配规则,可能也会存在考虑不周从而导致画蛇添足的情况,例如,通过id选择器已经可以唯一确定 目标元素了,就无须再附加其他多余的选择器:

/*错误示范*/
.content #my-content
/*正确方式*/
#my-content

​ 由于id选择器本身就是唯一存在的, 定位到目标元素数后再去查找名为content的类选择器元素就多此一举。当然在实际项目中的情况会复杂得多,但若能做故到尽量降低选择器的复杂性,则类似的问题也会容易避免。

三、使用BEM规范

​ BEM是一种CSS的书写规范,它的名称是由三个单词的首字母组成的,分别是块(Block)、元素(Element)和修饰符(Modifier)。理论上它希望每行CSS代码只有一个选择器,这就是为了降低选择器的复杂性,对对选择器的命名要求通过以下三个符号的组合来实现。

  • 中画线( - ): 仅作为连字符使用,表示某个块或子元素的多个单词之间的连接行。
  • 单下画线( _ ):作为描述一个块或其子元素的种状态。
  • 双下画线( _ _ );作为连接块与块的子元素。

接下来首先给出一个基于BEM的选择器命名形式,然后再分别看块、元素与修饰符的含义和使用示例:

/* BEM命名示例*/
type-block__element_modifier

1.块

通常来说,凡是独立的页面元素,无论简单或是复杂都可以被视作一个块,在HTML文档中会用一个唯一的类名来表示这个块。具体的命名规则包括三个:只能使用类选择器,而不使用ID选择器;每个块应定义一个前缀用来表示命名空间;每条样式规则必须属于一个块。比如一个自定义列表就可视作为一个块, 其类名匹配规则可写为:

.mylist{}

2.元素

元素即指块中的子元素,且子元素也被视作块的直接子元素,其类名需要使用块的名称作为前缀。以上面自定义列表中的子元素类名写法为例,与常规写法对比如下:

//常规写法
.mylist {}
.mylist .item {}
//BEM写法
.mylist {}
.mylist__item {}

3.修饰符

修饰符可以看作是块或元素的某个特定状态,以按钮为例,它可能包含大、中、小三种默认尺寸及自定义尺寸,对此可使用small、normal、 big 或size-N来修饰具体按钮的选择器类名,示例如下:

//自定又列表下子元素大、中、小三种尺寸的类选择器
.mylist__item_big {}
.mylist__item_normal {}
.mylist__item_small {}
//带自定义尺寸修饰符的类选择器
.mylist__item_size-10

​ BEM样式编码规范建议所有元素都被单一的类选择器修饰,从CSS代码结构角度来说这样不但更加清晰,而且由于样式查找得到了简化,谊染阶段的样式计算性能也会得到提升。

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2022-2023 alan_mf
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信