Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compound selectors and @extend behavior change since 3.2.7 #878

Closed
ghost opened this issue Aug 1, 2013 · 6 comments
Closed

Compound selectors and @extend behavior change since 3.2.7 #878

ghost opened this issue Aug 1, 2013 · 6 comments
Labels
bug Something isn't working

Comments

@ghost
Copy link

ghost commented Aug 1, 2013

This worked on 3.2.7, but since 3.2.8 through 3.2.10, it behaves differently. ( I didn't actually test 3.2.9 )

@mixin alpha { alpha: "hello"; }
%alpha { @include alpha; }

@mixin omega {
    &:after {
        @extend %alpha;
        omega: "world";
    }
}
%omega { @include omega; }

.alpha-omega-1 {
    @extend %alpha;
    @extend %omega;
}
.alpha-omega-2 {
    @extend %alpha;
    @extend %omega;
}

The expected result is:

.alpha-omega-1, .alpha-omega-2, 
.alpha-omega-1:after, .alpha-omega-2:after { alpha: "hello"; }

.alpha-omega-1:after, .alpha-omega-2:after { omega: "world"; }

But the actual result is:

.alpha-omega-1, .alpha-omega-2 { alpha: "hello"; }

.alpha-omega-1:after, .alpha-omega-2:after { omega: "world"; }

Note that the :after selectors aren't extended to include the alpha: "hello"; property. Of course, I could just @include alpha in the omega @mixin, however that changes the grouping; and besides, this should work so far as I can tell.

I don't know what your position is on the correct behavior here, so perhaps this is behaving expectedly, but I can't imagine that it is.

Just to clarify, the reason for both the @mixin and %rule is I use the %rule in the current media scope, and redefine it using the @mixin in different media scopes.

@chriseppstein
Copy link

This is a real bug. The mixins are not required to reproduce it:

%alpha { alpha: "hello"; }

%omega:after { 
        @extend %alpha;
        omega: "world";
}

.alpha-omega-1 {
    @extend %alpha;
    @extend %omega;
}
.alpha-omega-2 {
    @extend %alpha;
    @extend %omega;
}

Produces:

.alpha-omega-1, .alpha-omega-2 {
  alpha: "hello"; }

.alpha-omega-1:after, .alpha-omega-2:after {
  omega: "world"; }

But should produce:

.alpha-omega-1, .alpha-omega-2, 
.alpha-omega-1:after, .alpha-omega-2:after { alpha: "hello"; }

.alpha-omega-1:after, .alpha-omega-2:after { omega: "world"; }

Note that

%alpha { alpha: "hello"; }

%omega a { 
        @extend %alpha;
        omega: "world";
}

.alpha-omega-1 {
    @extend %alpha;
    @extend %omega;
}
.alpha-omega-2 {
    @extend %alpha;
    @extend %omega;
}

produces

.alpha-omega-1 a, .alpha-omega-2 a, .alpha-omega-1, .alpha-omega-2 {
  alpha: "hello"; }

.alpha-omega-1 a, .alpha-omega-2 a {
  omega: "world"; }

as expected. But even a class attached to the main placeholder is failing:

%alpha { alpha: "hello"; }

%omega.foo { 
        @extend %alpha;
        omega: "world";
}

.alpha-omega-1 {
    @extend %alpha;
    @extend %omega;
}
.alpha-omega-2 {
    @extend %alpha;
    @extend %omega;
}

@ghost
Copy link
Author

ghost commented Aug 1, 2013

Ah, I see. I didn't thoroughly test it ( without the @mixin ) and got onto other things.

So the core of the issue is compound selectors ( pseudo-classes, actual classes ) not extending properly. I'll edit the issue slightly to correct it.

@nex3
Copy link
Contributor

nex3 commented Aug 3, 2013

This is a weird case. In general, it would be correct to remove the pseudo-selector in this case -- .alpha-omega-1:hover, for example, is a sub-selector of .alpha-omega-1. Since .alpha-omega-1 has specificity as high as any of its source selectors, it satisfies the second law of extend and .alpha-omega-1:hover can safely be removed.

Where it starts to get weird is that :after isn't really a pseudo-class, it's a pseudo-element. Pseudo-elements select for completely different elements than whatever selector they're attached to. Currently there's a bug in Sass's sub-selector calculations where it doesn't treat pseudo-classes correctly. That needs to be fixed.

It gets even weirder, though. Although :after is a pseudo-element, it has only one colon, so it looks like a pseudo-class. In recent specs, it's been changed to ::after, but the old version is still valid. So in addition to correctly supporting pseudo-elements, Sass needs to know that some selectors that use the pseduo-class syntax (:before, :after, :first-line, and :first-letter) are actually pseudo-elements and should be treated as such.

@ghost
Copy link
Author

ghost commented Aug 3, 2013

I see, so once the bug is fixed, in addition to parsing ::[a-z-]+ as pseudo-elements to correctly apply specificity, you'll need to make special cases for :(before|after|first-line|first-letter).

While I can understand your desire to maintain compatibility to the spec ( and it's own backwards compatibility ), in the interest of simplicity perhaps only allowing ::[a-z-]+ to be parsed as pseudo-elements would be acceptable. It's only my opinion of course, but I would be perfectly fine with that. Not to mention, it's a mild visual indicator and something that can be treated differently by syntax highlighters.

@nex3
Copy link
Contributor

nex3 commented Aug 3, 2013

It's not too difficult to add special cases for the backwards-compatible selectors.

@ghost
Copy link
Author

ghost commented Aug 3, 2013

Cool beans 👍 just wanted to mention; you guys are doing an awesome job. I haven't worked with Ruby much, but I'm working on changing that. Looking forward to helping the cause in the future :-)

@nex3 nex3 closed this as completed in 004b1bd Aug 6, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants