How to define a dynamic mixin or function name in SASS?
Variable interpolation in @mixins does not appear to be supported currently.
The SASS documentation calls this #{} interpolation
and describes it like this:
Interpolation: #{}
You can also use SassScript variables in selectors and property names using #{} interpolation syntax:
$name: foo;
$attr: border;
p.#{$name} {
#{$attr}-color: blue;
}
Per the documentation, interpolation of variable names only appears to be supported for selectors and property names, and not for @mixin
s. If you'd like that feature, you may want to file an Issue for it, although this one may already be tracking what you're describing.
Edit:
Are you sure you need to use a @mixin
to accomplish the kind of styling you're talking about? Could you just use a selector with interpolation? For example, would this work:
$event-icons: fair, concert, art-show, conference, dance-show, film, party, festival, theatre, launch
@for $i from 1 to length($event-icons)
$event-icon: nth($event-icons, $i)
.event-icon-#{$event-icon}
background-position: -($event-icon-width * $i) 0
Sass Interpolation of Mixin, Function, and Variable names
Interpolation doesn't work on mixins or variables at this point in time. You'll have to come up with a different way to achieve your goal.
As of Sass 3.3, you can use mappings for this purpose for variables:
$dialogs:
( error:
( light: red
, dark: darken(red, 10%)
)
, success:
( light: green
, dark: darken(green, 10%)
)
);
@each $name, $colors in $dialogs {
.#{$name} {
color: map-get($colors, dark);
}
}
And for functions:
@function green() {
@return lighten(green, 10%);
}
@function red() {
@return lighten(red, 10%);
}
@mixin my-bg($function-name) {
background: call($function-name);
}
.foo {
@include my-bg('red');
}
Generate SCSS mixins based off certain values?
You are not allowed to generate mixins dynamically in Sass
but CSS
classes can be created dynamically.
reference - Read this thread
Method 1
In first method, I have used "key": value
pair to define a Sass map and from that we can easily set the name and value you prefer to mention as class name and it's property value.
$spacing-extra-small: 0.25rem;
$spacing-small: 0.5rem;
$spacing-medium: 1rem;
$spacing-large: 2rem;
$spacing-extra-large: 4rem;
$paddings: (
"pr0": 0,
"pr1": $spacing-extra-small,
"pr2": $spacing-small,
"pr3": $spacing-medium,
"pr4": $spacing-large,
"pr5": $spacing-extra-large
);
@each $padding, $value in $paddings {
.#{$padding} {
padding-right: #{$value};
}
}
Note - Instead of variables I have added in $padding
map, you can apply absolute pixel values directly as shown below.
$paddings: (
"pr0": 0,
"pr1": 0.25rem,
"pr2": 0.5rem,
"pr3": 1rem,
"pr4": 2rem,
"pr5": 4rem
);
Method 2
Here in second method, I have used only value
s to define a Sass map and it's class name is generated dynamically using index
of map value
.
Not like in JavaScript
array
object, initial Index
of map is started from number 1. So I have perform a calculation by subtracting 1
value from the current index of map value
and match to your individual mixin names mentioned above.
$spacing-extra-small: 0.25rem;
$spacing-small: 0.5rem;
$spacing-medium: 1rem;
$spacing-large: 2rem;
$spacing-extra-large: 4rem;
$paddings: ( 0, $spacing-extra-small, $spacing-small, $spacing-medium, $spacing-large, $spacing-extra-large );
@each $padding in $paddings {
.pr#{index(($paddings), ($padding)) - 1} {
padding-right: #{$padding};
}
}
Method 3
Here I have made it bit simplify by reducing to 1 mixin
and 5 variables. This mixin
can be included inside any css
class with a preferred padding variable.
HTML
<div class="box">
set a padding value here
</div>
SCSS
$spacing-extra-small: 0.25rem;
$spacing-small: 0.5rem;
$spacing-medium: 1rem;
$spacing-large: 2rem;
$spacing-extra-large: 4rem;
$pr0 : 0px;
$pr1 : $spacing-extra-small;
$pr2 : $spacing-small;
$pr3 : $spacing-medium;
$pr4 : $spacing-large;
$pr5 : $spacing-extra-large;
@mixin set-padding ($pr){
@if($pr){
padding-right: $pr;
}
}
/*Apply set-padding mixin to .box class*/
.box {
background-color: #ccc;
@include set-padding($pr2);
}
All three methods will be helpful to solve your problem. Thanks :)
Creating or referencing variables dynamically in Sass
Sass does not allow variables to be created or accessed dynamically. However, you can use lists for similar behavior.
scss:
$list: 20px 30px 40px;
@mixin get-from-list($index) {
width: nth($list, $index);
}
$item-number: 2;
#smth {
@include get-from-list($item-number);
}
css generated:
#smth {
width: 30px;
}
- http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#lists
- http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#list-functions
Is it posible to dynamically invoke a mixin in Sass?
You can't do this directly, but you can work around it. You could do kind of a switch statement:
@mixin breakpoint($mixin) {
@if $mixin == mixin1 {
@include mixin1;
}
@if $mixin == mixin2 {
@include mixin2;
}
}
How to dynamically change variable in mixin function in sass?
You need to specifically loop over the mixin a certain number of times, else how does the sass know how many nth-child
selectors to create?
I've removed your custom functions to make my example cleaner, but you can see that I have created a loop around the call to the mixin, which runs 9 times, passing the index to the function each time:
@mixin child($n) {
&:nth-child(#{$n}){
right: (50px * $n) !important;
}
}
li {
position: absolute;
top: -30px;
right: 0;
@for $i from 1 through 9 {
@include child($i);
}
}
How to use @each in mix includes in Sass?
The problem is here: @include media-#{$media-key} {...}
'cause you can't use interpolation in @mixin
. See this post, it is very clear about this issue: How to define a dynamic mixin or function name in SASS?
So, we have to use another way. A solution could be create a general mixin and work with its arguments. Something like this:
@mixin general-media($width){
@media only screen and (min-width: $width) {
@content;
}
}
After that, I choose to add your width values in $media-map
map and use them with that mixin (I tried to use your code):
$media-map: (
smartphone-xs: ( type: 'xs', width: $xs-width ),
smartphone-sm: ( type: 'sm', width: $sm-width ),
tablet-md: ( type: 'md', width: $md-width ),
tablet-lg: ( type: 'lg', width: $lg-width ),
desktop: ( type: 'xl', width: $xl-width )
);
And this is your loop with some changes:
@each $media-key, $media-type in $media-map {
@include general-media(map-get($media-type, 'width')) {
@each $display-key, $display-type in $container-map {
.container-#{map-get($media-type, 'type' )}-#{$display-key} {
display: map-get($map: $display-type, $key: display );
}
}
}
}
This is all code in action:
/* MEDIA_QUERIES.SCSS */
$xs-width: 320px;
$sm-width: 576px;
$md-width: 768px;
$lg-width: 992px;
$xl-width: 1200px;
@mixin general-media($width){
@media only screen and (min-width: $width) {
@content;
}
}
/* SIXBASE-GRID.SCSS */
$container-map: (
flex: ( display: flex ),
inline: ( display: inline )
);
$flex-direction-map: (
row: ( flex-direction: row ),
row-reverse: ( flex-direction: row-reverse ),
column: ( flex-direction: column ),
column-reverse: ( flex-direction: column-reverse )
);
$media-map: (
smartphone-xs: ( type: 'xs', width: $xs-width ),
smartphone-sm: ( type: 'sm', width: $sm-width ),
tablet-md: ( type: 'md', width: $md-width ),
tablet-lg: ( type: 'lg', width: $lg-width ),
desktop: ( type: 'xl', width: $xl-width )
);
* {
&::before,
&::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
}
@each $media-key, $media-type in $media-map {
@include general-media(map-get($media-type, 'width')) {
@each $display-key, $display-type in $container-map {
.container-#{map-get($media-type, 'type' )}-#{$display-key} {
display: map-get($map: $display-type, $key: display );
}
}
}
}
The output:
*::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
@media only screen and (min-width: 320px) {
.container-xs-flex {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.container-xs-inline {
display: inline;
}
}
@media only screen and (min-width: 576px) {
.container-sm-flex {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.container-sm-inline {
display: inline;
}
}
@media only screen and (min-width: 768px) {
.container-md-flex {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.container-md-inline {
display: inline;
}
}
@media only screen and (min-width: 992px) {
.container-lg-flex {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.container-lg-inline {
display: inline;
}
}
@media only screen and (min-width: 1200px) {
.container-xl-flex {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.container-xl-inline {
display: inline;
}
}
Related Topics
Responsive Order Confirmation Emails for Mobile Devices
How to Specify The Order of CSS Classes
Why Does Naming Your HTML Form Submit Button "Submit" Break Things
How to Make a Div with Arrowlike Side Without CSS Border Tricks
CSS Border Color Switch Animation: "From" Color Not Correct
How to Horizontal & Vertical Center a Div
Using: After to Clear Floating Elements
Streaming a Video from Google Drive Using HTML5 Video Tag
Display Background Color for The Page & Align Texts at Center
HTML5 I Tag Validity with Icons
How Does Stackoverflow Make Its Tag Input Field
Paragraph of Text in Circle Using CSS
How to Remove The Default Link Color of The HTML Hyperlink 'A' Tag
How to Center Multiple Divs Inside a Container in CSS
Is Form Enctype "Application/JSON" Available