减少样式计算的范围和复杂性(译文)

179 阅读3分钟

原文地址:web.dev/reduce-the-…

JavaScript通常是视觉变化的触发因素。有时是直接通过样式操作,有时是计算会导致视觉变化,比如搜索或排序一些数据。不合时宜或长时间运行的JavaScript可能是导致性能问题的常见原因,您应该尽可能将其影响降至最低。

通过添加和删除元素、更改属性、类或动画来更改DOM,都会导致浏览器重新计算元素样式,在许多情况下,还会对页面或其部分进行布局(或回流)。这一过程称为样式计算(computed style calculation)。

计算风格的第一部分是创建一组匹配的选择器,这本质上是浏览器确定哪些类、伪选择器和ID应用于任何给定的元素。

该过程的第二部分涉及从匹配选择器中获取所有样式规则,并找出元素的最终样式。在Blink(Chrome和Opera的渲染引擎)中,这些过程至少在今天的成本上大致相当:

摘要 #

  • 降低选择器的复杂性;使用以类为中心的方法论,如BEM。
  • 减少必须对其进行样式计算的元素数量。

减少选择器复杂度(Reduce the complexity of your selectors) #

在一个简单的案例中你可能会使用如下的选择器进行class查找

.title {
    /* styles */
}

但是,随着任何项目的发展,它可能会导致更复杂的CSS,因此您最终可能会得到如下选择器:

.box:nth-last-child(-n+1) .title {
    /* styles */
}

为了知道样式需要应用,浏览器必须有效地问“这是一个具有标题类的元素吗?它的父元素恰好是具有box类的减去第n个子元素加1个元素?”根据使用的选择器和有问题的浏览器,弄清楚这一点可能需要很多时间。选择器的预期行为可以改为如下选择器:

.final-box-title {  
/* styles */  
}

你可以使用特定类对最后一个元素进行标识,对于浏览器来说效率便可以有很大提升。例如,在以前的版本中,为了知道元素是其类型中的最后一个,浏览器必须首先知道所有其他元素的所有信息,以及在它之后是否有任何元素将是第n个最后一个子元素,这可能比简单地将选择器与元素匹配要昂贵得多。

(减少赋予样式的元素数量)Reduce the number of elements being styled

另一个性能考虑因素是元素更改时需要执行的工作量,这通常是许多样式更新的更重要因素。

一般来说,计算计算的元素样式的最坏情况成本是元素数量乘以选择器计数,因为每个元素至少需要对照每个样式检查一次,以查看它是否匹配。

样式计算通常可以直接针对少数元素,而不是整个页面。在现代浏览器中,这往往不是什么问题,因为浏览器不一定需要检查所有可能受到更改影响的元素。另一方面,较旧的浏览器不一定针对此类任务进行了优化。在可能的情况下,应该减少无效元素的数量。

使用BEM(Use Block, Element, Modifier) #

BEM (Block, Element, Modifier)

BEM的优势

  1. 实现css的namespace(虽然现在已经有了scope之类的功能)
  2. 减少选择器层级与复杂度:

例如不使用BEM(sass):

.item {
    /*selector*/
    .active { /*selector*/ }
}

使用BEM:

.item {
    /*selector*/
}
.item--active {
    /*selector*/
}

甚至可以

.item {
    /*selector*/
    &--active {
        /*selector*/
    }
}

sass编译后,也可以得到例2中的结果

  1. 便于样式覆盖。如果是嵌套的形式,会导致选择器权重增大,不利于其他选择器进行样式重写(尤其是在组件库中)。使用BEM则没有这个问题。