【问题标题】:SASS CSS: Target Parent Class from ChildSASS CSS:来自子级的目标父类
【发布时间】:2012-02-15 12:59:23
【问题描述】:

我正在使用 SASS,发现不便。这是我正在尝试做的一个例子:

.message-error {
    background-color: red;

    p& {
        background-color: yellow
     }
  }

预期的 CSS:

.message-error {
    background-color: red;
}
p.message-error {
    background-color: yellow ;
}

想法:所有带有 .message-error 的元素都是红色的,除非它是 p.message-error。这不是现实生活中的情况,只是为了展示一个例子。

SASS 无法编译这个,我什至尝试了字符串连接。是否有一些插件可以做到完全相同?

注意: 我知道我可以放另一个 CSS 定义,例如:

p.message-error{....}

...under,但我想避免这种情况,并为所有 .message-error 定义使用一个位置。

谢谢。

【问题讨论】:

  • 就像你说的:这不是现实生活中的情况。无论您使用的是 CSS 还是 Sass,最好做您知道该做的事情。没有理由按照你的提议去做。如果有,请澄清。
  • 它并没有过多地脱离现实生活:如果消息错误是

      ,我想要的是具有不同的布局。示例:对于

      元素,框的左侧会有一些背景 URL 图像(检查 Constellation 管理模板)。但如果是

        ,则没有精灵。
  • 不了解 sass。但是在正常的 CSS 中,如果你想要“所有带有 .message-error 的元素都是红色的,如果它是 p.message-error”,我假设 p.message-error 也不需要是黄色的,而不是我们可以使用否定伪类选择器“.message-error:not(p.message-error)” - 不确定。
  • 你有解决办法吗?
  • @cimmanon 的答案应该被选为解决方案,因为现在支持此功能。

标签: css sass


【解决方案1】:

从 Sass 3.4 开始,现在支持此功能。语法如下:

.message-error {
    background-color: red;

    @at-root p#{&} {
        background-color: yellow
    }
}

请注意 @at-root 指令和 & 符号上的插值语法。未能包含@at-root 指令将导致选择器类似于.message-error p.message-error 而不是p.message-error

【讨论】:

  • @at-root 是一个很酷的新功能,但是当它嵌套在另一层选择器中时,它会惨遭失败。尽管它可能适用于 Zeljko 的情况。 sassmeister.com/gist/bf8492e469d91740194b
  • @at-root 遇到与 .me {p & {}} 相同的问题,因为它一直跳到根。在我的情况下,我使用特定于页面的包装类来命名 css,使用其中任何一个都会失败。
  • 非常有用。谢谢你
【解决方案2】:

您可以将当前选择器分配给一个变量,然后在任意深度使用它:

.Parent {
  $p: &;

  &-Child {
    #{$p}:focus & {
      border: 1px solid red;
    }

    #{$p}--disabled & {
      background-color: grey;
    }
  }
}

【讨论】:

  • @TobiAkinyemi 不确定您使用的是什么奇怪的旧编译器 - codepen.io/ferahl/pen/MWbJxzdcodesandbox.io/s/gracious-hodgkin-y16gx?file=/src/App.js
  • 看截图。 .Parent-Child 不是一个现实的/可扩展的场景。 .parent .child.parent > .child 是 - 你可以在截图中看到发生了什么
  • 很抱歉,这方面的文档在哪里?它对我不起作用(并且不适用于在线 SCSS 编译器)
【解决方案3】:

Natalie Weizenbaum(Sass 的首席设计师和开发人员)表示永远不会支持它:

目前,& 在语法上与元素选择器相同,因此它 不能出现在一个旁边。我认为这有助于澄清它可以在哪里 用过的;例如,foo&bar 永远不会是有效的选择器(或者 可能相当于foo& barfoo &bar)。 我不认为这个用途 案例足够强大,足以保证改变这一点。

来源:#282 – Element.parent selector

据我所知,没有可能的解决方法。

【讨论】:

  • 我也找到了那个。事实上,它在旧版本中得到支持,并且由 Stylus 支持(我会使用但不知道如何安装)。这就是为什么我一直在寻找一些补丁、hack 之类的东西。
  • 考虑到@cinnamon 2 年后的回答,真正令人失望的是,最初的创建者使用“从不”来描述此功能的实现。我猜他们吸取了教训。
  • 在这个答案中应该注意,现在有一个支持的方法。
