Using wildcard as a value - css

Is there a way to use wildcard to write all these twenty rules as one:
.margin-bottom-1rem {
margin-bottom: 1rem;
}
.margin-bottom-2rem {
margin-bottom: 2rem;
}
...
.margin-bottom-20rem {
margin-bottom: 20rem;
}
I found many resources about capturing all the class names, but none about using a part of the captured name as a value. If this is not possible with wildcards, is there another workaround to avoid these duplicated rules?

SCSS
$sizes: 1rem, 2rem, 5rem, 10rem, 20rem;
#each $size in $sizes {
.margin-bottom-#{$size} {
margin-bottom: $size;
}
}
SASS
$sizes: 1rem, 2rem, 5rem, 10rem, 20rem
#each $size in $sizes
.margin-bottom-#{$size}
margin-bottom: $size
Both produce this:
.margin-bottom-1rem {
margin-bottom: 1rem;
}
.margin-bottom-2rem {
margin-bottom: 2rem;
}
.margin-bottom-5rem {
margin-bottom: 5rem;
}
.margin-bottom-10rem {
margin-bottom: 10rem;
}
.margin-bottom-20rem {
margin-bottom: 20rem;
}
Do something for every element
https://sass-lang.com/documentation/values/lists#do-something-for-every-element

Related

Consuming Less Vars in a generating for loop

