Skip to content
This repository

Syntax improvements related to the `&` selector #286

Closed
chriseppstein opened this Issue February 21, 2012 · 89 comments
Chris Eppstein
Collaborator

See #282 for the discussion leading to the creation of this umbrella issue.

Nathan Weizenbaum
Owner

If we do something smart with & + &, how should we handle & > & or & &?

Chris Eppstein
Collaborator

I don't think we should try to get into the business of understanding how to interpret combinators with &. Instead I think we should give better expressiveness about what is meant by the author.

For instance:

  • last-selector(&) + last-selector(&)
  • all-but-last-selector(&) > .foo > last-selector(&)

bad naming above is on purpose. Also, could consider using pseudo selectors instead of functions like &::last-component but this creates potential namespace collisions.

Nathan Weizenbaum
Owner

I'm not opposed on principle to adding some way of using functions along with &, but we'd need to find a good syntax for it. This means something that has a low probability of conflicting with CSS, and ideally something that integrates well with our existing syntax.

Here's one possibility that has a small delta on our existing syntax: we allow & as a first-class object in SassScript that evaluates to the parent selector. This allows you to write standard functions that operate on selectors; e.g. & + #{last-selector(&)}.

Chris Eppstein
Collaborator

It seems like if we are going to a make a literal that represents a selector in SassScript that we're close to allow storing a selector into a variable and allowing variables of type "selector" to be used without interpolation in selectors. I think this could be very attractive.

Nathan Weizenbaum
Owner

Having selectors be a first-class type (that is, storing them in variables) is very, very different than allowing variables without interpolation in selectors. Once variables are allowed without interpolation somewhere, people will expect all of SassScript to work; see for example #284. There's no good way to support all of SassScript in a selector.

Chris Eppstein
Collaborator

agree that these are separable concepts.

Trying to decide if I want to make a case for allowing a simple subset of SassScript that is Selector Safe™.

Chris Eppstein
Collaborator

Adding #285 to the list of things to consider here.

Zee Agency

I may be wrong but what about a syntax like &(1) where 1 is the number of steps back in the selector nesting chain (not sure how to call it, hopes you understand what I mean...).

For instance :

.foo {
    .bar {
        & &(1) {
            a: b;
        }
    }
}

Would output :

.foo .bar .foo {
    a: b;
}
Nathan Weizenbaum
Owner

I really hate the idea of having different subsets of SassScript work in different places. I'm already considering disallowing @media $foo { ... } in favor of @media #{$foo} { ... }.

Nathan Weizenbaum
Owner

@ZeeAgency That feels like it's much harder to understand than it's worth, given how little it would be used.

Nathan Weizenbaum
Owner

After talking this over with Chris, we're currently leaning towards having & be a SassScript expression referring to the current parent selector. Rather than have it be a string, we'd have it be a space-separated list of strings to make it easier to operate on with functions. I believe this, along with user-defined functions, would support all the use-cases brought up here.

Eric M. Suzanne

I was about to open another related issue, but I think it might fall under this one. The parent-selector (&) should not error-out on base-level rules. It should simply not reference anything.

Here's a sample use-case:

@mixin respond-to($media,$ie-class:'ie') {
  @media (#{$media}) { @content; }

  // We need the parent selector here in order to mimic the @media bubbling.
  .#{$ie-class} & { @content; }
}

// This works already.
.container { 
  @include respond-to('min-width: 30em') {
    color: red; 
  }
}

// This should work with exactly the same result.
// And it would without the error from parent-selector:
// "Base-level rules cannot contain the parent-selector-referencing character '&'."
@include respond-to('min-width: 30em') {
  .container { color: red; }
}

As it is, you can't create a mixin that works both in a nested and root context, which severely limits the mixin.

Eric M. Suzanne

@chriseppstein @nex3 - any thoughts on that? It's a blocker for the next Susy update, so it would be good to know if and when it might land. Thanks!

Alan Hogan

This is currently the only open issue tagged v3.2. Is it the only blocker? When might 3.2 go stable?

Chris Eppstein
Collaborator

We have one more feature for 3.2. It's variable argument passing to mixins and functions. And there's a pending pull request for giving warnings when an @extend doesn't match any selector.

Nathan Weizenbaum
Owner
nex3 commented June 15, 2012

This isn't going to make it into 3.2. Re-tagging as 3.3.

Eric M. Suzanne
ericam commented June 15, 2012

Even if Susy say's please?

Nathan Weizenbaum
Owner
nex3 commented June 15, 2012

I'm trying very hard to get 3.2 out the door, which means avoiding any additional features.

Eric M. Suzanne
ericam commented June 15, 2012

Ok, Susy will just look forward to 3.3 with longing and anticipation. :)

