Sass ampersand, select immmediate parent?

2019-02-04 02:19发布

问题:

Is there a way in Sass to use the ampersand to select the immediate parent, rather than the parent selector of the entire group? For example:

.wrapper{
    background-color: $colour_nav_bg;
    h1{
        color: $colour_inactive;
        .active &{
            color: red;
        }
    }
}

compiles to:

.wrapper h1{
    color: grey;
}

.active .wrapper h1{
    color: red
}

but what I actually want is:

.wrapper .active h1{
    color: red;
}

Is the only option to write the SCSS like so?

.wrapper{
    background-color: $colour_nav_bg;
    h1{
        color: $colour_inactive;
    }
    .active h1{
        color: red;
    }
}

The HTML looks like this:

<ul class="wrapper">
    <li class="active">
        <h1>blah</h1>
    </li>
</ul>

回答1:

As of this writing, there is no Sass selector for the direct parent instead of the root parent of an element. There is & which (as you know) selects the root parent. There are also % placeholder selectors which hides a rule until it's been extended.

Sass is open-sourced, so you could contribute a new "direct parent" selector.



回答2:

You can work around this today with a mixin like this one:

@mixin if-direct-parent($parent-selector) {
  $current-sequences: &;
  $new-sequences: ();

  @each $sequence in $current-sequences {
    $current-selector: nth($sequence, -1);
    $prepended-selector: join($parent-selector, $current-selector);
    $new-sequence: set-nth($sequence, -1, $prepended-selector);
    $new-sequences: append($new-sequences, $new-sequence, comma);
  }

  @at-root #{$new-sequences} {
    @content;
  }
}

Since the & is essentially a list of lists, you can use list functions (nth, set-nth, join and append) to create the selector sequence you want. Then use @at-root to output the new selector at root-level. Here's how you'd use it:

.grandparent-1,
.grandparent-2 {
  color: red;

  .child {
    color: blue;

    @include if-direct-parent('.parent') {
      color: green;
    }
  }
}

Which will output:

.grandparent-1,
.grandparent-2 {
  color: red;
}
.grandparent-1 .child,
.grandparent-2 .child {
  color: blue;
}
.grandparent-1 .parent .child, .grandparent-2 .parent .child {
  color: green;
}


回答3:

You need to wrap @at-root content in {}

.wrapper {
    h1 {
        @at-root {
           .wrapper .active h1 {
                color: red;
           }
        }
    }
}


回答4:

I have often wanted to do what you're asking and its a no go. I heard you can do that sort of thing in Stylus however. But there is another thing you can try which is to use @at-root to teleport outside of your nesting tree. For instance:

.wrapper{
    h1{
        @at-root .wrapper .active h1 {
            color: red;
        }
    }
}

This should compile down to the following:

.wrapper .active h1 {
  color: red;
}

The nice part is you keep your selector where it logically makes sense in the nesting structure for organizational purposes.



标签: sass