Sass combining parent using ampersand (&) with type selectors

I am having trouble with nesting in Sass. Say I have the following HTML:

<p href="#" class="item">Text</p>
<p href="#" class="item">Text</p>
<a href="#" class="item">Link</a>

When I try to nest my styles in the following I get a compiling error:

.item {
    color: black;
    a& {
        color:blue;
   }
}

How do I reference a type selector before the parent selector when it is part of the same element?


Solution 1:

As Kumar points out, this has been possible since Sass 3.3.0.rc.1 (Maptastic Maple).

The @at-root directive causes one or more rules to be emitted at the root of the document, rather than being nested beneath their parent selectors.

We can combine the @at-root directive along with interpolation #{} to arrive at the intended outcome.

SASS

.item {
    color: black;
    @at-root {
        a#{&} {
            color:blue;
        }
    }
}

// Can also be written like this.
.item {
    color: black;
    @at-root a#{&} {
        color:blue;
    }
}

Output CSS

.item {
    color: black;
}
a.item {
    color: blue;
}

Solution 2:

The @at-root-only method will not solve the problem if you intend to extend the closest selector up the chain. As an example:

#id > .element {
    @at-root div#{&} {
        color: blue;
    }
}

Will compile to:

div#id > .element {
    color: blue;
}

What if you need to join your tag to .element instead of #id?

There's a function in Sass called selector-unify() that solves this. Using this with @at-root it is possible to target .element.

#id > .element {
    @at-root #{selector-unify(&, div)} {
        color: blue;
    }
}

Will compile to:

#id > div.element {
    color: blue;
}