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

Posted

技术标签:

【中文标题】在 SASS/SCSS 中过度嵌套选择器在实践中有多糟糕?【英文标题】:How bad is it in practice to over-nest selectors in 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 的事情)。我见过许多将具有匹配属性的选择器组合在一起的情况(所以pcolor:red divcolor:red 变成了p, divcolor:red)。 【参考方案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 Sullivan、Paul Irish 和 Steve 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。正如我所说,这并不完全是您问题的答案,但如果您容易出现大量嵌套,请记住这一点:)

以上是关于在 SASS/SCSS 中过度嵌套选择器在实践中有多糟糕?的主要内容,如果未能解决你的问题,请参考以下文章

Sass(Scss)基础梳理与实践

Sass(Scss)基础梳理与实践

如何将 svelte :global() 与 sass/scss 一起使用?

vue2.0以上版本安装sass(scss)

sass/scss 和 less的区别

Sass ,Scss 简单教程