【问题标题】:Significant Performance Decrease after CSS Selector ChangeCSS 选择器更改后性能显着下降
【发布时间】:2016-04-26 18:06:09
【问题描述】:

我在一个相当复杂的 Web 应用程序中对一些 SASS 选择器进行了小改动,发现性能显着下降。当使用 Chrome 的时间线功能分析页面时,“重新计算样式”的实例(我假设在 DOM 操作后重排页面)从大约 1 毫秒变为大约 100 毫秒,并且这些样式重新计算的受影响元素计数从大约 10 变为大约 1500。

是什么让这个选择器的变化如此邪恶?以后要注意什么,以免再犯同样的错误?

原始 CSS(快速):

.button-group .button:not(:last-of-type) {
  margin-right: -1px;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.button-group .button:not(:first-of-type) {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

修改后的 CSS(非常慢):

.button-group > :not(:first-of-type) .button, .button-group > :not(:first-of-type).button {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
.button-group > :not(:last-of-type) .button, .button-group > :not(:last-of-type).button {
  margin-right: -1px;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

【问题讨论】:

  • 这和Sass有什么关系? Sass 编译缓慢 -> Sass 问题。浏览器渲染 CSS 很慢 -> 不是 Sass 问题。除非您有 Sass->CSS 编译问题,否则只发布已编译的 CSS
  • 很公平@cimmanon。但当然,这个论点并不普遍适用。 “Scala 编译缓慢 -> Scala 问题。JVM 运行字节码缓慢 -> 不是 Scala 问题。除非您遇到 Scala -> 字节码编译问题,否则只发布编译后的字节码。”是否有某种地方记录了这条规则,或者它是那些“不成文的 SO 规则”类型的东西之一?
  • 浏览器并不关心 CSS 是如何生成的。调试问题需要minimal reproducible example。除非 Sass 实际上是问题的一部分(即您只能用 Sass 重现问题),否则它与所提出的问题无关。
  • @cimmanon 我认为制作 MCVE 并不禁止使用合理的抽象和/或语法糖。在我看来,这种抽象级别的选择应该由用户决定。尽管如此,在这种情况下 CSS 很好,这确实是一个元级别的讨论
  • 期望用户可能会帮助您安装/查找 Sass 编译器只是为了重现问题,这是不体贴的(Sass 专家通常了解 CSS,但不能指望 CSS 专家知道萨斯)。你也没有考虑到垃圾标签甚至与问题无关(重现问题不需要Sass)。

标签: css performance css-selectors


【解决方案1】:

为了打破这一点,我将忽略.button-group,因为它在两者中相同并且不会影响任何东西。

在第一个示例中,您选择了每个 button 类。浏览器针对搜索类进行了优化,因此通常非常快。然后,您使用 not(:last-of-type) 修饰符,虽然速度较慢,但​​并不重要,因为池已被限制为仅 button 类。

在第二个示例中,您首先搜索:not(:first-of-type),它对.button-group 的每个子节点执行昂贵的操作。虽然使用直接子运算符 (>) 将有助于限制该池,但它的元素数量可能仍然比第一个示例多。我不太确定你想用.button, &.button 做什么,但无论哪种方式,这种操作的成本都不是很高,因为你只是按班级选择,而且你已经对池进行了相当多的限制。

因此,一般而言,您希望从成本最低的操作变为成本最高的操作,以便在尽可能少的元素上完成密集计算。

旁注,我认为您在第二个示例中.button 之后缺少逗号。


编辑:只是想指出你的两段代码编译成的区别。

第一:

.button-group .button:not(:last-of-type)

第二:

.button-group > :not(:first-of-type) .button, 
.button-group > :not(:first-of-type).button {

正如你所看到的,第二个还有很多事情要做。仅这一点就可能是它变慢的原因,尽管我现在正在检查以确保 not 的排序有影响。

【讨论】:

  • "在第二个例子中,你首先搜索 :not(:first-of-type)" 同样,嵌套在它下面的 .button, &.button 选择器意味着当浏览器到达否定时它是已经只关注.button 元素,没有别的。
  • @BoltClock,我认为这不是真的。你看过编译后的代码吗?
  • @BoltClock,是的,我就在这里。编译代码为:.button-group > :not(:first-of-type) .button, .button-group > :not(:first-of-type).button {:not.button 之前,因此首先进行计算。如果它被反转,它会更快。比较两者,如果您看到其他内容,请告诉我。
  • 嗯。从来没有想过简单选择器的顺序实际上对性能很重要。这似乎是一个缺陷。但我不是实施者,所以我知道什么......
  • 这就是我学到的,但我可能是错的......我真的很好奇这个,我会做一些测试并确定。
猜你喜欢
  • 2020-05-10
  • 2017-06-06
  • 1970-01-01
  • 1970-01-01
  • 2018-10-08
  • 1970-01-01
  • 1970-01-01
  • 2014-02-03
  • 1970-01-01
相关资源
最近更新 更多