探究 CSS 选择器的性能真相
2023-01-30 11:15:14来源:前端充电宝
大家好,我是 CUGGZ。
【资料图】
在 CSS 中,有些选择器会比其他选择器执行速度更快。下面就来深入研究 CSS 选择器的性能真相,看看如何编写 CSS 选择器才能更快地执行!
幕后编写 CSS 选择器的方式会影响浏览器如何渲染页面。每当页面发生变化时,运行它的浏览器引擎需要查看新的 DOM 树,并确定如何根据可用的 CSS 样式表对其进行样式设置。这种将样式与 DOM 节点匹配的操作称为重新计算样式。浏览器引擎需要查看所有规则并决定哪些规则适用于给定元素。为此,引擎需要从右向左查看选择器规则。
例如,当引擎看到像.wrapper .section .title .link这样的选择器时,它会首先尝试将link类与元素匹配,如果匹配,则从右到左沿链向上找到类名为title的祖先元素,然后找到类名为section的元素,最后找到类名为wrapper的元素。
这个例子说明,浏览器引擎只匹配.link可能比匹配更长的.wrapper .section .title .link选择器更快,因为需要检查的更少了。
当然,类并不是在 CSS 选择器中可以使用的唯一类型标识符。一个有趣的例子就是使用属性选择器并进行子字符串匹配,如[class*="icon-"],这选择器就要求浏览器引擎不仅要检查元素是否有class属性,还要检查这个属性的值是否包含子字符串icon-。这个例子说明,不同的选择器编写方式可能需要引擎或多或少的工作来应用 CSS 规则。
在实践中,这重要吗?这在很大程度上取决于网页、DOM 树的大小、CSS 规则的数量以及 DOM 是否经常变化。不幸的是,并没有关于这方面的规则。
事实上,谈到规则,我们喜欢为什么是好的和什么是坏的制定规则。规则帮助我们快速做出决定,并在编写代码和设计软件时提供指导。但这也会让我们无法了解具体情况下真正发生的事。
在编写 CSS 选择器时,严格应用规则或使用 linter 自动执行,在某些情况下可能会适得其反。过于复杂的 CSS 选择器,再加上变化很大的巨大 DOM 树,很可能会导致性能不佳。过度的套用理论规则来获得更好的性能,可能会使 CSS 更难阅读和维护,并且实际收益并不大。
因此,尽可能以对应用有意义且易于阅读和维护的方式来编写代码,然后再去衡量重要用户场景的实际性能。
性能测量工具Edge 浏览器中的 DevTools 提供了一个性能工具,它可以帮助我们测量页面性能。在实际的测试中,我们要为用户建立同理心,并尽可能使用他们实际使用的设备。因为往往开发机器可能比用户的设备强大得多。DevTools 可以直接从工具内部降低 CPU 和网络连接速度。
从 Edge 109 版本开始,DevTools 中的性能工具可以列出样式重新计算中成本最高的选择器。使用方法如下:
打开 DevTools 中的性能工具;点击右上角的齿轮图标打开工具设置。选中Enable advanced rendering instrumentation (slow)点击录制按钮,在要改进的网页上执行特定场景,然后单击停止;在记录的配置文件中,确定要改进的重新计算样式,并在瀑布视图(“主要”部分)中选择它;在底部的选项卡栏中,点击“选择器统计信息”进行查看。DevTools 现在提供了浏览器引擎在此重新计算操作期间计算的所有 CSS 选择器的列表,可以按选择器处理时间或匹配次数对选择器进行排序。
如果发现一个选择器需要很长时间来处理,并且匹配了很多次,那么它可能就是一个可以优化的对象。选择器是否可以简化?是否可以更具体地描述需要匹配的元素?
案例分析下面通过一个照片库案例,看看如何改进 CSS 选择器的性能!
这个页面顶部有一个工具栏,可以按相机型号、光圈、曝光时间等过滤照片。现在在相机型号之间切换感觉有点慢。所以,主要关注如下场景:
加载页面,并等待过滤器准备就绪;将相机型号切换到另一个值并开始记录性能;切换回所有相机型号并停止录制。当切换回所有相机型号时速度很慢,因此只需要测量这一过程。我们还将 CPU 速度降低四倍,以获得比通常在功能强大的开发机器上获得的结果更真实的结果。
录制准备就绪后,可以在配置文件中看到一个长的重新样式计算块,总计执行超过 900 毫秒。点击这个块,打开选择器统计信息,然后按运行时间排序:
一个选择器需要匹配的工作越多,匹配的次数越多,通过改进这个选择器获得的性能提升就越多。在列表中,主要关注以下选择器:
.gallery .photo .meta ::selection.gallery .photo .meta li strong:empty[class*=" gallery-icon--"]::before.gallery .photo .meta li*html[dir="rtl"] .gallery .photo .meta li button改进::selection选择器.gallery.photo.meta ::selection选择器用来匹配照片元数据被用户选中时的背景和文本颜色。当用户选择照片下方的文本时,将使用自定义颜色而不是浏览器默认颜色。
由于代码中的错误,这种特殊情况实际上是有问题的。真正的代码应该是.gallery.photo.meta::selection,即::selection前面没有空格。因为这个错误的空格,选择器实际上被引擎解析为.gallery .photo .meta *::selection,这使得在样式重新计算期间匹配起来要慢得多,因为引擎需要检查所有 DOM 元素,然后验证它们是否嵌套在正确的祖先中。
如果没有多余的空格,引擎只需要检查元素是否具有.meta类,然后再继续即可。
改进:empty选择器.gallery .photo .meta li strong:empty中的:empty选择器表示仅在strong元素没有任何内容时匹配。这就可能需要引擎做更多的工作,而不仅仅是检查元素的标签名称。
查看与此类似的其他 CSS 规则,可以看到:
.gallery .photo .meta li strong:empty { padding: .125rem 2rem; margin-left: .125rem; background: var(--dim-bg-color);}html[dir="rtl"] .gallery .photo .meta li strong:empty { margin-left: unset; margin-right: .125rem;}
相同的选择器重复两次,但第二个选择器以html[dir=rtl]为前缀,当页面上的文本方向是从右到左时,rtl方向规则会覆盖左边距并将其替换为右边距。
为了改进这一点,可以使用 CSS 逻辑属性。可以使用符合任何文本方向的逻辑边距方向,而不是指定物理边距方向:
.gallery .photo .meta li strong:empty { padding: .125rem 2rem; margin-inline-start: .125rem; background: var(--dim-bg-color);}
这样,第二个选择器html[dir="rtl"] .gallery .photo .meta li button就可以去掉了。
改进[class*="gallery-icon--"]选择器以下是使用此选择器的 CSS 规则:
[class*=" gallery-icon--"]::before { content: ""; display: block; width: 1rem; height: 1rem; background-size: contain; background-repeat: no-repeat; background-position: center; filter: contrast(0);}.gallery-icon--camera::before { background-image: url(...); }.gallery-icon--aperture::before { background-image: url(...); }.gallery-icon--exposure::before { background-image: url(...); }
这里可以通过图标类给元素添加对应的图标。这就要求引擎读取类名并对其进行子字符串搜索。可以通过以下方式帮助引擎减少工作量:
.gallery-icon::before { content: ""; display: block; width: 1rem; height: 1rem; background-size: contain; background-repeat: no-repeat; background-position: center; filter: contrast(0);}.gallery-icon.camera::before { background-image: url(...); }.gallery-icon.aperture::before { background-image: url(...); }.gallery-icon.exposure::before { background-image: url(...); }
现在,不只使用一个类,而是向元素添加两个类:
相关新闻
-
探究 CSS 选择器的性能真相
大家好,我是CUGGZ。在CSS中,有些选择器会比其他选择器执行速度更快。下面就来深入研究CSS选择器的性能...
-
手写图表指南,你学会了吗?
1、前言说到数据可视化,大家应该都不陌生。它旨在借助于图形化手段,清晰有效的传达与沟通信息。广义的...
-
两万字详解Oracle分区表技术,太顶了
大家好,我是哪吒,最近项目有一个新的需求,按月建表,按天分区。不都是分库分表吗?怎么又来...
-
手把手带你开发Starter,点对点带你讲解原理
___________ ____|(_)
-
国脚吴兴涵出轨绯闻,10段感情,女人买的计生用品,废话太多?
今年的中超春节,虽然是淡季,但山东泰山球员吴兴涵疑似婚外情的丑闻却成为这段时间球迷热议的话题。事...
-
云南能投、孩子王等20股获陆股通增仓超50%
证券时报网讯,Wind统计显示,截至1月20日,共有918只个股获陆股通增仓。其中,持股量环比增幅在50%以上...
-
114可以查询哪些内容_用114可以查什么
114可以查询号码信息服务、商旅服务、位置服务、通信服务、法律顾问、教育导航、健康顾问、如意折扣、话...
-
深圳01月29日13时疫情有多少例 _昨日新增60例本土确诊病例、0例本土无症状感染者
深圳01月29日13时疫情有多少例(昨日新增60例本土确诊病例、0例本土无症状感染者)具体详情!1
-
玛曲县气象台发布大风蓝色预警信号
玛曲县气象台发布大风蓝色预警信号
-
悄悄聘请多国承包商训练AI,野心藏住不住了!
作者|朱先忠、云昭审校|言征OpenAI或在悄悄聘请国际承包商,以培训其软件工程方面的人工智能。本文将...
-
如何使用Python检测和识别车牌?
译者|布加迪审校|孙淑娟车牌检测与识别技术用途广泛,可以用于道路系统、无票停车场、车辆门禁等。这...
-
构建高效的 DevOps 文化的六个技巧
你为什么要构建DevOps文化?开发团队和运维团队的精简协作有很多好处。效率是首要目标:提高新软件部署...
-
聊聊并发库 Conc,你学会了吗?
上个月sourcegraph放出了conc[1]并发库,目标是betterstructuredconcurrencyforgo,简单的评价一下每个
-
阿里二面:RocketMQ 消费者拉取一批消息,其中部分消费失败了,偏移量怎样更新?
大家好,我是君哥。最近有读者参加面试时被问了一个问题,如果消费者拉取了一批消息,比如100条,第100...
-
聊聊微服务划分的姿势
大家好,我是不才陈某~我们知道微服务是一种理念,没有确切的定义和边界,好比设计原则,是属于抽象的概...