I'm trying to use a loop to generate the relevant CSS using defined Less vars. However I'm struggling as I'm slowly getting used to Less after years with scss and could use another pair of eyes since I can't seem to find a fitting example.
So say you have Less like this (except in reality my less vars are in a separate file and imported via #import before the loop);
#spacing-xsmall: .25rem; // 4px
#spacing-small: .5rem; // 8px
#spacing-medium: 1rem; // 16px
#spacing-medium-large: 1.5rem; // 24px
#spacing-large: 2rem; // 32px
#spacing-xlarge: 2.5rem; // 40px
#spacing-xxlarge: 4rem; // 64px
#sizes: xsmall, small, medium, medium-large, large, xlarge, xxlarge;
.init-spacing(#i) when (#i > 0) {
#size: extract(#sizes, #i);
#space: ~"#spacing-#{size}";
.margin-#{size} { margin: #space }
.padding-#{size} { padding: #space; }
.init-spacing(#i - 1);
}
.init-spacing(length(#sizes));
This produces output like this;
.margin-xxlarge {
margin: #spacing-xxlarge;
}
.padding-xxlarge {
padding: #spacing-xxlarge;
}
....
Except obviously in the CSS output I would want the variable VALUE instead so the output would be like;
.margin-xxlarge {
margin: 4rem;
}
.padding-xxlarge {
padding: 4rem;
}
....
How can I accomplish this with Less? I know the string interpolation is a likely culprit but am a bit stuck in the docs as it were.
Here's a Codepen to tinker with for a reproducible example of the issue.
I tried this answer but the output just returns like .class { margin: [object, object] } along with a couple other similar I found but can't seem to get my scenario covered where I loop an array like I want to do since my existing variables may not be just an easy index number, and I think that's part of where I'm falling short in a Parametric mixin that would work here. I'm just searching for the nuance I'm missing here to generate the results intended in a rather generic way so I can apply it in other similar instances.
Why not use variable variables ?
#spacing-xsmall: .25rem; // 4px
#spacing-small: .5rem; // 8px
#spacing-medium: 1rem; // 16px
#spacing-medium-large: 1.5rem; // 24px
#spacing-large: 2rem; // 32px
#spacing-xlarge: 2.5rem; // 40px
#spacing-xxlarge: 4rem; // 64px
#sizes: xsmall, small, medium, medium-large, large, xlarge, xxlarge;
.init-spacing(#i) when (#i > 0) {
#size: extract(#sizes, #i);
#space: ~"spacing-#{size}";
.margin-#{size} { margin: ##space }
.padding-#{size} { padding: ##space; }
.init-spacing(#i - 1);
}
.init-spacing(length(#sizes));
I got (with a preview)
.margin-xxlarge {
margin: 4rem;
}
.padding-xxlarge {
padding: 4rem;
}
.margin-xlarge {
margin: 2.5rem;
}
.padding-xlarge {
padding: 2.5rem;
}
.margin-large {
margin: 2rem;
}
.padding-large {
padding: 2rem;
}
.margin-medium-large {
margin: 1.5rem;
}
.padding-medium-large {
padding: 1.5rem;
}
.margin-medium {
margin: 1rem;
}
.padding-medium {
padding: 1rem;
}
.margin-small {
margin: 0.5rem;
}
.padding-small {
padding: 0.5rem;
}
.margin-xsmall {
margin: 0.25rem;
}
.padding-xsmall {
padding: 0.25rem;
}

How to inject literal string into scss #mixin

Considering this following scss code:
#mixin homeSlider(
$dim: 150px,
$h1: "h1 { font-size: 4em; margin-top: 0; }"
){
section {
margin-top: -$dim;
}
$h1;
}
#include homeSlider( $dim: 50px, $h1: "h1 { font-size: 3em; margin-top: 0; }" )
I need to know how is it possible to achieve my goal
Try this
#mixin homeSlider($dim, $h1-font-size){
section {
margin-top: -$dim;
h1 {
font-size: $h1-font-size;
margin-top: 0;
}
}
}
#include homeSlider(50px, 3em;) /* $dim = 50px - $h1-font-size = 3em; */

How to overwrite Referencing Parent Selector using Mixin in SCSS

I had a common used component and its scss is like this:
.component {
margin-right: 12px;
&.specified-use-case {
margin-right: 30px;
&:nth-child(odd) {
margin-right: 70px
}
}
}
Now I want everything has same style in mobile view
.component {
margin-right: 12px;
// some predefined mixin
#include viewport(mobile) {
margin-right: 0px;
margin-bottom: 14px;
}
&.specified-use-case {
margin-right: 30px;
&:nth-child(odd) {
margin-right: 70px
}
}
}
But this can't change style for "specified-use-case" in mobile view. In order to do it I have to
.component {
margin-right: 12px;
// some predefined mixin
#include viewport(mobile) {
margin-right: 0px;
margin-bottom: 14px;
}
&.specified-use-case {
margin-right: 30px;
#include viewport(mobile) {
margin-right: 0px;
margin-bottom: 14px;
}
&:nth-child(odd) {
margin-right: 70px
#include viewport(mobile) {
margin-right: 0px;
margin-bottom: 14px;
}
}
}
}
Which just doesn't seem right to me. Is there a better way to define mobile view css just for once?
According to CSS' specificity rules (try this calculator) you unfortunately need to repeat yourself. What your SCSS interpreter does is just compiling what you've written to standard CSS, which will look something akin to:
.component {
margin-right:12px
}
#media (max-width:768px) {
.component {
margin-right:0px;
margin-bottom:14px
}
}
.component.specified-use-case {
margin-right:30px
}
#media (max-width:768px) {
.component.specified-use-case {
margin-right:0px;
margin-bottom:14px
}
}
.component.specified-use-case:nth-child(odd) {
margin-right:70px
}
#media (max-width:768px) {
.component.specified-use-case:nth-child(odd) {
margin-right:0px;
margin-bottom:14px
}
}
As you can see, you're overriding each class with a #media ruleset just after it has been declared. And since I'm a big proponent to never use !important (because you'll open a pandoras box), the only way you can shorten your SCSS is doing:
.component {
margin-right: 12px;
// some predefined mixin
#include viewport(mobile) {
margin-right: 0px;
margin-bottom: 14px; // only need to define margin-bottom once, here.
}
&.specified-use-case {
margin-right: 30px;
#include viewport(mobile) {
margin-right: 0px;
//margin-bottom: 14px;, remove this
}
&:nth-child(odd) {
margin-right: 70px
#include viewport(mobile) {
margin-right: 0px;
//margin-bottom: 14px;, remove this
}
}
}
}
Hope this helps!
You can put the rules inside of the media query:
#include viewport(mobile) {
margin-right: 0px;
margin-bottom: 14px;
&.specified-use-case {
margin-right: 0px;
margin-bottom: 14px;
}
}
seems like sass is wrong because you specify margins above a breakpoint, try this:
.component {
margin-right: 12px;
&.specified-use-case {
margin-right: 30px;
&:nth-child(odd) {
margin-right: 70px
}
}
// some predefined mixin
#include viewport(mobile) {
margin-right: 0px;
margin-bottom: 14px;
}
}