【解决方案4】:

最好的办法可能是这样(假设您的 .message-error 类中包含的不仅仅是背景颜色。

.message-error {
  background-color: red;
}

p.message-error {
  @extend .message-error;
  background-color: yellow
}

这种方法不提供那种紧密的分组,但您可以让它们彼此靠近。

【讨论】:

  • 我会说除非你有很少的课程可以这样做,否则我会避免使用@extend。你最终会得到巨大的 CSS 文件,因为这会创建 .message-error, p.message-error, ... { ... }。一两个就可以了,明智地使用。
【解决方案5】:

我遇到了同样的问题,所以我为此做了一个 mixin。

@mixin tag($tag) {
  $ampersand: & + '';
  $selectors: simple-selectors(str-replace($ampersand, ' ', ''));

  $main-selector: nth($selectors, -1);
  $previous-selectors: str-replace($ampersand, $main-selector, '');

  @at-root {
     #{$previous-selectors}#{$tag}#{$main-selector} {
      @content;
    }
  }
}

要使其工作,您还需要一个字符串替换功能 (from Hugo Giraudel):

@function str-replace($string, $search, $replace: '') {
  $index: str-index($string, $search);
  @if $index {
    @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
  }
  @return $string;
}

工作原理:

SCSS

.foo {
  color: blue;

  @include tag(p) {
    color: red;
  }
}

输出

.foo {
  color: blue;
}

p.foo {
  color: red;
}

用例
此方法适用于嵌套选择器,但不适用于复合选择器。

