SASS CSS:子级的目标父类

发布于 2025-01-06 00:37:15 字数 586 浏览 0 评论 0原文

我正在使用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{....}

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

谢谢。

I am using SASS and found an inconvenience. This is an example of what I am trying to do:

.message-error {
    background-color: red;

    p& {
        background-color: yellow
     }
  }

Expected CSS:

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

The idea: all elements with .message-error will be red, except if it is p.message-error. This is not real-life situation, just to show an example.

SASS is not able to compile this, I even tried string concatenation. Is there some plugin that will do exactly the same?

NOTE:
I know I can put another CSS definition like:

p.message-error{....}

...under, but I would like to avoid that and use one place for all .message-error definitions.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

妥活 2025-01-13 00:37:15

从 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代码>.

As of Sass 3.4, this is now supported. The syntax looks like this:

.message-error {
    background-color: red;

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

Note the @at-root directive and the interpolation syntax on the ampersand. Failure to include the @at-root directive will result in a selector like .message-error p.message-error rather than p.message-error.

凌乱心跳 2025-01-13 00:37:15

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

.Parent {
  $p: &;

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

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

You can assign the current selector to a variable and then use it at any depth:

.Parent {
  $p: &;

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

    #{$p}--disabled & {
      background-color: grey;
    }
  }
}
有深☉意 2025-01-13 00:37:15

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

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

来源:# 282 – Element.parent 选择器

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

Natalie Weizenbaum (the lead designer and developer of Sass) says it will never be supported:

Currently, & is syntactically the same as an element selector, so it
can't appear alongside one. I think this helps clarify where it can be
used; for example, foo&bar would never be a valid selector (or would
perhaps be equivalent to foo& bar or foo &bar). I don't think this use
case is strong enough to warrant changing that.

Source: #282 – Element.parent selector

To my knowledge, there is no possible workaround.

云归处 2025-01-13 00:37:15

最好的做法可能是这样(假设您的 .message-error 类中除了背景颜色之外还有更多内容)。

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

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

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

The best thing to do would be probably this (assuming you have a little more in your .message-error class than just background color.

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

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

This approach doesn't offer that close grouping, but you can just keep them close to each other.

断桥再见 2025-01-13 00:37:15

我遇到了同样的问题,所以我为此做了一个 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;
    }
  }
}

为了使其工作,您还需要一个字符串替换函数来自 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;
}

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

I had the same problem so I made a mixin for that.

@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;
    }
  }
}

To make it work, you will need a string replacement function as well (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;
}

How it works:

SCSS

.foo {
  color: blue;

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

Output

.foo {
  color: blue;
}

p.foo {
  color: red;
}

Use case
This method works with nested selectors but not whit compound ones.

寂寞清仓 2025-01-13 00:37:15

@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
     }
  }

@Zeljko It is no possible to do what you want via SASS.

See Nex3 comment: https://github.com/nex3/sass/issues/286#issuecomment-7496412

The key is the space before the '&':

.message-error {
    background-color: red;

    p & {
        background-color: yellow
     }
  }

instead of:

.message-error {
    background-color: red;

    p& {
        background-color: yellow
     }
  }
懒猫 2025-01-13 00:37:15

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

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

当然,body可以替换为其他一些公共父元素,例如#Content< /code> 或另一个包含所有错误消息的 div 名称。

更新(另一个想法)

如果您利用@for 列表 然后看起来这应该可行(我不确定列表是否允许 . (句点)。

@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;}

I think if you want to keep them grouped by parent selector, you might need to add a common parent:

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

Of course, body could be replaced with some other common parent, such as #Content or another div name that will contain all the error messages.

UPDATE (Another Idea)

If you leverage @for and lists then it seems like this should work (what I don't know for sure is if the list will allow the . (period).

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

Should compile to something like:

.message-error {
   background-color: red;}
p.message-error {
   background-color: yellow;}
ul.message-error {
   background-color: cyan;}
浮光之海 2025-01-13 00:37:15

我做了一个 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;
}

I made a mixin that solves this problem.

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

