SASS check if current loop contains part of input - sass

I have an array called $ratings-list that I'm trying too loop through and if the $current-class contains .5 then to use a a segment of css otherwise use a different segment;
$ratings-list: 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5;
#each $current-class in $ratings-list {
$i: index($ratings-list, $current-class);
&[data-rating="#{$current-class}"] {
#if (index($current-class, .5)) {
.rating-stars__star:nth-child(-n+#{floor($current-class)}) .ratings-star {
height: floor($current-class);
}
} #else {
.rating-stars__star:nth-child(-n+#{$i}) .ratings-star {
height: 7px;
}
}
}
}
The above always returns the else height: 7px segment.

You could turn $current-class into a string and use str-index instead.
$ratings-list: 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5;
#each $current-class in $ratings-list {
$i: index($ratings-list, $current-class);
[data-rating="#{$current-class}"] {
#if (str-index(#{"" + $current-class}, '.5')) {
.rating-stars__star:nth-child(-n+#{floor($current-class)}) .ratings-star {
height: floor($current-class);
}
} #else {
.rating-stars__star:nth-child(-n+#{$i}) .ratings-star {
height: 7px;
}
}
}
}
Compiles to
[data-rating="1"] .rating-stars__star:nth-child(-n+1) .ratings-star {
height: 7px;
}
[data-rating="1.5"] .rating-stars__star:nth-child(-n+1) .ratings-star {
height: 1;
}
[data-rating="2"] .rating-stars__star:nth-child(-n+3) .ratings-star {
height: 7px;
}
[data-rating="2.5"] .rating-stars__star:nth-child(-n+2) .ratings-star {
height: 2;
}
[data-rating="3"] .rating-stars__star:nth-child(-n+5) .ratings-star {
height: 7px;
}
[data-rating="3.5"] .rating-stars__star:nth-child(-n+3) .ratings-star {
height: 3;
}
[data-rating="4"] .rating-stars__star:nth-child(-n+7) .ratings-star {
height: 7px;
}
[data-rating="4.5"] .rating-stars__star:nth-child(-n+4) .ratings-star {
height: 4;
}
[data-rating="5"] .rating-stars__star:nth-child(-n+9) .ratings-star {
height: 7px;
}

Related

Dynamic Class Generation With Sass

I want to create my own bootsrap with flexbox.It is something like this:
.df {
display: flex;
}
.aic {
align-items: center;
}
.jcc {
justify-content: center;
}
.jcsb {
justify-content: space-between;
}
.fdc {
flex-direction: column;
}
.fx1 {
flex: 1;
}
But there is also one thing I would like to realize,that's dynamic classes for margins and paddings and etc.Something like:
.mr-40 {
margin-right: 40;
}
So i want to this value (40) to be dynamic (1,5,100 and so on).Is there a way to realize this in SCSS/SASS?
This is just a quick implementation:
#use "sass:map";
$utils: (
"padding": (
"className": p,
"property": padding,
"values": 0 10 20 30 40 50 60 70 90 100,
),
"margin": (
"className": m,
"property": padding,
"values": 0 10 20 30 40 50 60 70 90 100,
),
);
#each $key, $values in $utils {
#each $cValue in map.get($values, "values") {
.#{map.get($values, "className")}-#{$cValue} {
#{map.get($values, "property")}: $cValue + "px";
}
}
}
.p-0 {
padding: "0px";
}
.p-10 {
padding: "10px";
}
.p-20 {
padding: "20px";
}
// ...
.m-0 {
padding: "0px";
}
// ...

How to pass multiple content blocks as arguments to a mixin?

