在实践中,在 SASS/SCSS 中过度嵌套选择器有多糟糕?

How bad is it in practice to over-nest selectors in SASS/SCSS?

提问人:Madara's Ghost 提问时间:12/11/2012 最后编辑:BoltClockMadara's Ghost 更新时间:7/20/2020 访问量:8496

问:

我有一个 .scss 文件,其中包含以下内容:

nav {
  font-size: 0;
  ul {
    margin: $padding/3;
  }
  li {
    z-index: 10;
    position: relative;
    display: inline-block;
    font-size: $fontSize;
    /**
     * If we want separated, Uncomment!

    margin: $padding/3;
    @include border-radius(5px);

    */
    &:first-child {
      @include border-radius(0 5px 5px 0);
    }
    &:last-child {
      @include border-radius(5px 0 0 5px);
    }
    padding: $padding/3 0;
    @include background(linear-gradient(lighten($textColor, 10%), $textColor));
    border: 1px solid lighten($textColor, 20%);
    a {
      color: $brightColor;
      padding: $padding/3 $padding;
      font-weight: bold;
      text-decoration: none;
      @include transition(.2s all);

    }
    //Nested menues
    ul {
      opacity: 0;
      //display: none;
      position: absolute;
      margin: 0;
      top: 0;
      left: 0;
      right: 0;
      z-index: 5;
      pointer-events: none;
      @include transition(.2s all);
      li {
        @include background(linear-gradient(darken($brightColor, 10%), darken($brightColor, 30%)));
        display: block;
        border: 1px solid lighten($textColor, 20%);
        &:first-child {
          @include border-radius(0);
        }
        &:last-child {
          @include border-radius(0 0 5px 5px);
        }
        a {
          color: $textColor;
        }
      }
    }
    &:hover ul {
      pointer-events: all;
      top: 100%;
      opacity: 1;
      //display: block;
    }
  }
}

它在实践中有多糟糕/有害?我听过很多关于“不要超过 3 个嵌套选择器”的讨论!但它到底有多有害?它对页面加载有任何明显影响吗?我所做的基准测试说不,但我缺少什么吗?

CSS 性能 css-selectors sass

评论

1赞 BoltClock 12/11/2012
我最担心的是他们生成的 CSS 文件的大小,但我相信编译器知道缩小的方法......
0赞 ZenMaster 12/11/2012
如果能真正得到一个正确的答案,我会非常棒。在幕后是否有一些编译器优化?当特定的 SCSS 规则(选择器?)被转换为可能性能不佳的内容时,是否有可能收到来自编译器的警告?
0赞 Shauna 12/11/2012
@ZenMaster - 我不知道警告,但我知道正在进行优化(尽管它可能是 Compass 的事情)。我见过很多情况,其中具有匹配属性的选择器被组合在一起(所以像这样的东西变成了)。p{color:red} div{color:red}p, div{color:red}

答:

36赞 morewry 12/11/2012 #1

这取决于页面加载后将对 DOM 和样式进行多少动态操作。问题不在于页面加载(大部分)或初始布局上的缓慢选择器,而是重绘/重排。

现在,史蒂夫·苏德斯(Steve Souders)说,在普通网站上,这根本不是一个真正的问题。但是,在 Web 应用程序或高度交互的网站上,性能不佳的 CSS 规则可能会使您的重绘速度比应有的速度慢。如果你有很多重绘......

Nicole SullivanPaul IrishSteve Souders 等专家介绍了 CSS 与 JavaScript 的交互方式,以及如何编写高性能的 CSS 选择器。这不仅仅是深度(不同的选择器具有不同的性能),但一个好的经验法则是限制深度和复杂性,以免遇到麻烦——但不要有那么多的性能问题,请继续阅读。

然而,正如 jankfree.org 所指出的,与其说是后代或特定的选择器,不如说是某些上下文(html5rocks.com)中的某些属性使油漆变得昂贵。我认为冗长或复杂的选择器更像是一个可维护性问题(Nicolas Gallagher),而不是性能问题——请记住,可维护性与性能是相互作用的。高度可维护的代码可以更快地迭代,并且更易于调试(帮助您查找和修复性能问题)。

现在,关于Sass优化。是的,Sass 可以优化你的 CSS。但它无法优化您的选择器。一个 4 级嵌套块将作为 4 级嵌套选择器输出。Sass 无法在不使您的 CSS 无法正常工作的情况下更改它。作为作者,你必须优化你编写 Sass 的方式来优化你的输出。就我个人而言,我只以有限的方式使用嵌套(对我来说,Sass 的一个杀手锏是使用 和 占位符组合样式)。但是,如果您真的喜欢嵌套,则可以使用 Sass 父选择器引用(或较新的 @at-root)在一定程度上调整输出。@extend

