Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 561
McShaman Avatar asked Jun 24 '13 04:06

McShaman


People also ask

What does the ampersand & symbol do in Sass SCSS?

Ampersand or “&” is a powerful feature of SASS. It enhances the readability of code by using nesting statements, which takes an edge over conventional CSS. We can nest the css class any number of times but most of the times it's not required.

What is the use of & in SCSS?

The & is a special selector invented by SCSS which is used in nested selectors to refer to the outer selector . It simply means that it will be replaced with the outer selector when compiling to CSS.


5 Answers

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;
}
like image 192
Blaine Avatar answered Oct 17 '22 18:10

Blaine


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;
}
like image 44
Ben Avatar answered Oct 17 '22 17:10

Ben


For starters, (at time of writing this answer) there's no sass syntax that uses selector&. If you were going to do something like that, you'd need a space between the selector and the ampersand. For example:

.item {
    .helper & {

    }
}

// compiles to:
.helper .item {

}

The other way of using the ampersand is probably what you're (incorrectly) looking for:

.item {
    &.helper {

    }
}

// compiles to:
.item.helper {

}

This allows you to extend selectors with other classes, IDs, pseudo-selectors, etc. Unfortunately for your case, this would theoretically compile to something like .itema which obviously doesn't work.

You may just want to rethink how you're writing your CSS. Is there a parent element you could use?

<div class="item">
    <p>text</p>
    <p>text</p>
    <a href="#">a link</a>
</div>

This way, you could easily write your SASS in the following manner:

.item {
    p {
        // paragraph styles here
    }
    a {
        // anchor styles here
    }
}

(Side note: you should take a look at your html. You're mixing single and double quotes AND putting href attributes on p tags.)

like image 45
imjared Avatar answered Oct 17 '22 16:10

imjared


AFAIK In case you want to combine ampersand for class and tags at the same time, you need to use this syntax:

.c1 {
  @at-root h1#{&},
    h2#{&}
    &.c2, {
    color: #aaa;
  }
}

will compile to

h1.c1,
h2.c1,
.c1.c2 {
  color: #aaa;
}

Other uses (like using the class before @at-root or using multiple @at-roots) will lead to errors.

Hope it'll be useful

like image 35
Vahid Avatar answered Oct 17 '22 18:10

Vahid


This feature has landed in the newest version of Sass, 3.3.0.rc.1(Maptastic Maple)

The two closely related features which you'll need to use are the scriptable &, which you can interpolate within a nested styles to reference parent elements, and the @at-root directive, which places the immediately following selector or block of css at the root (it will not have any parents in the outputted css)

See this Github issue for more details

like image 21
kumarharsh Avatar answered Oct 17 '22 16:10

kumarharsh