前端优化之五:缩小样式计算的范围并降低其复杂性

通过添加和删除元素,更改属性、类或通过动画来更改 DOM,全都会导致浏览器重新计算元素样式,在很多情况下还会对页面或页面的一部分进行布局(即自动重排)。这就是所谓的计算样式的计算。

TL;DR

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

降低选择器的复杂性

在最简单的情况下,您在 CSS 中引用只有一个类的元素:

.title {  /* styles */  }`

但是,随着项目的增长,将可能产生更复杂的 CSS,最终您的选择器可能变成这样:

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

为了知道是否需要应用样式,浏览器实际上必须询问“这是否为有 title 类的元素,其父元素恰好是负第 N 个子元素加上 1 个带 box 类的元素?”计算此结果可能需要大量时间,具体取决于所用的选择器和相应的浏览器。选择器的预期行为可以更改为一个类:

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

您可能对该类的名称有疑问,但此工作对于浏览器而言要简单得多。在上一版本中,为了知道(例如)该元素是否为其类型的最后一个,浏览器首先必须知道关于其他元素的所有情况,以及其后面是否有任何元素会是第 N 个最后子元素,因为其类匹配,这可能比简单地将选择器与元素匹配的开销要大得多。

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

另一个性能考虑,对于许多样式更新而言是更重要的因素,即减少在元素更改时需要计算的工作量。

总体来说,计算元素的计算样式的最糟糕的开销情况是元素数量乘以选择器数量,因为需要对照每个样式对每个元素都检查至少一次,看它是否匹配。

注:以前曾经是这样:如果您改变了(例如)body 元素上的一个类,则该页的所有子元素将需要重新计算其计算样式。幸好情况不再是这样;对于更改时会导致重新计算样式的元素,某些浏览器维护一小组每个这种元素独有的规则。这意味着,根据元素在树中的位置以及所改变的具体属性,元素不一定需要重新计算。

样式计算可能经常是直接针对少量元素,而不是声明整个页面无效。在现代浏览器中,这往往不再是个问题,因为浏览器并不一定需要检查一项更改可能影响的所有元素。另一方面,较早的浏览器不一定针对此类任务进行了优化。应当尽可能减少声明为无效的元素的数量

注:如果您热衷于网页组件,有一点值得注意,样式计算在这方面稍有不同,因为默认情况下样式不会跨越 Shadow DOM 的边界,并且范围限于单个组件,而不是整个树。但是,总体来看,同样的概念仍然适用:规则简单的小树比规则复杂的大树会得到更高效地处理。

测量样式重新计算的开销

测量样式重新计算的最简单、最好的方法是使用 Chrome DevTools 的 Timeline 模式。首先,打开 DevTools,转至 Timeline 选项卡,选中记录并与您的网站交互。停止记录后,将看到下图所示情况。

image.png

顶部的条表示每秒帧数,如果看到柱形超过较低的线,即 60fps 线,则存在长时间运行的帧。

image.png

如果一些滚动之类的交互或其他交互时出现长时间运行的帧,则应当进一步审查。

如果出现较大的紫色块,如上例所示,请点击记录了解到更多细节。

image.png

在这次抓取中,有一个长时间运行的重新计算样式事件,其时间刚好超过 18 毫秒,并且恰好发生在滚动期间,导致用户体验到明显的抖动。

如果点击事件本身,将看到一个调用栈,精确指出了您的 JavaScript 中导致触发样式更改的位置。此外,您还获得样式受更改影响的元素数量(本例中刚好超过 400 个元素),以及执行样式计算所花的时间。您可以使用此信息来开始尝试在代码中查找修正点。

使用块、元素、修饰符

BEM(块、元素、修饰符)之类的编码方法实际上纳入了上述选择器匹配的性能优势,因为它建议所有元素都有单个类,并且在需要层次结构时也纳入了类的名称:

.list {  }  .list__list-item {  }

如果需要一些修饰符,像在上面我们想为最后一个子元素做一些特别的东西,就可以按如下方式添加:

.list__list-item--last-child {}

如果您在寻找一种好方法来组织您的 CSS,则 BEM 真的是个很好的起点,不仅从结构的角度如此,还因为样式查找得到了简化。

如果不喜欢 BEM,还可使用其他方法来组织您的 CSS,但是应评估其性能注意事项以及方法的人体工学。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,651评论 18 139
  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,748评论 1 92
  • 简介网络浏览器很可能是使用最广的软件。在这篇入门文章中,我将会介绍它们的幕后工作原理。我们会了解到,从您在地址栏输...
    wengjq阅读 2,022评论 2 15
  • 1. 介绍 浏览器可能是最广泛使用的软件。本书将介绍浏览器的工作原理。我们将看到,当你在地址栏中输入google....
    康斌阅读 2,018评论 7 18
  • “这是—种既复杂却又单纯,既悲伤却又欢喜,既无奈却又无怨的心情。 这是一种我一直不会完全知道的心情。”刚才...
    一半是火阅读 208评论 0 0