Phillip Haydon

Will this allow something like.

.search {
   .container& {
      // if .search is inside .container...
   }
}

To output:

.container .search {
   // styles
}

( just trying to understand what I'm reading in this issue to see if it solves what I want :) )

Nathan Weizenbaum
Owner
nex3 commented August 03, 2012

@phillip-haydon You can do that today, like so:

.search {
   .container & {
      // ...
   }
}
Chris Eppstein
Collaborator

Reminder: be sure that ruby functions can access the & in a script context.

yobssarG m'I

how about this case?

$C: ".module-"; //module class name prefix
#{$C}farther {
    color:red;
    #{$C}child {
        color:orange;
    }
    & #{$C}child { //same as previous block
        color:orange; 
    }
    #{$C}grand-farther & {
        color:yellow;
    }
    &#{$C}mother {
        color:green;
    }
}

the newest version of sass's output is below

.module-farther { /* css block 1*/
  color: red;
}
.module-farther .module-child { /* css block 2*/
  color: orange;
}
.module-farther .module-child { /* css block 3*/
  color: orange;
}
.module-grand-farther .module-farther { /* css block 4*/
  color: yellow;
}
.module-farther.module- mother { /* css block 5*/
/*NOTICE: there is a SPACE char between the 2nd. ".module-" and "mother" */
  color: green;
}

In css block 1~4, the result of string combination in css selectors are correct...

but the selector in css block 5 should be

.module-farther.module-mother 

rather than

.module-father.module- mother /* a space char before "mother" */

btw, from http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#id11 (sass reference: @for)
we can confirm that string combination in css selectors would be accepted

i know the '&' reference cannot be combined with other string
but in this case, the string combination should occurred between ".module-" and "mother"
it should be accept just like the selectors in block 1~4

so... can we regard this case as a bug of sass?


finally, please forgive me about my poor English... thanks...

Nathan Weizenbaum
Owner
nex3 commented August 20, 2012

@Grassboy That happens because Sass doesn't understand what you mean when you do &#{$C}mother. It expects & to be followed by a simple selector (e.g. .foo, #bar); when it's followed by interpolation, it thinks you're just starting a new selector.

With this change, you'll be able to accomplish your goal by doing #{&}#{$C}mother.

yobssarG m'I

Thanks for your response...

i've found that the sass code can be modified as follow before #{&} is available

$C: "module-"; //module class name prefix
.#{$C}farther {
    color:red;
    .#{$C}child {
        color:orange;
    }
    & .#{$C}child { //same as previous block
        color:orange; 
    }
    .#{$C}grand-farther & {
        color:yellow;
    }
    &.#{$C}mother {
        color:green;
    }
}

then Sass would understand what i mean,
and i can modify my module name in the future easily in the future

Phillip Haydon

@nex3 this seems really fiddly. Given:

div.column {
    div.information {
      &:hover & {
          display: block;
      }
    }
}

I would expect the output

div.column:hover div.information {
    display:block;
}

However I end up with:

div.information:hover div.column div.information {
    display:block;
}

Seems broken or at-least doesn't do what I want it to do :(

yobssarG m'I

In div.information { ... }

the '&' character stands for "div.column div.information"

so, the block

div.column {
    div.information {
      &:hover & {
          display: block;
      }
    }
}

i guess it may generate

div.column div.information:hover div.column div.information {
    display: block;
}

under the optimization process, the result css may be reduced as

div.information:hover div.column div.information {
    display:block;
}

and maybe that's what you end up with

Nathan Weizenbaum
Owner

@phillip-haydon As @Grassboy points out, & refers to the entire parent selector. There's no way for Sass to know that you want it to refer to subsets of that selector -- let alone which subset -- in the example you gave.

Brewster

I see that the additional feature of using the parent selector at the base-level is a future feature for 3.3...

...but does 3.3 have a time table? I dont see a milestone setup for it. I am eagerly awaiting this feature :)

