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

简介: 通过添加和删除元素,更改属性、类或通过动画来更改 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,但是应评估其性能注意事项等。

目录
相关文章
|
4月前
|
图形学 开发者
U3D开发进阶:精细调整Collider与优化碰撞检测性能
【7月更文第11天】在Unity 3D(简称U3D)开发过程中,精确控制Collider(碰撞器)的设置与合理利用Layer Collision Matrix(层级碰撞矩阵)对于提升游戏性能、优化物理模拟至关重要。本文将深入探讨这两项技术的应用,通过实际案例和代码示例,帮助开发者构建更加高效、流畅的游戏体验。
490 2
|
6月前
|
缓存 JavaScript 前端开发
< 性能提升 Get √ :如何理解 “ 回流 ” 与 “ 重绘 ” ?如何合理的减少其出现呢 ? >
`回流` 和 `重绘` 可以说是每一个web前端开发者经常听到的两个名词,虽然听的多,但是我们真的都理解它们的意思了嘛? 很显然都迷迷糊糊,当然在之前没有去了解的时候,小温也不例外! 之前是介于之前公司要分享,所以当时有做了解,所以这次打算和大伙分享一下! > 🧐 预先剧透一下: " **`回流`** " 和 “ **`重绘`** ” 是阻碍浏览器渲染 及 服务性能的关键因素中 比较重要的两点, 合理的规避它们,能够有效的提高项目的性能!
< 性能提升 Get √ :如何理解 “ 回流 ” 与 “ 重绘 ” ?如何合理的减少其出现呢 ? >
|
5月前
|
开发者 UED 容器
与传统的块级和行内布局相比,Flexbox为Web开发者提供了更加灵活、高效的布局方式
【6月更文挑战第10天】Flexbox是CSS3的弹性盒子布局,提供灵活、高效的网页布局解决方案。其特点包括灵活性、响应式和易理解,能适应不同屏幕尺寸和设备。核心概念有容器和项目,常用于导航栏、卡片布局、响应式设计、表格和表单布局。关键属性如flex-direction定义主轴方向,justify-content和align-items控制对齐,flex属性处理伸缩,order调整顺序。通过响应式设计和兼容性考虑,Flexbox助力创建优质、适应性强的Web界面。
39 0
|
6月前
|
前端开发 UED 开发者
【专栏】探讨了CSS3动画卡顿的原因,包括复杂动画效果、过多元素参与、低效代码结构和硬件资源限制,并提出优化措施
【4月更文挑战第29天】本文探讨了CSS3动画卡顿的原因,包括复杂动画效果、过多元素参与、低效代码结构和硬件资源限制,并提出优化措施:简化动画路径、控制元素数量、优化代码结构、利用硬件加速及性能监测。通过实际案例展示了优化效果,强调了性能优化对提升用户体验的重要性。在开发中,应持续关注并优化动画性能,以适应网页应用的需求。
373 1
|
6月前
|
机器学习/深度学习 JSON 物联网
ORPO偏好优化:性能和DPO一样好并且更简单的对齐方法
ORPO是另一种新的LLM对齐方法,这种方法甚至不需要SFT模型。通过ORPO,LLM可以同时学习回答指令和满足人类偏好。
318 0
|
6月前
|
算法
【MFAC】基于紧格式动态线性化的无模型自适应迭代学习控制
【MFAC】基于紧格式动态线性化的无模型自适应迭代学习控制
【MFAC】基于紧格式动态线性化的无模型自适应迭代学习控制
|
设计模式 人工智能 安全
没有性能瓶颈的无限级菜单树应该这样设计
以一门网络课程为例,我们设计一个课程的关系结构。比如,我们有Java入门课程、人工智能课程、Java设计模式、源码分析、软技能等,而Java设计模式、源码分析、软技能又属于Java架构师系列课程包,每个课程的定价都不一样。但是,这些课程不论怎么组合,都有一些共性,而且是整体和部分的关系,可以用组合模式来设计。首先创建一个顶层的抽象组件CourseComponent类。
95 0
An动画优化之补间形状与传统补间的优化
An动画优化之补间形状与传统补间的优化
906 0
An动画优化之补间形状与传统补间的优化
|
算法
几种算法的时间和控件复杂度
几种算法的时间和控件复杂度
84 0
几种算法的时间和控件复杂度