Extending a Nested Placeholder in SCSS - css

Is it possible to #extend a SCSS placeholder with nesting, and have that nesting reflected in the resulting class?
Given a nested placeholder:
%my-form-field {
...
&__label {
...
}
&__feedback {
...
}
}
I currently have to do the following:
.one-of-many-targets {
#extend %my-form-field;
&__label {
#extend %my-form-field__label;
}
&__feedback {
#extend %my-form-field__feedback;
}
}
But I'd like to be able to simplify this to:
.one-of-many-targets {
#extend %my-form-field;
}
... and have it resolve to:
.one-of-many-targets { ... }
.one-of-many-targets__label { ... }
.one-of-many-targets__feedback { ... }
Is there a different way to write my placeholder and #extends to make the SCSS cleaner, as in the 2nd example?

You can use a mixin instead:
#mixin my-form-field() {
width: 10px;
&__label {
width: 20px;
}
&__feedback {
width: 30px;
}
}
.one-of-many-targets {
#include my-form-field();
}
will generate:
.one-of-many-targets {
width: 10px;
}
.one-of-many-targets__label {
width: 20px;
}
.one-of-many-targets__feedback {
width: 30px;
}

You could try use selector.append()
See: https://github.com/sass/sass/issues/2808#issuecomment-574413393
Also see more info why parent selector didn't work as you expect in extend-only selectors: https://github.com/sass/sass/issues/2262#issuecomment-291645428

Related

Nested selectors using Sass

How can I have this output using Sass?
.class.active .class-name1 {}
.class.active .class-name2 {}
Here is what I tried :
.class {
&.avtive {
&-name1 {
}
&-name2 {
}
}
}
You need to keep a reference to the outer class name, and interpolate it for your -name classes. Using color: red as an example of the style to apply:
.class {
$outer-class: &;
&.active {
#{$outer-class}-name1 {
color: red;
}
#{$outer-class}-name2 {
color: red;
}
}
}

Syntax for if/else condition in SCSS mixins

I created a SASS #mixin which contains #if conditions to assign styling to elements based on their z-index property to create some sort of elevation.
However what ever I am trying it will not work out.
I'm pretty sure I am doing something just slightly wrong that affects everything else.
I'd appreciate your feedback. Thanks in advance!
$background: #121212;
$surface: #1f1f1f;
$surface-shade_1: #282828;
$surface-shade_2: #303030;
%surface {
background-color: $surface;
}
%surface-shade_1 {
background-color: $surface-shade_1;
}
%surface-shade_2 {
background-color: $surface-shade_2;
}
#mixin elevation($elevationValue) {
#if $elevationValue>0 {
#extend %surface;
}
#else if $elevationValue>4 or $elevationValue=4 {
#extend %surface-shade_1;
}
#else if $elevationValue>8 or $elevationValue=8 {
#extend %surface-shade_2;
}
z-index: $elevationValue * 50;
}
nav {
#mixin elevation(4);
}
If you want to use #mixin inside the CSS files you can use like #include mixin-name and also use directly $elevationValue >= 4 instead of $elevationValue>4 or $elevationValue=4 it becomes much cleaner.
$background: #121212;
$surface: #1f1f1f;
$surface-shade_1: #282828;
$surface-shade_2: #303030;
%surface {
background-color: $surface;
}
%surface-shade_1 {
background-color: $surface-shade_1;
}
%surface-shade_2 {
background-color: $surface-shade_2;
}
#mixin elevation($elevationValue) {
#if $elevationValue > 0 {
#extend %surface;
}
#else if $elevationValue >= 4 {
#extend %surface-shade_1;
}
#else if $elevationValue >= 8 {
#extend %surface-shade_2;
}
z-index: $elevationValue * 50;
}
nav {
#include elevation(4);
}

sass prepend root class to current selector

I am having trouble prepending the root class to my current selector in sass. I have the following code:
.cta-two-columns {
&__text-holder {
#at-root&#{__inner} {
// also tried #at-root __inner&{#}
// and many others like #at-root__inner
padding: rem(25px);
}
}
}
but this gives me the following:
.cta-two-columns__text-holder__inner {
padding: rem(25px);
}
I don't understand the above - what's the point of at-root as you may as well just do &__inneras it gave me the same as the two things I have shown I tried
how do I get
.cta-two-columns__text-holder .cta-two-columns__inner {
}
without having to resort to
.cta-two-columns {
&__text-holder {
.cta-two-columns__inner {
padding: rem(25px);
}
}
}
Or is this the only way to do it in sass?
#at-root doesn't really work like you may think in this case. #at-root will simply make the declaration outside the nest. To better understand, add another CSS declaration like below:
.cta-two-columns {
&__text-holder {
margin: 10px;
#at-root&#{__inner} {
padding: rem(25px);
}
}
}
This will produce the following CSS code:
.cta-two-columns__text-holder {
margin: 10px;
}
.cta-two-columns__text-holder__inner {
padding: rem(25px);
}
Simply imagine how the selector will be created without #at-root then make it outside.
Without it will produce this:
.cta-two-columns__text-holder {
margin: 10px;
}
.cta-two-columns__text-holder .cta-two-columns__text-holder__inner {
padding: rem(25px);
}
Then we simply omit .cta-two-columns__text-holder.
One idea to obtain what you want is to consider a variable where you can declare the main class then you will be able to nest as many element as you want:
$sel: '.cta-two-columns';
#{$sel}__text-holder {
#{$sel}__inner {
padding: rem(25px);
}
}
Will produce:
.cta-two-columns__text-holder .cta-two-columns__inner {
padding: rem(25px);
}
with more nested elements:
$sel: '.cta-two-columns';
#{$sel}__text-holder {
#{$sel}__outer {
#{$sel}__inner{
#{$sel}__wrap{
padding: rem(25px);
}
}
}
}
Will produce
.cta-two-columns__text-holder .cta-two-columns__outer .cta-two-columns__inner .cta-two-columns__wrap {
padding: rem(25px);
}

Can I add a variable to a mixin function name in Less?

Is this possible to do in some way I don't know? I'm trying to add a variable in the mixin function name.
#mybar: Test;
.mymixin() {
padding: 10px;
}
.mymixin#{mybar}() {
padding: 10px;
}
.test {
.mymixinTest();
}
I think it should work if you do:
.myMixin(#myvar) {
.myMixin#{myvar} {
//your css
}
}

Simplifying sass attribute selectors

I'm trying to come up with a way to simplify some SCSS attribute selectors. What I end up with is:
[data-attr="opt1"] { ... }
[data-attr="opt2"] { ... }
[data-attr="opt3"] { ... }
What I'm hoping for is to be able to write something closer to:
[data-attr]
&="opt1" { ... }
&="opt2" { ... }
&="opt3" { ... }
via a mixin, or whatever. Can't come up with a solution though. Any clever ideas?
I've come to this idea:
#mixin attrVal($value) {
$attr: str-slice(#{&}, 2, -2); // $attr = "data-attr"
#at-root {
[#{$attr}="#{$value}"] {
#content;
}
}
}
[data-attr] {
#include attrVal('opt1') { width: 10px; }
#include attrVal('opt2') { width: 20px; }
#include attrVal('opt3') { width: 30px; }
}
Output (tested on sassmeister.com)
[data-attr="opt1"] { width: 10px; }
[data-attr="opt2"] { width: 20px; }
[data-attr="opt3"] { width: 30px; }
For this specific example there's no that huge simplification, but with this approach you're actually decoupling the attribute name from its value (in the aim of code reuse).

Resources