I wanna be able to do something like so:
.myTransitionableElement {
transition: all .5s;
.subChild { transition: all 1s }
#include transitionKeyframes(
start: {
opacity: 0;
transform: tranlsate(50px);
.subChild {
transform: rotate(45deg);
}
},
end: {
opacity: 1;
transform: tranlsate(0);
.subChild {
transform: rotate(0);
}
}
)
}
#mixin transitionKeyframes($args) {
&.transitionStartKeyframe {
#include map_get($args, "start");
}
&.transitionEndKeyframe {
#include map_get($args, "end");
}
}
Which should at the end be equivalent to:
.myTransitionableElement {
transition: all .5s;
.subChild { transition: all 1s }
&.transitionStartKeyframe {
opacity: 0;
transform: tranlsate(50px);
.subChild {
transform: rotate(45deg);
}
}
&.transitionEndKeyframe {
opacity: 1;
transform: tranlsate(0);
.subChild {
transform: rotate(0);
}
}
}
The reason behind this is that I wanna find a way to not have to remember those classes names every time I use a JS abstraction that uses those classes.
You can't pass different content as arguments in SASS mixins.
Below is example of what you can achieve using SASS.
Can you specify what you want to achieve here?
#mixin rtl() {
&.ltr {
#content;
direction: ltr;
}
&.rtl {
#content;
direction: rtl;
}
}
.parent {
#include rtl {
display: flex;
}
}
You can try different approaches here. In this particular one I'm using map to hold the data for me. But if attributes and class names are fixed; you can even simplify it.
$map: (Start: (self: (opacity: '0', transform: 'tranlsate(50px)'), child: (transform: rotate(45deg))), End: (self: (opacity: '1', transform: 'tranlsate(0)'), child: (transform: rotate(0))));
$prefix: transition; $postfix: Keyframe;
#mixin transitionKeyframes($map) {
#each $key, $val in $map {
&.#{$prefix}#{$key}#{$postfix} {
#each $attr, $prop in map-get($val, self) {
#{$attr}: #{$prop};
}
.subChild {
#each $attr, $prop in map-get($val, child) {
#{$attr}: #{$prop};
}
}
}
}
}
.myTransitionableElement {
#include transitionKeyframes($map);
transition: all .5s;
.subChild { transition: all 1s }
}
Use mixins for a repetitive task. Modify the mixin or $frames if you have many variations. Breakdown opacity and transistion further to smaller mixins and invoke them conditionally.
$prefix: transition; $postfix: Keyframe;
$frames: 'Start', 'End';
$opcity-main: ('Start': 0, 'End': 1);
$translate-main: ('Start': 50, 'End': 0);
#mixin transitionKeyframes($frame) {
#each $key in $frame {
&.#{$prefix}#{$key}#{$postfix} {
$opacity: map-get($opcity-main, $key);
$translate: map-get($translate-main, $key);
opacity: $opacity;
transform: tranlsate($translate + px);
}
}
}
.myTransitionableElement {
#include transitionKeyframes($frames);
transition: all .5s;
.subChild { transition: all 1s }
}

How to dynamically generate classes in SCSS from array?

I have array of classes
$templates: (
'one',
'two',
'three'
);
And I want to generate next code
input[type="radio"][id="one"]:checked {
& ~ .two,
& ~ .three {
width: 0;
height: 0;
}
}
input[type="radio"][id="two"]:checked {
& ~ .one,
& ~ .three {
width: 0;
height: 0;
}
}
input[type="radio"][id="three"]:checked {
& ~ .one,
& ~ .two {
width: 0;
height: 0;
}
}
What is the best way to do it?
Now I have next code
#mixin somemixinname {
width:0;
height:0;
}
#each $class1 in $templates {
input[type="radio"][id="#{$class1}"]:checked {
#each $class2 in $templates {
#if $class2 != $class1 {
& ~ .#{$class2} { #include somemixinname }
}
}
}
}
But It generates a bit different code(

SASS multiple increment values in #for statement

I have a loop that generates number from 0-5, but would like it to also generate up to 20, but in multiples of 5.
Desired results would be:
0, 1, 2, 3, 4, 5, 10, 15, 20
Is this possible in a single #for statement?
#for $i from 0 through 20 {
#if $i < 5 and $i > 0 {
.number-#{$i} {
height:(#{$i}px);
}
}
#if $i % 5 == 0 {
.number-#{$i} {
height:(#{$i}px);
}
}
}
The output would be
.number-0 {
height: 0px;
}
.number-1 {
height: 1px;
}
.number-2 {
height: 2px;
}
.number-3 {
height: 3px;
}
.number-4 {
height: 4px;
}
.number-5 {
height: 5px;
}
.number-10 {
height: 10px;
}
.number-15 {
height: 15px;
}
.number-20 {
height: 20px;
}
The for loop will go through 0 to 20. The I check 1-5 through the first if statement, the using modulus I I check divisible by 5.