Example: https://codepen.io/imkremen/pen/RMVBvq


Usage (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;
        }
      }
    }
  }
}

Result (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;
}
小苏打饼 2025-01-13 00:37:15

我使用类似的解决方案创建了 package/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';
 }

有关存储库的更多信息。

I created package/mixin with a similar solution :) (Maybe it will help U)

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

so writing:

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

This mixin will add selector only for the last parent:

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

More info on the repo.

情丝乱 2025-01-13 00:37:15

我以前也遇到过这个问题。 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

I have ran into this before as well. Bootstrap 3 handles this using a parent selector hack. I've tweaked it slightly for my own purposes...

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

wheresrhys uses a similar approach above, but with some sass errors. The code above allows you to manage it as one block and collapse it in your editor. Nesting the variable also makes it local so you can reuse $class for all instances where you need to apply this hack. See below for a working sample...

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

我一向站在原地 2025-01-13 00:37:15

当我需要更改中间的某些元素时,我使用这样的 @mixin 函数
一棵萨斯大树的。

第一个参数是父元素、目标,第二个参数是应该具有的类。

SASS

@mixin parentClass($parentTarget, $aditionalCLass) {

    @at-root #{selector-replace(&, $parentTarget, $parentTarget + $aditionalCLass)} {
        @content;
    }
}
示例,

就像我需要改进强标记中的字体大小一样,当 .txt-target 也有 .txt-strong

HTML

   <section class="sample">
        <h1 class="txt-target txt-bold">Sample<strong>Bold</strong>Text</h1>
    </section>

SASS

section{
    .txt-target{
        strong{
            @include parentClass('.txt-target','.txt-bold'){
                font-weight:bold;
                font-size:30px;
            }
        }
    }
}

字体:

https://sass-lang.com/documentation/at-rules/at -root

这里可以看到一个名为 @mixin unify-parent($child) 的函数,如下所示

I use an @mixin function like this, when i need change some element in middle
of a sass big tree.

The first parameters is the parent element, the target, and the second the class that should have.

SASS

@mixin parentClass($parentTarget, $aditionalCLass) {

    @at-root #{selector-replace(&, $parentTarget, $parentTarget + $aditionalCLass)} {
        @content;
    }
}
Sample,

like i need to improve font size in a strong tag, when .txt-target had .txt-strong too

HTML

   <section class="sample">
        <h1 class="txt-target txt-bold">Sample<strong>Bold</strong>Text</h1>
    </section>

SASS

section{
    .txt-target{
        strong{
            @include parentClass('.txt-target','.txt-bold'){
                font-weight:bold;
                font-size:30px;
            }
        }
    }
}

Font:

https://sass-lang.com/documentation/at-rules/at-root

Here you can see a function called @mixin unify-parent($child) that looks like this

放赐 2025-01-13 00:37:15

这个作弊可能会起作用,

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

     p#{$and} {
        background-color: yellow
     }
  }

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

SASS 具有内置的作用域,这样就不必担心 $and 的值泄漏到样式表的其余部分

变量仅在嵌套选择器级别内可用
它们的定义位置。如果它们是在任何嵌套之外定义的
选择器,它们随处可用。

This cheat might work

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

     p#{$and} {
        background-color: yellow
     }
  }

You may even be able to use $& as your variable name but I'm not 100% sure it won't throw an error.

And SASS has inbuilt scoping, which removes having to worry about the value of $and leaking out to the rest of your stylesheet

Variables are only available within the level of nested selectors
where they’re defined. If they’re defined outside of any nested
selectors, they’re available everywhere.

暗恋未遂 2025-01-13 00:37:15

在当前版本:Selective Steve (3.4.14) 中,这现在是可能的,只需要更新一点您的代码:

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

这仅在您是一层嵌套时才有效,例如,如果您有这样的内容,则它不起作用:

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

In the Current Release: Selective Steve (3.4.14) this is now possible, just need to update a little bit your code:

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

this only works if you are one level nested, for instance it does not work if you have something like this:

.messages{
    .message-error {
        background-color: red;
        p &{
            background-color: yellow
         }
     }
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文