Reputation: 1378
Is there a way to use both optional and variable elements in a sass mixin?
i try
@mixin name($className, $centered: false, $dimension...)
but the first dimension value is assigned to $centered
switching parameters order don't compile
@mixin name($className, $dimension..., $centered: false )
the error is:
SASSInvalid CSS after "..., $dimension...": expected ")", was ", $centered: fa..."
since the mixin without the optional parameter is used in many place (over 70) i dont want yo change it all to add the new parameters, so i want to leave it optional?
Any way to change this mixin or i have to leave the original without $centered
and create an ovverride with the new parameter?
for info this is the mixin body:
@for $i from 1 through length($dimension){
@if($centered) {
.#{$className}Td#{$i}, .#{$className}Th#{$i} {
width: nth($dimension, $i);
text-align:center;
}
}
@else{
.#{$className}Td#{$i}, .#{$className}Th#{$i} {width: nth($dimension, $i); }
}
}
EDIT with complete cowking example:
simply iam defining css for column width of my table in a faster way, so this
@include nome("columnsName", 40%, 30%, 30%);
is rendered in that way:
.columnsNameTd1, .columnsNameTh1{width: 40%;}
.columnsNameTd2, .columnsNameTh2{ width: 30%; }
.columnsNameTd3, .columnsNameTh3{ width: 30%;}
i want a way to text-align center all my columns, maybe can be interesting see if there is a way do to specify what column to center, making all other left by default
Upvotes: 2
Views: 5479
Reputation: 2664
This is actually possible using something Sass calls Arbitrary Keyword Arguments. The idea is that you pass a keyword argument as one of your arbitrary (variable) arguments, and then extract it from the argument list using the meta.keywords($args)
function.
Here's a simplified version of your code to illustrate how it works:
@use "sass:map";
@use "sass:meta";
@mixin name($class-name, $widths...) {
$centered: map.get(meta.keywords($widths), centered) or false;
$i: 1;
@each $width in $widths {
.#{$class-name}-#{$i} {
width: $width;
@if $centered {
text-align: center;
}
}
$i: $i + 1;
}
}
Results:
@include name("column", 40%, 30%, 30%);
// .column-1 {width: 40%;}
// .column-2 {width: 30%;}
// .column-3 {width: 30%;}
@include name("column", 40%, 30%, 30%, $centered: true);
// .column-1 {width: 40%; text-align: center;}
// .column-2 {width: 30%; text-align: center;}
// .column-3 {width: 30%; text-align: center;}
The magic happens in that second line of the mixin, where you set the value of $centered
. As you can see, the keyword argument is also removed from $widths
. It's a little bit weird (and not widely known?), but very handy!
Upvotes: 1
Reputation: 68319
You can't do what you're asking because variable arguments (the ...
syntax) absolutely must be last. You have 2 options, I recommend option #2.
Option 1 (examine the last element to see if it is a boolean):
@mixin name($className, $dimension...) {
$last: nth($dimension, length($dimension));
$centered: if(type-of($last) == bool, $last, false);
$length: if(type-of($last) == bool, length($dimension) - 1, length($dimension));
@for $i from 1 through $length {
.#{$className}Td#{$i}, .#{$className}Th#{$i} {
width: nth($dimension, $i);
@if($centered) {
text-align: center;
}
}
}
}
Option 2 (use the @content
directive):
@mixin name($className, $dimension...) {
@for $i from 1 through length($dimension) {
.#{$className}Td#{$i}, .#{$className}Th#{$i} {
width: nth($dimension, $i);
@content;
}
}
}
// usage
@include name(rar, 10%, 20%, 30%);
@include name(rar, 10%, 20%, 30%) {
text-align: center;
}
Upvotes: 5
Reputation: 1771
ok, what if you try testing the last value of your list, since it seems that sass does not support anything else after a list as a parameter.
@function last($list) {
@return nth($list, length($list));
}
//returns the last item of a list
@mixin nome($className, $dimension...) {
@for $i from 1 through length($dimension){
@if(last($dimension) == true) {
.#{$className}Td#{$i}, .#{$className}Th#{$i} {
width: nth($dimension, $i);
text-align:center;
}
}
@else{
.#{$className}Td#{$i}, .#{$className}Th#{$i} {width: nth($dimension, $i); }
}
}
}
so if you add @include nome("className", 4%, 4%, 4%, 6%, 70%, 12%, true);
and the last value is true
it should center your div, or whatever you trying to do!
Upvotes: 2