Grouping classes with similar rules in SASS

I'm using the following algorithm to create column classes in SASS:
$columns: 8;
$exclude-columns: 5 7;
#for $i from 1 through $columns {
#for $j from 1 through $i {
$width: (100% / $i) * $j;
#if $i != $j and index($exclude-columns, $i) {
.layout-unit-#{$j}of#{$i} {
width: $width;
}
}
}
}
It's working fine, however, the output has quite a bit of duplication:
.layout-unit-1of2 { width: 50%; }
.layout-unit-1of3 { width: 33.33333%; }
.layout-unit-2of3 { width: 66.66667%; }
.layout-unit-1of4 { width: 25%; }
.layout-unit-2of4 { width: 50%; }
.layout-unit-3of4 { width: 75%; }
.layout-unit-1of6 { width: 16.66667%; }
.layout-unit-2of6 { width: 33.33333%; }
.layout-unit-3of6 { width: 50%; }
.layout-unit-4of6 { width: 66.66667%; }
.layout-unit-5of6 { width: 83.33333%; }
.layout-unit-1of8 { width: 12.5%; }
.layout-unit-2of8 { width: 25%; }
.layout-unit-3of8 { width: 37.5%; }
.layout-unit-4of8 { width: 50%; }
.layout-unit-5of8 { width: 62.5%; }
.layout-unit-6of8 { width: 75%; }
.layout-unit-7of8 { width: 87.5%; }
Is there a way to get the output to look more like this:
.layout-unit-1of2,
.layout-unit-2of4,
.layout-unit-3of6,
.layout-unit-4of8 { width: 50%; }
.layout-unit-1of3,
.layout-unit-2of6 { width: 33.33333%; }
.layout-unit-2of3,
.layout-unit-4of6 { width: 66.66667%; }
.layout-unit-1of4,
.layout-unit-2of8 { width: 25%; }
.layout-unit-3of4,
.layout-unit-6of8 { width: 75%; }
.layout-unit-1of6 { width: 16.66667%; }
.layout-unit-5of6 { width: 83.33333%; }
.layout-unit-1of8 { width: 12.5%; }
.layout-unit-3of8 { width: 37.5%; }
.layout-unit-5of8 { width: 62.5%; }
.layout-unit-7of8 { width: 87.5%; }
Or is this a limitation of SASS?
It's not a limitation of Sass, but the algorithm.
Here is a solution that requires at least Sass 3.3 (see live demo on SassMeister):
Note: I fixed your code to support the exclusion of columns.
$columns: 8;
$exclude-columns: 5 7;
// A stack to store the different widths.
$width_stack: ();
#for $i from 1 through $columns {
#for $j from 1 through $i {
#if $i != $j and not index($exclude-columns, $i) {
$width: (100% / $i) * $j;
// Compute the number 66.66667% to a valid CSS selector: "66-66667".
$width_unitless: $width / 1% + unquote("");
$width_dot: str-index($width_unitless, '.');
#if $width_dot {
$width_unitless: str-slice($width_unitless, 0, $width_dot - 1) +
"-" +
str-slice($width_unitless, $width_dot + 1);
}
// Manage the stack of known widths to avoid repeats.
#if not index($width_stack, $width_unitless) {
$width_stack: append($width_stack, $width_unitless);
// Dynamic placeholder!
%mycols-#{$width_unitless} {
width: $width;
}
}
.layout-unit-#{$j}of#{$i} {
#extend %mycols-#{$width_unitless};
}
}
}
}

Resources