据我所知,Sass 和 Compass 都没有内置工具来分析选择器并发出警告。也许可以创建一个工具来做到这一点(设置一个最大深度,并让你的预处理器警告你),利用 AST。更直接地说,Google Page Speed 确实有一个提供一些信息的现有功能。SCSS Lint 有一个嵌套选项。还有 CSS Lint。(理论上,如果您还没有使用 Grunt 或 Gulp 之类的东西,则可以将它们添加到您的 Compass 配置中运行)。on_stylesheet_saved

10赞 ferne97 12/13/2012 #2

想想你想如何编写实际的css选择器。不要仅仅因为它是元素的子元素就嵌套所有内容。

nav li ul li a { 
    /* over specific, confusing */
}
.sub-menu a {
    /* add a class to nested menus */
}

一旦你开始链接那么多选择器,覆盖起来就会变得很痛苦,并可能导致特异性问题。

4赞 Ben Frain 2/12/2013 #3

只是为了插话并执行其他人所说的话。从性能的角度来看,这不一定是一种不好的做法(与优化选择器相比,去除模糊/阴影和圆角可能会获得更好的绘制时间增加),但从可维护性的角度来看。

选择器嵌套得越多,生成的 CSS 规则就越具体(您已经知道了)。因此,当你想在某个时候“胜过”该规则时,你必须在级联中进一步编写一个相同(或更大)特异性的规则来推翻第一个规则。如果你有一个 ID,那也会使它更加具体(所以除非你需要它们并且知道你不需要覆盖线路,否则请避免)。

为了得出合乎逻辑的结论,除非需要,否则不要嵌套。不要有这样的规则:

.selector .another .yeah-another {}

当它会做同样的工作时:

.yeah-another {}

它只是让每个人(包括您)的生活更轻松。

9赞 user1164682 9/11/2013 #4

不要嵌套 CSS。我们觉得嵌套 css 很舒服,因为这与我们在 HTML 中所做的非常相似。嵌套为我们提供了内部的上下文。它为我们提供了对级联的一些控制。但仅此而已。.some-child.some-parent

正如 SMACSS 所建议的那样,我会嵌套在类名中。即,用代替 或.child-of-parent.parent .child.parent > .child

在实践中,嵌套不当会导致页面速度极慢。了解 github 如何加快其差异页面的速度。你至少应该做的是遵循初始规则,该规则规定你不应该嵌套超过 4 个级别。

但是,我会更进一步说,我们根本不应该嵌套 CSS。我写了一篇博文,表达了我的观点。希望这是有用的。

评论

0赞 Madara's Ghost 9/11/2013
一个写得很好的答案。谢谢。我也会读你的博文:)
4赞 monsto 9/25/2013 #5

我的意见:

告诉我你的眼睛哪个更糟

从 OP

nav li ul li a {color: $textColor;}

或如所建议的那样

.nav-menuitem-menu-menuitem-link {color: $textColor;}

所以。。。

问题是“在 SCSS 中超嵌套是不好的做法吗?(或者是 SASS?我说不。但这是一个辅助论点。

更糟糕的做法是将 SASS(或者是 SCSS?)输出留在机器驱动的状态下用于生产。

S*SS 只是你技巧包中的一个工具,与 Notepad++ 或 Git 或 Chrome 没有什么不同。它的作用是通过将一些非常通用的编程概念带到构建一些 css 的地步,让你的生活更轻松一些。它的作用不是构建你的css。你不能指望它能为你完成你的工作,并创建完全可用、可读、可执行的输出。

随心所欲地筑巢,然后遵循良好做法......

...之后将通过您的 CSS 并手动调整。使用超嵌套输出进行测试、构建等。当 S*SS 创建我上面的第一个示例时,给该锚点一个类并使用 .nav .class

评论

1赞 Madara's Ghost 9/25/2013
我喜欢同时使用S@SS来指代两者:P谢谢你的回答,我同意这里所说的很多,但是,在动画和页面重排方面似乎存在过度嵌套的问题。所以“神话”本身有一定的优点。尽管如此,你还是得到了我的 +1 :)
0赞 monsto 9/25/2013
@MadaraUchiha到同一点,为了让网站行为正确,并且您怀疑这是问题所在,那么请不要犹豫,在 S*SS 中将其拉到一边(或者它是S@SS?)并给它一个更短的选择器。.if .your .nested div #is .too-deep
1赞 Drops 5/10/2014 #6

虽然不是直接回答你的问题,但你可以出于自己的目的保留高度嵌套的 sass,但仍然使用 .在这里查看。@at-root

.parent {
  @at-root {
   .child1 { ... }
   .child2 { ... }
  }
} 

// compiles to ... 

.child1 { ... }
.child2 { ... }

评论

2赞 Madara's Ghost 5/10/2014
这有什么帮助?这只会让事情变得更加混乱。
0赞 Drops 5/10/2014
例如,我喜欢在 sass 文件(可读性、组织)中使用深度嵌套,因此为了避免在 css 输出中使用复杂的选择器,我使用 @at-root。正如我所说,这并不完全是您问题的答案,但如果您容易出现大量嵌套:),则需要牢记这一点