【讨论】:

    【解决方案6】:

    @Zeljko 不可能通过 SASS 做你想做的事。

    见 Nex3 评论:https://github.com/nex3/sass/issues/286#issuecomment-7496412

    关键是'&'之前的空格:

    .message-error {
        background-color: red;
    
        p & {
            background-color: yellow
         }
      }
    

    代替:

    .message-error {
        background-color: red;
    
        p& {
            background-color: yellow
         }
      }
    

    【讨论】:

    • 添加空格会使输出p .message-error,我认为OP正在寻找p.message-error(没有空格);虽然您的建议有效,但我认为这不是这种特殊情况下的解决方案。
    【解决方案7】:

    我认为如果你想让它们按父选择器分组,你可能需要添加一个共同的父:

    body {
        & .message-error {background-color: red;}
        & p.message-error {background-color: yellow}
    }
    

    当然,body 可以替换为其他一些常见的父级,例如 #Content 或另一个包含所有错误消息的 div 名称。

    更新(另一个想法)

    如果您利用@forlists,那么这似乎应该有效(我不确定该列表是否允许.(句点)。

    @for $i from 1 to 3 {
      nth(. p. ul., #{$i})message-error {
        background-color: nth(red yellow cyan, #{$i}));
      }
    }
    

    应该编译成这样的:

    .message-error {
       background-color: red;}
    p.message-error {
       background-color: yellow;}
    ul.message-error {
       background-color: cyan;}
    

    【讨论】:

    • 我希望它们嵌套,而不是在附近分组:)
    • @Zeljko——我想出了另一个可能的解决方案。我不知道它是否满足您的需求,但可能是一种紧凑的编写方式。
    • 谢谢,但我真的需要我在第一篇文章中提出的要求。
    【解决方案8】:

    我做了一个 mixin 来解决这个问题。

    Github:https://github.com/imkremen/sass-parent-append

    示例:https://codepen.io/imkremen/pen/RMVBvq


    用法(scss):

    .ancestor {
      display: inline-flex;
    
      .grandparent {
        padding: 32px;
        background-color: lightgreen;
    
        .parent {
          padding: 32px;
          background-color: blue;
    
          .elem {
            padding: 16px;
            background-color: white;
    
            @include parent-append(":focus", 3) {
              box-shadow: inset 0 0 0 8px aqua;
            }
    
            @include parent-append(":hover") {
              background-color: fuchsia;
            }
    
            @include parent-append("p", 0, true) {
              background-color: green;
            }
          }
        }
      }
    }
    

    结果(css):

    .ancestor {
      display: inline-flex;
    }
    .ancestor .grandparent {
      padding: 32px;
      background-color: lightgreen;
    }
    .ancestor .grandparent .parent {
      padding: 32px;
      background-color: blue;
    }
    .ancestor .grandparent .parent .elem {
      padding: 16px;
      background-color: white;
    }
    .ancestor:focus .grandparent .parent .elem {
      box-shadow: inset 0 0 0 8px aqua;
    }
    .ancestor .grandparent .parent:hover .elem {
      background-color: fuchsia;
    }
    .ancestor .grandparent .parent p.elem {
      background-color: green;
    }
    

    【讨论】:

      【解决方案9】:

      我用类似的解决方案创建了包/mixin :)(也许它会帮助你)

      https://github.com/Darex1991/BEM-parent-selector

      这么写:

      .calendar-container--theme-second-2 {
        .calendar-reservation {
          @include BEM-parent-selector('&__checkout-wrapper:not(&--modifier):before') {
            content: 'abc';
          }
        }
      }
      

      这个 mixin 只会为最后一个父级添加选择器:

      .calendar-container--theme-second-2 .calendar-reservation__checkout-wrapper:not(.calendar-reservation--modifier):before {
         content: 'abc';
       }
      

      有关回购的更多信息。

      【讨论】:

        【解决方案10】:

        我以前也遇到过这种情况。 Bootstrap 3 使用父选择器 hack 来处理这个问题。为了我自己的目的,我稍微调整了一下......

        @mixin message-error() {
          $class: '.message-error';
          #{$class} {
            background-color: red;
          }
          p#{$class} {
            background-color: yellow;
          }
        }
        @include message-error();
        

        wheresrhys 使用与上述类似的方法,但有一些 sass 错误。上面的代码允许您将其作为一个块进行管理并在您的编辑器中折叠它。嵌套变量也使其成为本地变量,因此您可以在需要应用此 hack 的所有实例中重用 $class。请参阅下面的工作示例...

        http://sassmeister.com/gist/318dce458a9eb3991b13

        【讨论】:

        • 如果在您修正了一个小错字后之前的答案有效,那么适当的操作是修正错字,而不是发布一个全新的答案。
        • 我认为这种方法足够不同,可以分享。
        【解决方案11】:

        这个作弊可能有用

         {
             $and: .message-error;
             #{$and} {
                background-color: red;
             }
        
             p#{$and} {
                background-color: yellow
             }
          }
        

        您甚至可以使用 $& 作为变量名,但我不能 100% 确定它不会引发错误。

        而且 SASS 具有内置范围,无需担心 $and 的值会泄漏到样式表的其余部分

        变量仅在嵌套选择器级别内可用 它们被定义的地方。如果它们是在任何嵌套之外定义的 选择器,它们无处不在。

        【讨论】:

        • 我也想过这样的事情,但我相信上面的输出(假设插值按预期工作)实际上是.message-error p.message-error {...},而父级的 Zeljko 最初尝试使用选择器&(如果它按照他想要的方式工作)它不会嵌套,并产生p.message-error {...}。我不确定这一点,因为我不是 SASS 专家,但通过阅读文档,我似乎已经正确理解了您的解决方案的输出。
        • 哦,是的...很好发现。我已经编辑了其他可能有用的东西,虽然不太整洁
        • 谢谢大家,但这看起来比 .message-error{} 下的 p.message-error{} 更糟糕。而且它仍然没有按照我的需要嵌套。我想我要么学习 Stylus,要么为 SASS 创建一张票。
        • 这里有两件事。如果我错了,请纠正我,但我不相信没有选择器的括号会起作用。您还需要在班级名称周围加上引号。
        【解决方案12】:

        在当前版本中:Selective Steve (3.4.14) 现在可以这样做了,只需要稍微更新一下您的代码:

        .message-error {
            background-color: red;
            p &{
                background-color: yellow
             }
         }
        

        这仅在您是一级嵌套时才有效,例如,如果您有这样的东西,它就不起作用:

        .messages{
            .message-error {
                background-color: red;
                p &{
                    background-color: yellow
                 }
             }
         }
        

        【讨论】:

        • 这一直有效,并且 不是 OP 在这里要求的。
        猜你喜欢
        • 1970-01-01
        • 2020-12-13
        • 2021-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-15
        • 1970-01-01
        相关资源
        最近更新 更多