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

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 }
}

Related

animation color sass with variables not working

I want to select the color depend of class. But it always takes the last values in the $color1 and $color2 variables. So it is always showed as yellow.
.animated-color {
-webkit-animation: color_change var(--time-color) infinite alternate;
-moz-animation: color_change var(--time-color) infinite alternate;
-ms-animation: color_change var(--time-color) infinite alternate;
-o-animation: color_change var(--time-color) infinite alternate;
animation: color_change var(--time-color) infinite alternate;
}
.color-white {
$color1: white;
$color2: white;
#-webkit-keyframes color_change {
from {
background-color: $color1;
}
to {
background-color: $color2;
}
}
#-moz-keyframes color_change {
from {
background-color: $color1;
}
to {
background-color: $color2;
}
}
#-ms-keyframes color_change {
from {
background-color: $color1;
}
to {
background-color: $color2;
}
}
#-o-keyframes color_change {
from {
background-color: $color1;
}
to {
background-color: $color2;
}
}
#keyframes color_change {
from {
background-color: $color1;
}
to {
background-color: $color2;
}
}
}
.color-yellow {
$color1: rgb(255, 253, 137);
$color2: rgb(255, 254, 168);
#-webkit-keyframes color_change {
from {
background-color: $color1;
}
to {
background-color: $color2;
}
}
#-moz-keyframes color_change {
from {
background-color: $color1;
}
to {
background-color: $color2;
}
}
#-ms-keyframes color_change {
from {
background-color: $color1;
}
to {
background-color: $color2;
}
}
#-o-keyframes color_change {
from {
background-color: $color1;
}
to {
background-color: $color2;
}
}
#keyframes color_change {
from {
background-color: $color1;
}
to {
background-color: $color2;
}
}
}

Good idea to use #mixin for "DRY'ing" up #keyframes?

Is it a good idea to use mixins to DRY up keyframes as the following example:
Note that I just have left and right here but if I where to have more I think the use of #mixins is a better choice. I am not familiar with the customs of writing neat scss/sass, what is the preferred way?
#keyframes fade-in-left {
0% {
opacity: 0;
transform: translate3d(-100%, 0, 0);
}
100% {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
#keyframes fade-in-right {
0% {
opacity: 0;
transform: translate3d(100%, 0, 0);
}
100% {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
vs
#mixin fade-in-horizontally($direction_value) {
#keyframes fade-in-left {
0% {
opacity: 0;
transform: translate3d($direction_value, 0, 0);
}
100% {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
}
Mixins are great but should not be used just to shorten some code. In that case, you only want to define your #keyframes once.
So, here is a third option: using a list and an each directive.
$keyframes-fade: (
('left', -100%),
('right', 100%)
);
#each $dir, $translateTX in $keyframes-fade {
#keyframes fade-in-#{$dir} {
0% {
opacity: 0;
transform: translate3d($translateTX, 0, 0);
}
100% {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
}
This will make your code shorter while keeping it easy to understand.
You can see the output here

How can I get responsive classes with this mixin

My sass file looks like this when I use my mixin:
$viewports: 25 50 75 100;
#each $viewport in $viewports {
.vh-#{$viewport} {
height: #{$viewport}vh;
}
}
.vh-25 {
height: 25vh;
}
...
But I want that class and the class with the #sm, #md, …
Can I do that with sass?
#media (min-width: 576px) and (max-width: 767px) {
.vh-25#sm {
height: 25vh;
}
}
# is not allowed in class name, but if you want to replace it with -:
$viewports: (
xs: 25,
sm: 50,
md: 75,
xl: 100,
);
#each $viewport, $height in $viewports {
.vh-#{$height}-#{$viewport} {
height: #{$height}vh;
}
}

SASS check if current loop contains part of input

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;
}

SASS keyframes not compiling as wanted

I am using the following keyframes mixin for SCSS
#mixin keyframes($name) {
#-webkit-keyframes #{$name} {
#content;
}
#-moz-keyframes #{$name} {
#content;
}
#-ms-keyframes #{$name} {
#content;
}
#keyframes #{$name} {
#content;
}
}
it works perfectly, when i have to animate, which has the animation property, but when i try to use it for child elements i get not the output, that i need (but syntax-valid)
Example:
#include keyframes('text') {
0% {
span { color: red; }
}
100% {
span { color: green; }
}
}
Will output (short ouput):
#keyframes text {
0% span { color: red; }
100% span { color: green; }
}
But what i need is:
#keyframes text {
0% {
span { color: red; }
}
100% {
span { color: green; }
}
}
How can i prevent sass from snapping the first brackets?
As far as i am concerned you apply keyframes to an element. so your desired output:
#keyframes text {
0% {
span { color: red; }
}
100% {
span { color: green; }
}
}
does not make much sense in CSS.
I think what you need is something like :
#keyframes span#text {
0% {color: red; }
100% { color: green; }
}
also it is not your mixin problem as this SASS:
0% {
span { color: red; }
}
100% {
span { color: green; }
}
compiles to:
0% span {
color: red; }
100% span {
color: green; }
as desired.
I think the intended usege of your keyframes mixin would be something like:
span#text {
#include keyframes(text) {
0% {
color: red;
}
100% {
color: green;
}
}
}

Resources