缩小样式计算的范围并降低其复杂性[转]

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

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

计算样式的第一部分是创建一组匹配选择器,这实质上是浏览器计算出给指定元素应用哪些类、伪选择器和 ID。

第二部分涉及从匹配选择器中获取所有样式规则,并计算出此元素的最终样式。在 Blink(Chrome 和 Opera 的渲染引擎)中,这些过程的开销至少在目前是大致相同的:

用于计算某元素计算样式的时间中大约有 50% 用来匹配选择器,而另一半时间用于从匹配的规则中构建 RenderStyle(计算样式的表示)。 Rune Lillesveen, Opera / Blink 中的样式失效机制

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

降低选择器的复杂性

在最简单的情况下,您在 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
顶部的条表示每秒帧数,如果看到柱形超过较低的线,即 60fps 线,则存在长时间运行的帧。
image
如果一些滚动之类的交互或其他交互时出现长时间运行的帧,则应当进一步审查。

如果出现较大的紫色块,如上例所示,请点击记录了解到更多细节。
image
在这次抓取中,有一个长时间运行的重新计算样式事件,其时间刚好超过 18 毫秒,并且恰好发生在滚动期间,导致用户体验到明显的抖动。

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

使用块、元素、修饰符

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

.list { }
.list__list-item { }

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

.list__list-item--last-child {}

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

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

目录
相关文章
|
Python
python 获取剪切板的内容
python 获取剪切板的内容
373 0
|
7月前
|
SQL 关系型数据库 MySQL
阿里云RDS云数据库全解析:产品功能、收费标准与活动参考
与云服务器ECS一样,关系型数据库RDS也是很多用户上云必买的热门云产品之一,阿里云的云数据库RDS主要包含RDS MySQL、RDS SQL Server、RDS PostgreSQL、RDS MariaDB等几个关系型数据库,并且提供了容灾、备份、恢复、监控、迁移等方面的全套解决方案,帮助您解决数据库运维的烦恼。本文为大家介绍阿里云的云数据库 RDS主要产品及计费方式、收费标准以及活动等相关情况,以供参考。
|
Windows
windows 技巧篇-解除共享文件夹占用方法,解决共享文件被占用导致不可修改问题,查看共享文件被谁占用方法
windows 技巧篇-解除共享文件夹占用方法,解决共享文件被占用导致不可修改问题,查看共享文件被谁占用方法
2677 0
windows 技巧篇-解除共享文件夹占用方法,解决共享文件被占用导致不可修改问题,查看共享文件被谁占用方法
|
7月前
|
算法 数据可视化 机器人
《从代码混乱到架构清晰:经营类游戏NPC行为系统重构指南》
本文以古风山水经营游戏开发实践为核心,分享NPC行为系统从机械执行到环境共生的技术优化路径。初期因架构缺乏扩展性,简单条件判断设计在需求迭代后陷入维护困境,经模块化重构与行为树设计破解耦合问题。后续围绕真实感与系统联动展开技术突破:构建需求层次与环境因子双重驱动模型,让NPC随天气、资源动态调整行为;引入隐性信号与分帧更新,解决群体行为冲突与性能问题;以事件驱动架构打通环境、NPC与经济系统,实现霜降等事件的连锁响应;通过NPC行为设计调控经济,化解低阶道具泛滥;采用组件化与规则引擎,保障系统长期可扩展性,最终显著提升玩家沉浸感与互动频次。
684 1
|
10月前
|
存储 前端开发 测试技术
小试牛刀-区块链代币锁仓合约实战
记录一下自己在开发代币合约中的过程,加深自己对合约功能的理解,在后续的学习过程中可以进行资料查阅,以及帮助有这方面开发要求或想学习的朋友进行更方便的入门。
266 1
|
JavaScript 前端开发 算法
vue和react 哪个更强大
vue和react 哪个更强大
377 3
|
网络协议 测试技术 网络架构
Ping命令的用途?
【8月更文挑战第14天】Ping命令的用途?
985 2
|
监控 测试技术 Apache
如何测试服务器性能?
通过以上步骤,您可以全面评估服务器的性能,找出潜在问题,并采取措施来提高服务器的性能和稳定性。这对于确保服务器在实际生产环境中能够高效运行非常重要。
1083 1