Dynamic margin/padding with sass

Is it possible to simplify and make this more easily maintained with sass?
.padding-8 { padding: 8px !important; }
.padding-10 { padding: 10px !important; }
.padding-top-0 { padding-top: 0 !important; }
.padding-top-3 { padding-top: 3px !important; }
.padding-bottom-0 { padding-bottom: 0 !important; }
.padding-bottom-3 { padding-bottom: 3px !important; }
.padding-bottom-5 { padding-bottom: 5px !important; }
.margin-top-0 { margin-top: 0 !important; }
.margin-top-5 { margin-top: 5px !important; }
.margin-bottom-0 { margin-bottom: 0 !important; }
.margin-bottom-5 { margin-bottom: 5px !important; }
etc..
Is it also possible to write something like .padding-$dir-$value { padding-$dir: $value px !important; } so you can use a class with f.ex padding-left-13?
Make two maps with the properties you want to mix.
For each combination create a placeholder class. I think it's appropiate if you don't want to create a full list of classes that maybe you won't use. This is the modular-friendly use.
Extend the class in your element.
$paddingDirection:('right','left','top','bottom');
$paddingLength:(15,30,45,50);
#each $dir in $paddingDirection{
#each $len in $paddingLength{
%padding-#{$dir}-#{$len}{ padding-#{$dir}: #{$len}px;}
}
}
.any-class{
#extend %padding-right-30;
}
/*output*/
.any-class {
padding-right: 30px;
}
Original answer here
you can use this: (enhanced the above solution)
$paddingDirection:('right','left','top','bottom');
$paddingLength:(15,30,45,50);
// if you only wants to use "padding" without postfix
#each $len in $paddingLength {
.padding-#{$len} { padding: #{$len}px;}
}
// if you want to use padding-left, padding-right etc.
#each $dir in $paddingDirection {
#each $len in $paddingLength {
.padding-#{$dir}-#{$len} { padding-#{$dir}: #{$len}px;}
}
}
usage:
<div class="padding-15"></div>
<div class="padding-left-15 padding-top-15"></div>

how to get the direct parent in sass interpolation of &

Is there a way to use {$} to get the most direct parent?
In the example below '&#{&}' is not working as I expected, I managed to work around it using mixin.
#mixin modifier($modifier, $block: &) {
&#{"."+$block}--#{$modifier} {
#content;
}
}
.namespace{
$button : 'btn';
.#{$button} {
line-height: 1;
#include modifier('big', $button){ // working but not clean
padding-top: 8px;
}
&#{&}--big{ // not working as {&} is interpolated to namespace .btn
padding-top: 12px;
}
}
}
Compiled to:
.namespace .btn {
line-height: 1;
}
.namespace .btn.btn--big {
padding-top: 8px;
}
.namespace .btn.namespace .btn--big {
padding-top: 12px;
}
The construct looks a bit odd to me – but you could do it like:
.namespace {
$class: ".btn";
#{$class} { line-height: 1; }
#{$class}#{$class}--big { padding-top: 8px; }
& #{$class}#{&} #{$class}--big { padding-top: 12px; }
}
...or using selector append
.namespace .btn {
line-height: 1;
#at-root {
#{selector-append(&,".btn")}--big{ padding-top: 8px; }
#{selector-append(&,&)}--big{ padding-top: 12px; }
}
}
both compiling to:
.namespace .btn { line-height: 1; }
.namespace .btn.btn--big { padding-top: 8px; }
.namespace .btn.namespace .btn--big { padding-top: 12px; }

Resources