【问题标题】:How bad is it in practice to over-nest selectors in SASS/SCSS?在 SASS/SCSS 中过度嵌套选择器在实践中有多糟糕?
【发布时间】:2012-11-28 02:59:20
【问题描述】:

我有一个 .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 文件的大小,但我相信编译器知道如何缩小...
  • 如果能真正收到关于这个问题的正确答案,我会非常棒。幕后是否有一些编译器优化?当特定的 SCSS 规则(选择器?)被翻译成可能性能不佳的东西时,是否有可能收到来自编译器的警告?
  • @ZenMaster - 我不知道警告,但我知道正在进行优化(尽管它可能是 Compass 的事情)。我见过许多将具有匹配属性的选择器组合在一起的情况(所以p{color:red} div{color:red} 变成了p, div{color:red})。

标签: css performance css-selectors sass


【解决方案1】:

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

现在,Steve Souders 这么说on the average site it's simply not a real concern。但是,在 Web 应用程序或高度交互的网站上,CSS 规则 can make your repaints slower 的性能比它们必须的要差。如果你有很多重绘...

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

然而,正如jankfree.org 所指出的,并不是certain properties in certain contexts (html5rocks.com) 的后代或特定选择器使油漆变得昂贵。我认为长或复杂的选择器更像是a maintainability issue (Nicolas Gallagher) 而不是性能问题——请记住,可维护性与性能相互作用。高度可维护的代码可以更快地迭代并且更容易调试(帮助您发现和修复性能问题)。

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

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

      选择器的嵌套越重,生成的 CSS 规则就越具体(您已经知道了)。因此,当您想在某个时候“胜过”该规则时,您必须在级联的下方编写一个相同(或更高)特异性的规则以推翻第一个规则。如果您在其中有一个 ID,这也将使其更加具体(所以避免,除非您需要它们并且知道您不需要覆盖下一行)。

      要遵循这个逻辑结论,除非需要,否则不要嵌套。不要有这样的规则:

      .selector .another .yeah-another {}

      什么时候可以做同样的工作:

      .yeah-another {}

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

      【讨论】:

        【解决方案4】:

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

        正如 SMACSS 建议的那样,我将嵌套在类名中。即,使用.child-of-parent 而不是.parent .child.parent > .child

        在实践中糟糕的嵌套会导致页面极其缓慢。看看 github 如何加速他们的差异页面。你至少应该遵循inception rule 声明你不应该嵌套超过 4 个级别。

        但是,我会更进一步说我们根本不应该嵌套 CSS。我写了一个blog post 表达我的意见。希望这有用。

        【讨论】:

        • 一个写得很好的答案。谢谢你。我也会读你的博文:)
        【解决方案5】:

        我的看法:

        你告诉哪个对你的眼睛更不利

        来自操作

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

        或者按照建议

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

        所以...

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

        WORSE 做法在于将 SASS(或者是 SCSS?)输出以机器驱动的状态用于生产。

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

        尽可能多地和尽可能深地筑巢,然后遵循良好实践...

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

        【讨论】:

        • 我喜欢同时使用 S@SS :P 谢谢你的回答,我同意这里所说的很多,但是,似乎存在过度嵌套的问题它涉及页面的动画和重排。所以“神话”本身也有一些优点。不过,你会得到我的 +1 :)
        • @MadaraUchiha 在同一点上很好,.if .your .nested div #is .too-deep 让网站正常运行,你怀疑这是问题所在,然后毫不犹豫地把它拉到一边,在 S* SS(或者是 S@SS?)并给它一个更短的选择器。
        【解决方案6】:

        虽然不能直接回答您的问题,但您可以为自己的目的保留高度嵌套的 sass,但仍然使用@at-root。看看here

        .parent {
          @at-root {
           .child1 { ... }
           .child2 { ... }
          }
        } 
        
        // compiles to ... 
        
        .child1 { ... }
        .child2 { ... }
        

        【讨论】:

        • 这有什么帮助?它只会让事情变得更加混乱。
        • 例如我喜欢在 sass 文件中使用深度嵌套(可读性、组织性),因此为了避免 css 输出中出现复杂的选择器,我使用了@at-root。正如我所说,这并不完全是您问题的答案,但如果您容易出现大量嵌套,请记住这一点:)
        猜你喜欢
        • 1970-01-01
        • 2017-09-15
        • 1970-01-01
        • 1970-01-01
        • 2014-07-31
        • 2015-11-09
        • 1970-01-01
        • 2016-11-24
        相关资源
        最近更新 更多