当前位置: 首页 > 科技观察

CSS选择器的性能真相

时间:2023-03-13 08:53:51 科技观察

嗨,我是CUGGZ。在CSS中,一些选择器比其他选择器执行得更快。让我们深入研究CSS选择器的性能真相,看看如何编写CSS选择器以更快地执行!CSS选择器在后台编写的方式会影响浏览器呈现页面的方式。每当页面发生变化时,运行它的浏览器引擎都需要查看新的DOM树,并根据可用的CSS样式表确定如何设置它的样式。这种将样式与DOM节点匹配的操作称为重新计算样式。浏览器引擎需要查看所有规则并决定哪些适用于给定元素。为此,引擎需要从右到左查看选择器规则。例如,当引擎看到像.wrapper.section.title.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和网络连接。从Edge109开始,DevTools中的性能工具可以列出样式重新计算中最昂贵的选择器。使用方法如下:在DevTools中打开性能工具;单击右上角的齿轮图标以打开工具设置。勾选Enableadvancedrenderinginstrumentation(slow)点击记录按钮,在你想要改进的网页上执行一个特定的场景,然后点击停止;在记录的配置文件中,确定要改进的重新计算样式,并在瀑布视图中(“主要”部分);在底部的标签栏中,单击选择器统计信息以查看它。DevTools现在提供浏览器引擎在此重新计算操作期间评估的所有CSS选择器的列表,选择器可以按选择器处理时间或匹配数排序。如果你发现一个选择器处理时间长,而且匹配次数多,可能是优化的对象。可以简化选择器吗?能不能具体说一下需要匹配的元素?案例研究让我们通过一个照片库示例,看看如何提高CSS选择器的性能!此页面顶部有一个工具栏,可让您按相机型号、光圈、曝光时间等过滤照片。现在在相机型号之间切换感觉有点慢。所以,主要关注以下场景:加载页面,等待过滤器就绪;将相机型号切换到另一个值并开始录制性能;切换回所有相机型号并停止录制。切换回所有相机型号时很慢,因此只需测量过程即可。我们还将CPU速度提高了四倍,以获得比通常在功能强大的开发机器上获得的结果更真实的结果。录制准备好后,可以在配置文件中看到一长串restyle计算,总共执行了900多毫秒。单击该块将打开选择器统计信息,然后按运行时间排序:选择器需要匹配的工作越多,匹配的次数越多,通过改进该选择器可以获得更多的性能提升。在列表中,关注以下选择器:.gallery.photo.meta::selection.gallery.photo.metalistrong:empty[class*="gallery-icon--"]::before.gallery.photo.metali*html[dir="rtl"].gallery.photo.metalibuttonImproved::selectionselector.gallery.photo.meta::selection选择器用于在用户选择时匹配照片元数据的背景和文本颜色.当用户选择照片下方的文本时,将使用自定义颜色而不是浏览器默认颜色。由于代码中的错误,这种特殊情况实际上是有问题的。真正的代码应该是.gallery.photo.meta::selection,也就是::selection之前没有空格。由于这个错误的空格,选择器实际上被引擎解析为.gallery.photo.meta*::selection,这使得匹配在样式重新计算时慢很多,因为引擎需要检查所有DOM元素然后验证它们是不是嵌套在正确的祖先中。如果没有额外的空格,引擎只需要在继续之前检查元素是否具有.meta类。改进:empty选择器.gallery.photo.metalistrong:empty中的:empty选择器表示仅在强元素没有内容时匹配。这可能需要引擎做更多的工作,而不仅仅是检查元素的标签名称。查看与此类似的其他CSS规则,您会看到:.gallery.photo.metalistrong:empty{padding:.125rem2rem;左边距:.125rem;背景:var(--dim-bg-color);}html[dir="rtl"].gallery.photo.metalistrong:empty{margin-left:unset;margin-right:.125rem;}同一个选择器重复了两次,但是第二次选择器以html结尾[dir=rtl],当页面上的文本方向是从右到左时,rtl方向规则会覆盖左边距并用右边距替换它。为了改进这一点,可以使用CSS逻辑属性。您可以使用与任何文本方向匹配的逻辑边距方向,而不是指定物理边距方向:.gallery.photo.metalistrong:empty{padding:.125rem2rem;保证金内联开始:.125rem;background:var(--dim-bg-color);}这样,第二个选择器html[dir="rtl"].gallery.photo.metali按钮就可以去掉了。改进的[class*="gallery-icon--"]选择器下面是使用这个选择器的CSS规则:[class*="gallery-icon--"]::before{content:'';显示:块;宽度:1rem;高度:1rem;背景大小:包含;背景重复:不重复;背景位置:中心;filter:contrast(0);}.gallery-icon--camera::before{background-image:url(...);}.gallery-icon--aperture::before{背景图片:url(...);}.gallery-icon--exposure::before{背景图片:url(...);}这里可以通过图标类给元素添加相应的图标。这需要引擎读取类名并对其进行子字符串搜索。你可以帮助引擎做更少的工作:.gallery-icon::before{content:'';显示:块;宽度:1rem;高度:1rem;背景大小:包含;背景重复:不重复;背景-位置:中心;过滤器:对比度(0);}.gallery-icon.camera::before{背景图像:url(...);}.gallery-icon.aperture::before{背景图片:url(...);}.gallery-icon.exposure::before{背景图片:url(...);现在,不是只使用一个类,而是向元素添加两个类:而不是,这样就不需要读取类名和搜索子字符串,减少浏览器引擎的工作量。改进的.gallery.photo.metali选择器此选择器强制浏览器检查li元素的祖先列表中的多个级别。该案例的网页有很多li元素,这可能意味着很多工作。它可以通过为li元素分配一个特定的类并删除不必要的嵌套来简化:对齐项目:居中;间隙:.5rem;height:1.5rem;}改进*select*符号在CSS中用作匹配任何元素的通用选择器。这种匹配任何事物的能力意味着引擎需要将相关规则应用于所有元素。在性能日志中可以看到,这个选择器匹配了很多次。如果它应用了特定的box-sizing值:*{box-sizing:border-box;这在CSS中很常见,但最好将其删除并仅在需要时设置box-sizing属性。Improvements经过上面的改进,我们再来看看这个场景的性能:在第一个性能记录中,同样的“recalculatestyle”块运行几乎需要一秒,现在它运行了大约300毫秒,性能上有很大的提升大升级!总结案例研究表明,改进某些CSS选择器可以带来重要的性能提升。但是,关键是要记住,这主要取决于具体的用例。您可以使用性能工具来测试网页的性能,如果您发现样式重新计算正在减慢渲染速度,请使用Edge浏览器中新的“选择器统计”功能!参考:https://blogs.windows.com/msedgedev/2023/01/17/the-truth-about-css-selector-performance/