SCSS, how to #extend Nested ampersand "prefix"? - css

The nested ampersand prefix doesn't get expanded with #extend
.firstClass{
color: green;
&-a{
color: red;
}
}
.secondClass{
#extend .firstClass;
}
The expected output would be
.firstClass, .secondClass{
color: green;
}
.firstClass-a, .secondClass-a{
color: red;
}
But the actual output doesn't have the .secondClass-a at all.
.firstClass, .secondClass{
color: green;
}
.firstClass-a{
color: red;
}
I found this is an intended behavior to use #extend https://github.com/sass/sass/issues/2154
But is there a workaround that can extend nested ampersand prefix?

Maybe the versions I worked on were older but I don't believe it was possible. You could change your properties to a mixin as such:
#mixin classStyle {
color: green;
&-a{
color: red;
}
}
.firstClass {
#include classStyle;
}
.secondClass {
#include classStyle;
}

Related

How to declare two classes for element with scss

I have this scss code:
button.green{
background-color: $green;
.current {
color: $white;
}
}
I want to apply two classes to my button <button class="green current"></button> but my scss code just does not work. How would you fix that in a proper scss manner?
Also tried that with no luck:
button {
.green{
background-color: $green;
}
& .current {
color: $white;
}
}
Nearly correct, missing "&" in your nesting to connect button.green and .current.
The css output of your scss is:
button.green > .current
meaning, you style an element "current" within its parent "button.green".
Correct:
button.green{
background-color: $green;
&.current {
color: $white;
}
}
Which outputs:
button.green.current
.green.current {
background-color: $green;
color: $white;
}
This will apply both class!!

Why does SASS modify chained selectors of the same name when using extend?

Given the following HTML / SASS code:
<div class="a">hello</div>
%color {
color: blue;
}
.a {
color: red;
}
.a.a {
#extend %color;
}
I was expecting the resulting color to be blue (due to the more specific .a.a selector1) with output something like this:
.a.a {
color: blue;
}
.a {
color: red;
}
But actually, the resulting color is red, with SASS output:
.a {
color: blue;
}
.a {
color: red;
}
I find this quite counter-intuitive!
Why does SASS refactor my .a.a selector to .a?
Just in case you don't believe me, here's a codepen demo (click view compiled css to see the CSS output)
NOTE:
This 'refactoring' of the selector only occurs to the declarations within the extend.
So in the following SASS:
%color {
color: blue;
}
.a.a {
#extend %color;
position: relative;
}
The output is:
.a {
color: blue;
}
.a.a {
position: relative;
}
(Codepen demo)
1See the spec:
Note: Repeated occurrences of the same simple selector are allowed and
do increase specificity.
By the looks of it, the result depends on the parsing engine. If you use DartSass v1.6.2 (default on sassmeister.com), it outputs your expected result:
.a.a {
color: blue;
}
.a {
color: red;
}
Check on sassmeister.com (you can also switch parsing engines there).
LibSass v3.5.2 creates the result you complained about:
.a {
color: blue;
}
.a {
color: red;
}

How do I render duplicate classes using the amerpsand operator in scss?

I am trying to generate a double class using scss for specifity reasons and avoiding the usage of the dreaded !important
I have tried the following example:
.my-class {
color: black;
&.&:hover {
color: red;
}
}
But all I'm getting is:
Error: Invalid CSS after "... of parent rule": expected "}", was "&.&:hover {"
With reference to your answer, the ampersand can be interpolated as well:
.my-class {
color: black;
&#{&}:hover {
color: red;
}
}
outputs
.my-class {
color: black;
}
.my-class.my-class:hover {
color: red;
}

How to extend in scss from parent (in case of BEVM)

I try to understand BEVM+SCSS philosophy.
I don't know how to extend V from BE in this case.
What I want to achieve:
.block {
&__element {
background-color: black;
&--variation-a {
#extend &__element; //won't work
color: red;
}
&--variation-b {
#extend &__element; //won't work
color: green;
}
}
}
What I want to avoid:
.block {
&__element {
background-color: black;
&--variation-a {
#extend .block__element; //work but ugly
color: red;
}
&--variation-b {
#extend .block__element; //work but ugly
color: green;
}
}
}
The only way I've found it's to have a kind of %element { ... } aside and extends from it, but it's not exactly what I want.
You can use variables. $b to store block name and $e to store element name.
Sassmeister demo.
.block {
$b: &;
&__element {
$e: #{$b}__element;
background-color: black;
&--variation-a {
#extend #{$e};
color: red;
}
&--variation-b {
#extend #{$e};
color: green;
}
}
}
But it's bad practice to nest element styles by modifier. Modifier must only override styles.

Sass #extend base/default without also extending pseudo-classes?

I know I can #extend .foo:hover, but is there a way to #extend the .foobar base/default properties without also extending the definitions for pseudo-classes like :hover, :active, etc?
For example, how would I change the following such that .foobar extends only .foo's default state?
.foo {
& {
color:blue;
}
&:hover {
background-color: black;
}
}
.foobar {
#extend .foo;
&:hover {
//As is, I have to override. Any better way?
background-color: transparent;
}
}
(If there is no way to do this with Sass, is there a preferred way to achieve the same effect?)
You have to rewrite your selectors in such a way that you only extend exactly the part you want:
%foo {
color:blue;
}
.foo {
#extend %foo;
&:hover {
background-color: black;
}
}
.foobar {
#extend %foo;
&:hover {
background-color: transparent;
}
}
However, depending on how you are going to be extending/reusing your .foo class, the new #content directive might be the better way to go.
#mixin foo {
color: blue;
&:hover {
#content;
}
}
.foo {
#include foo {
background-color: black;
}
}
.foobar {
#include foo {
background-color: transparent;
}
}

Resources