Nathan Weizenbaum
Owner

We generally don't commit to time tables, since Chris' and my schedules are generally pretty variable.

Brewster

Understood. More just curious. When you mentioned 3.3 I looked for a milestone to track issues against.

Kevin Montag

Not sure if this belongs in its own issue, but I'd love the ability to do something like the following:

+html-modifier(foo)
  color: blue
  +html-modifier(bar)
    color: red

Outputting:

html.foo { color: blue }
html.foo.bar { color: red }

Currently the closest I can get is:

=html-modifier($modifier)
  html.#{$modifier} &
    @content

However, this doesn't work at the base-level, and nesting the mixin generates rules like:

html.bar html.foo .selector { // styles }

Concretely, this would be useful for outputting separate styles based on e.g. different combinations of Modernizr detections, or different combinations of "theming" classes (like light/dark at http://compass-style.org/) applied to the HTML element.

Nathan Weizenbaum
Owner

@kmontag this could be used for something like that, although it would probably require pretty heavy-duty processing on the part of the mixin.

thesyd

is it posible?

.selector {
    .ie8 & { // property }
    //& plays ascendant role
}

css becomes

.ie8 .selector{ //property }

is there any feature in 3.3 to obtain from scss, something like .ie8 & { .child // property or child reference } to translate in css

.ie8 .selector .child { //property }
Nathan Weizenbaum
Owner
nex3 commented March 12, 2013

Yes; that works right now.

thesyd

how? if i may ask please

Snugug
.selector {
  .ie8 & {
    .child {
    }
  }
}
thesyd

this will result in
.ie8 .selector .child { }

what i was wonder if you can achieve a child of the .ie8 that reference it
.ie8 .child .selector { }
once you are in scss but without
.selector {
.ie8 .child & { }
}

Nathan Weizenbaum
Owner
nex3 commented March 13, 2013

No, you can't.

Iñaki Baz Castillo
ibc commented March 14, 2013

Some way to reference a parent would be useful. In my case I strongly miss something to improve the following syntax:

.parent {
  .child-1 {
    .child-2 {
      color: black;
    }
  }
}

.parent.selected .child-1 .child-2 {
  color: red;
}
Alexander Samilyak

I was really surprised so common css usecase @ibc described is such a mess in SASS. That's especially funny when

.parent{
  &.state{
    ...
  }
}

works, but

.parent{
  .child1{
    .child2{
      .state.&{ // or .state&
       ...
      }
    }
  }
}

doesn't work. Come on, I've just switched .state and &.
Anyway guys I love SASS (thanks for your work) and eagerly awaiting this feature to be implemented in 3.3.

Chris Eppstein
Collaborator

Come on, I've just switched .state and &.

You're treating & as if it's just a string replacement. It's not. & is a selector that is parsed like an element name and as such, there are only certain place it is valid for it to be present in a syntactically-valid way for all uses of the value of &. String replacement is what #{} is for, and as such exposing & to a script context is the way we're going to tackle this project. The script parser has to be changed to know what & means and then we have to wire the selector context into the script context.

This is very high on the list of features we want to add. I actually started working on it the other day.

Miller Medeiros

it would be good if we could manipulate the parent selector like a list, so we could potentially grab the last [n] selectors on the chain - eg. button#{tail(&)} inside .foo .bar would output button.bar.

FWeinb
FWeinb commented May 10, 2013

I thought about a way to better write BEM like CSS in SASS/SCSS.

The main idea is that it should be possible to write SCSS like this

.block{
    &__element{
    }
    &--modifier{
    }
}

to get this

.block{
}
.block__element{
}
.block--modifier{
}

I hope the new & selector will support this in v3.3. Or is there a better way to accomplish this?

Chris Eppstein
Collaborator

@FWeinb Yes, This would work like this:

.block{
    #{&}__element {
      // ...
    }
    #{&}--modifier {
      // ...
    }
}
FWeinb
FWeinb commented May 10, 2013

Yeah, tried that but that didn't work for me.

See: http://codepen.io/FWeinb/pen/601856036197d62523038b1413a79b59

Error on line number: 2. Invalid CSS after "    #{": expected expression (e.g. 1px, bold), was "&}__element {"

I have tested it local with Sass 3.2.8 (Media Mark)

Chris Eppstein
Collaborator

@FWeinb it will work in Sass 3.3.

Nathan Weizenbaum nex3 referenced this issue May 10, 2013
Closed

Ampersand problem #746

Arnaud Rinquin ArnaudRinquin referenced this issue in maxim/bootswatch-rails May 10, 2013
Closed

badges in Amelia #35

Nathan Weizenbaum
Owner
nex3 commented May 24, 2013

Chris and I ran into an issue with the implementation of this as sketched here. If you write foo { .bar#{&} { ... } } there's no good way for Sass to know that it shouldn't include .foo in the generated selector, yielding foo .barfoo { ... } instead of the desired .barfoo { ... }.

Our solution to this is to introduce a new directive, @at-root, which causes one or more selectors to be placed at the root of the document instead of being nested, while preserving the parent selector as the referent of &. So you'd write foo { @at-root .bar#{&} { ... } }, which would yield .barfoo { ... }. This is unfortunately verbose, but we think it's the best option.

It will also work without a selector, like so:

foo {
  @at-root {
    .bar#{&} { ... }
    .baz#{&} { ... }
    .qux#{&} { ... }
  }
}

Rejected Alternatives

Look For &

The first solution we considered was similar to what we do for non-SassScript selectors: look in the selector expressions and see if & is used. However, this breaks referential transparency, the principle that (in this case) $var: ...; #{$var} { ... } should always be equivalent to #{...} { ... }. This is because Sass would be unable to detect that a parent selector was being used in the code foo { $parent: &; .bar#{$parent} { ... } }.

"Parent Selector" Bit

We could try to track, for every SassScript value, whether that value is derived from a reference to the parent selector. This solves the referential transparency issues, but also adds a host of practical problems. Every SassScript operation and function, including third-party functions, would have to be aware of the parent selector bit and propagate it forward if necessary. Worse than the practical issues, though (in my opinion), is the issue of associating invisible and inaccessible information with an unremarkable-looking value.

Other Syntaxes

We talked about various different syntaxes for indicating that the parent selector should be omitted from a given selector. &:omit and :omit(&) were rejected for looking too much like plain CSS and for making it look like & could be replaced by a different selector. ::no-parent and ::no-& were rejected because the semantics of a pseudo-element didn't match well with the operation that was being performed. ^ was rejected because adding a completely new syntactic character bears a high cost and eats up syntax space that isn't worth it for what's ultimately a reasonably narrow feature.

Once we settled on the directive syntax, we also talked about different names. @no-parent was rejected because the parent selector & is still meaningful within the block. @no-auto-parent was rejected because of verbosity and because the nesting process isn't referred to as "auto parent" anywhere else. @unnested was rejected because nesting still occurs, it's just broken at one specific level. @bubble was rejected because the notion of "bubbling" is a reasonably advanced concept that we didn't want to presuppose knowledge of.

We chose @at-root because it didn't include a negation, which we thought caused confusion, and because it neatly describes the process of putting the selector(s) at the root of the document.

Deleted user
ghost commented May 29, 2013

The content you are editing has changed. Reload the page and try again.

Hello,

I've just update my version from 3.1.1 to 3.2.9.

Does this version includes the possibility to concatenate class names like this:

.badge 
   border: 1px solid black;
   &-info 
      background:blue;
  

to have a result as:

.badge { border: 1px solid black; }
.badge-info { background: blue; }

Or:

.bt,
.bp 
   border: 1px solid black;
   &-info 
      background:blue;

If this syntax isn't supported yet, how can I accomplish it? Have a huge amount of files in which I need to update the syntax.

Thanks!

Sending Request…

Attach images by dragging & dropping or selecting them. Octocat-spinner-32 Uploading your images… Unfortunately, we don't support that file type. Try again with a PNG, GIF, or JPG. Yowza, that's a big file. Try again with an image file smaller than 10MB. This browser doesn't support image attachments. We recommend updating to the latest Internet Explorer, Google Chrome, or Firefox. Something went really wrong, and we can't process that image. Try again.

Edward

@avrilverhaeghen you can't with 3.2.9. Something like that you have above will work in Sass 3.3 (though not with the synax your using).

svitaliyv

How can I install Sass 3.3 for work with "-" and "_" in class names?

Chris Eppstein
Collaborator

The lastest code changes are available via gem install sass --pre.

Carsten Kraus
casio commented May 31, 2013

@chriseppstein Just installed --pre, and tried:
#{&}__element { /*...*/ }

..but I still get:
Invalid CSS after " #{": expected expression (e.g. 1px, bold), was "&}__element {"

What would be the correct syntax?

Chris Eppstein
Collaborator

@casio that change hasn't landed yet.

Nick Middleweek

Hey @chriseppstein, how you doing? Looks like a few of us are eagerly waiting for the 'SASS-BEM' syntax, this will be awesome when it's released so thanks for making this happen... I see you guys have it in a 'late' Alpha stage, when is likely to be a proper 3.3 release? Are we talking weeks or months? I'm just thinking of production sites.

Cheers,
Nick Middleweek

Chris Eppstein
Collaborator
Mark Reilly

I have use/edge case that you may want to consider.

Due to poor system design, I need to override a style from a stylesheet that's called after mine. Mine is the 'skin' or 'theme' stylesheet and should be called last but it's not. I'm using CSS specificity to override the styles that come after.
I'd like to make a mixin to do this using the & selector but it doesn't quite work.

Mixin

@mixin specificity {
  & & {
    @content;
  }
}  

Sass

.whatever {
  @include specificity {
    border: solid;
  }
}

Outputted CSS

.whatever .whatever {
  border: solid;
}

Desired CSS

.whatever.whatever {
  border: solid;
}

Less than ideal workaround
In case anyone is looking for something similar or has a better solution here's my current workaround.

Mixin

@mixin specificity-2($selector) {
  &#{$selector} {
    @content;
  }
}

Sass

.whomever {
  @include specificity-2(".whomever") {
    border: solid;
  }
}

CSS

.whomever.whomever {
  border: solid;
}

This may indeed be an edge case but I thought I'd add it to the discussion.

Thanks,
Mark

Chris Eppstein
Collaborator

@alienresident This would be possible to do in sass 3.3. like this:

@function index-of-last-class($selector) {
  $index: null;
  $counter: 1;
  @each $component in $selector {
    @if str-index($component, ".") == 1 {
      $index: $counter;
    }
    $counter: $counter + 1;
  }
  @return $index;
}

@function list-slice($list, $start, $end: length($list)) {
  $new-list: ();
  @for $i from $start through $end {
     $new-list: append($new-list, nth($list, $i), list-separator($list));
  }
  @return $new-list;
}

@mixin increased-specificity($selector: &) {
  $class-index: index-of-last-class($selector);
  @if $class-index {
    @at-root #{list-slice($selector, 1, $class-index)}#{nth($selector,$class-index)} #{list-slice($selector, $class-index + 1, length($selector))} {
      @content;
    }
  }
  @else {
    @warn "Cannot increase the specificity of #{$selector}. It does not include a class name.";
    @content;
  }
}  

Note: this does not currently work, even on the lastest code base, as it uses planned features.

Mark Reilly

Wow, thanks!
Look forward to it's implementation. Thanks for all you work. Sass and Compass have changed my life. I can now design in the browser.

UPDATE

@mixin specificity {
  &#{&} {
    @content;
  }
}

.whatever {
  @include specificity {
    border: solid;
  }
}

Produces

.whatever.whatever {
  border: solid;
}

In Sass (v3.3.0.rc.1)
See (SassMeister gist)[http://sassmeister.com/gist/7142577]

This is what's supposed to happen right?

Anton Kuznetsov

@chriseppstein Hi. 2 months ago you told about bem-like syntax in 3.3.0. Today we have 212 alpha and we haven't this feature.
One question - when?

Paul d'Aoust

@chriseppstein @nex3 What might happen with nested @at-root directives? (Real life situation -- I'm trying to do some sort of 'root class bubbling' to emulate 'media query bubbling' for Modernizr-style root classes. Note that a lot of these selectors and styles would be inserted via mixins; I've just flattened it out for demonstration purposes.)

.menu {
    @at-root .unresponsive-desktop & {
        li { display: inline-block; }
        a { display: block; background: alice-blue; height: 1.5em;
            @at-root .unresponsive-desktop.touch & {
                height: 40px; // Make the target large enough to press with a finger.
            }
        }
    }
}

I imagine this would create something like...

.unresponsive-desktop .menu li { display: inline-block; }
.unresponsive-desktop .menu a { display: block; background: alice-blue; height: 1.5em; }
.unresponsive-desktop.touch .menu a { height: 40px; }

My question is, do @at-root directives bubble/nest (remembering the containing @at-root directive's selector and adding it on), or do they always break out to root, ignoring the containing @at-root directive completely? Because I can imagine the above Sass code creating this, which isn't quite right:

.unresponsive-desktop .menu .unresponsive-desktop.touch a { height: 40px; }

Thanks; looking forward to this!

Chris Eppstein
Collaborator

@pdaoust The value of & is unaffected by @at-root directives in any way. @at-root only tells sass to not do an automatic ancestor prepend to the immediate selectors within it. Or to the selector given as it's argument. To date, we haven't planned to allow both nested and inline selectors with @at-root

Chris Eppstein
Collaborator

@iSnifer Probably another month or so according to plan.

Paul d'Aoust

@chriseppstein So if I understand you correctly, my first example was the right guess?

Chris Eppstein
Collaborator

No, first, it's using a syntax we don't intend to create, but accepting that I understand what you're trying to express it would end up creating: .unresponsive-desktop.touch .unresponsive-desktop .menu a

Paul d'Aoust

I think I understand... so in the two examples where I'm using @at-root, because I have a & in the argument, it would be exactly the same as if I hadn't used it at all, right? As for the syntax you don't intend to create, do you mean I can pass the un-inherited selector as an argument, or have it as a child of @at-root, but not both?

.parent {
    @at-root .not-child { // okay
        color: blue;
    }
}

or

.parent {
    @at-root {
        .not-child { // also okay
            color: blue;
    }
}

but not

.parent {
    @at-root .not-child {
        color: blue;
        .not-grandchild { // not okay, because we've got selectors as arguments and children
            color: green;
        }
    }
}

So I'm guessing that @at-root is not intended for use cases like mine, eh?

Chris Eppstein
Collaborator

@pdaoust Well, @at-root is what enables us to manipulate the value of & in SassScript. And in SassScript you could write a function like replace-primary-scope(&, ".unresponsive-desktop.touch")

yobssarG m'I

Execuse me? has this feature ( #{&} syntax) been available in
https://rubygems.org/gems/sass/versions/3.3.0.alpha.222 (sass 3.3.0.alpha.222) ?

Geremia Taglialatela

It Seem it isn't...

I also need this feature to convert less stuff like

.responsive-visibility() {
  display: block !important;
  tr& { display: table-row !important; }
  th&,
  td& { display: table-cell !important; }
}
Nathan Weizenbaum
Owner
nex3 commented August 09, 2013

This feature is still in development. It's not yet available on the master branch or alpha release.

Geremia Taglialatela tagliala referenced this issue in diowa/twbs_sass_rails August 13, 2013
Open

TODO #1

4 of 6 tasks complete
Paul d'Aoust

It seems to be in the master branch now, and available via gem install sass --pre as well. Looking good, and really useful for strange edge cases (which I seem to create a lot of in my day-to-day Sass writing), although I think there may be a couple bugs.

Geremia Taglialatela

@pdaoust glad to hear, I will take a look asap.

What is the syntax to achieve (in less)

.class {
  a& { color: red; }
}

?

Paul d'Aoust

That would be

.class {
    @at-root a#{&} { color: red; }
}

To give you

a.class { color: red; }

Keep in mind, though, that just like with Less, if you decide to nest it...

.wrapper {
    .class {
        @at-root a#{&} { color: red; }
    }
}

you'll get weird results:

a.wrapper .class { color: red; }
Chris Eppstein chriseppstein closed this October 11, 2013
Chris Eppstein
Collaborator

This landed on master recently.

Nathan Weizenbaum
Owner

This has been implemented; @at-root development will be tracked in #774.

Yurii Khmelvskii

@at-root + #{&} + many nested = ugly syntax! This syntax in Stylus is beautiful

sascha fuchs

Write a Mixin

@mixin c($name)
  @at-root
    #{&}--#{$name}
      @content

.myclass
  +c(child)
    height: 200px

Result
.myclass--child {
  height: 200px; }
Chris Eppstein
Collaborator

@khmelevskii Every language has it's own benefits and drawbacks. Ours works this way for very good reasons. You're welcome to use stylus if it is a better fit for your stylesheets.

Ivan
body {
    color: black;
    #{&}.red {
        color: red;
    }
    &.green {
        color: green;
    }
}

compiles to

body {
  color: black; }
  body body.red {
    color: red; }
  body.green {
    color: green; }

Using Sass 3.3.0.rc.1 (Maptastic Maple) on Windows

Paul d'Aoust

@joneff That looks like Sass is doing what it ought to; if this isn't what you expected, can you give us a sample of what you expected and we can steer you in the right direction with the new scriptable &?

Ivan

Reading trough the @chriseppstein 's comment (#286 (comment)), related to BEM implementation

.block{
    #{&}__element {
      // ...
    }
    #{&}--modifier {
      // ...
    }
}

I'd really expect both & and interpolated #{&} to work the same in this simplest of cases [and not to have duplication of the parent rule].

Actually it's the duplication of the parent rule that bothers me :)

Paul d'Aoust

Ah, I see. What happens is that #{&} takes the parent selector and treats it as a value, so you can almost (not quite, but almost) think of it as a variable that holds the value of the parent selector. It would be almost the same as writing:

body {
    $parent-selector: #{&};
    #{$parent-selector}.red {
        color: red;
    }
}

Now you can see that, because the parent selector is stored as a variable and interpolated into the child selector, it becomes part of the tree and the parent selector gets added to it. What you want to do is break out of the parent selector completely, like so:

body {
    @at-root #{&}.red {
        color: red;
    }
}

That'll produce

body.red {
    color: red;
}

I think that Chris' comment #286 was written before @at-root and the scripted & had been solidified. The syntax has changed since then.

(Note: As you already discovered, your example would be the same as writing

body {
    &.red {
        color: red;
    }
}

so you wouldn't be getting any benefit from scripted &, but I assume that your actual code is more complex than your example.)

Sergey

@chriseppstein Please take a look at following comment - #286 (comment) @FWeinb demonstrated that classes are not nested under parent class (that make sense, why would we bother adding parent to class which already have parent name as part of itself). Is there anything that can be done about it?

Sergey

Sorry, I lost attention, that answers my question

.block{
    color: #000;

    @at-root #{&}__element{
      border: 1px solid;
    }
    @at-root #{&}--modifier{
      background: #fff;
    }
}
Paul d'Aoust

