2
votes

I know in SCSS I can do this:

.foo {
    color: blue;
    a {
        color: red;
        .bar & { color: green; }
    }
}

And get this:

.foo { color: blue; }
.foo a { color: red; }
.bar .foo a { color: green; }

But is there a way to append that selector, to result in:

.foo { color: blue; }
.foo a { color: red; }
.foo.bar a { color: green; }

Note this is a simple example, in my use case the rule is nested much deeper than this.

4

4 Answers

4
votes

The & only works one level up. In your code example, you wouldn't be able to get the code you expect. You'll need to handle it in a different way.

.foo {
    color: blue;
    a {
        color: red;
    }
    &.bar {
       a {
          color:green;
       }
    }
}
1
votes

Apparently this only renders with phpsass compiler, so it is compiler specific.

Just get rid of your space before the &:

.foo {
    color: blue;
    a {
        color: red;
        .bar& { color: green; }
    }
}

Compiles to:

.foo {
  color: blue;
}

.foo a {
  color: red;
}

.bar.foo a {
  color: green;
}

Note that .foo.bar and .bar.foo are equivalent selectors (they both make a selection only if both classes are on the item), so the order does not matter in such a case. Now, whether this could work in a more deeply nested structure (which you state you have) all depends on what you are trying to target, but essentially this would add a class to the outmost level (your .foo equivalent) no matter how deep the structure.

0
votes

You can qualify a selector by putting & to the right of the intended parent of the selector. Wrapping it in #{} allows you to place it directly beside that parent.

The @at-root rule causes everything proceeding it to be emitted at the root instead of using regular nesting.

If you use both, you can achieve what you are looking for.


.flashlight {
    .light {
        background: yellow;

        @at-root .dead-battery#{&} {
            background: transparent;
        }

        .daytime &{
            background: transparent;
        }
    }
}

This would compile to:

.flashlight .light {
  background: yellow;
}
.dead-battery.flashlight .light {
  background: transparent;
}
.daytime .flashlight .light {
  background: transparent;
}
-1
votes

You're having an XY problem. You need to override the color of a, but instead of asking for an optimal way to do that, you invent some weird construction and ask why it is not working.

The matter is that you don't need to put a inside .foo to override the color. An a gets it's color not from .foo directly, but from a's own color property.

By default color is set to inherit, which naturally inherits from parent. So to override a's color, you change it's color property from inherit to whatever you want. To do that, you don't need to put parent into the selector!

UPD: As cimmanon has corrected me below, the color of a is not inherited from parent, it uses its own default value instead.

So an optimal solution would be this:

.foo {
  color: blue; }

a {
  color: red;

  .foo.bar & {
    color: green; } }

Also, the fact that you want to override exactly for .foo.bar a indicates that you're overcomplicating things.

You only need .foo.bar a if you need to handle four different situations: a, .foo a, .bar a and .foo.bar a. Do you really have that much different colors for the links? Why?

Most certainly you could refactor your HTML structure, make it more semantic and be happy with code like this:

a {
  color: red; }

#header {
  color: blue; }

.cart-item 
   & a {
    color: green; } }

With this code, the link can only be two different colors: green for cart items and red for everything else.

If you do have a good reason to have many colors, consider using a mixin:

@mixin link-with-color($color: red) {
  a {
    color: $color; } }

#header {
  @include link-with-color(blue); }

.cart-item {
  @include link-with-color(green); }