@Serge-Z I thought I'd mention that support for this has been temporarily removed (see #1077) and will be added back in in Sass 3.4. So if you really need this (as I do) and don't mind some bloated output sometimes, stay with 3.3.0.rc2.

Nathan Weizenbaum
Owner

Actually, as per #1055, it's even easier to do this with Sass 3.3:

.block {
  color: #000;
  &__element {
    border: 1px solid;
  }
  &--modifier {
    background: #fff;
  }
}
Paul d'Aoust

@nex3 correct, after reading https://gist.github.com/nex3/8050187 I was just about to edit my response. Thanks for setting us both straight! :-)

nford nford referenced this issue in hcatlin/libsass January 23, 2014
Closed

Support for Sass 3.3's #{&} selector #269

Barney Carroll

I'm trying to qualify variations of the ancestor selector from within a nested chain.
Ideally, qualifying classes could be appended to the ancestor selector, but I don't believe this is yet possible with SASS – but by all accounts, I should be able to come up with the following using a half-way reasonable use of SASS nesting:

.delivery-option .icon {
  // Ancestor element styles 
}

.standard.delivery-option .icon {
  // Sprite 1
}

.unavailable.standard.delivery-option .icon {
  // Sprite 2
}

I've tried this:

.delivery-option {
  // Ancestor element styles 

  .icon {
    // Icon layout

    .standard& {
      // Sprite 1

      .unavailable& {
        // Sprite 2
      }
    }
  }
}

And I've also tried forcing interpolation with eg .standard#{&} and #{".standard"}#{&}.

I was using 3.3.0.rc.6, and just updated to 3.3.3. & is always a syntax error (most explicitly because "&" may only be used at the beginning of a compound selector.), any which way I try to achieve this. Has this regressed, or am I doing it wrong?

Chris Eppstein
Collaborator

@barneycarroll we removed script access to & for the 3.3 release. See https://gist.github.com/nex3/8050187 for more information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.