Using Undefined Number of Arguments in Mixins

Can a sass @mixin accept an undefined number of arguments?

Variable Arguments

Sometimes it makes sense for a mixin to take an unknown number of arguments. For example, a mixin for creating box shadows might take any number of shadows as arguments. For these situations, Sass supports “variable arguments,” which are arguments at the end of a mixin declaration that take all leftover arguments and package them up as a list. These arguments look just like normal arguments, but are followed by .... For example:

@mixin box-shadow($shadows...) {
-moz-box-shadow: $shadows;
-webkit-box-shadow: $shadows;
box-shadow: $shadows;
}

.shadows {
@include box-shadow(0px 4px 5px #666, 2px 6px 10px #999);
}

is compiled to:

.shadows {
-moz-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
-webkit-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
}

From : SASS official Documentation

So you basically just need to change your mixins declaration to look like this :

@mixin transition($var...)
-webkit-transition: $var
transition: $var

Less CSS: Mixins with Variable Number of Arguments

See my answer here: Multiple properties are getting treated as separate arguments in mixins

Summary: use this mixin for variable number of arguments:

.transition (@value1,@value2:X,...)
{
@value: ~`"@{arguments}".replace(/[\[\]]|\,\sX/g, '')`;

-webkit-transition: @value;
-moz-transition: @value;
-ms-transition: @value;
-o-transition: @value;
transition: @value;
}

Making a Sass mixin with optional arguments

A DRY'r Way of Doing It

And, generally, a neat trick to remove the quotes.

@mixin box-shadow($top, $left, $blur, $color, $inset:"") {
-webkit-box-shadow: $top $left $blur $color #{$inset};
-moz-box-shadow: $top $left $blur $color #{$inset};
box-shadow: $top $left $blur $color #{$inset};
}

SASS Version 3+, you can use unquote():

@mixin box-shadow($top, $left, $blur, $color, $inset:"") {
-webkit-box-shadow: $top $left $blur $color unquote($inset);
-moz-box-shadow: $top $left $blur $color unquote($inset);
box-shadow: $top $left $blur $color unquote($inset);
}

Picked this up over here: pass a list to a mixin as a single argument with SASS

How to define Sass mixins with variable arguments

You can set your second parameter to be false as the default value, and do a @if statement inside your mixin.

@mixin myMixin( $param1, $param2:false ){
@if $param2 == false{
// Do something
}
@else{
// Do something with both parameters
}
}

Edit: this a custom function I made to transform px unit into em unit. You can pass a list or a single value as parameter. You can also set a base and a line-height. Maybe you can find few tricks inside this function.

You can use it like this: emify(10px 16px, 16px).

This will output: 0.625em 1em

/**
*
* Emify
* Transform px unit into em
* defaults:
* base: 16
* usage:
* emify(unit)
* emify(unit, base)
* emify(unit, line-height, base)
* examples:
* emify(16px) = 1em
* emify(16px, 10px) = 1.600em
* emify(16px, 10px, 10px) = 1.600em / 1em
*
**/
@function emify( $target, $lineheight: null, $base: null ) {

@if $base == null and $lineheight == null { $base: 16 }
@if $base == null and $lineheight != null { $base: $lineheight }

[...]

}

Variable list of arguments in a LESS mixin

@rest is not a keyword, its a sample identifier use to demonstate .... It could have any other name.

To fix your code:

.linear-gradient(@rest...) {
background: -webkit-linear-gradient(@rest);
background: -o-linear-gradient(@rest);
background: -moz-linear-gradient(@rest);
background: linear-gradient(@rest);
}

body > header {
.linear-gradient(red, yellow, blue);
}

You could replace @rest with @arguments inside the mixin as you use the entire input as a "variable arguments list". Then you could also omit the @rest identifier altogether:

.linear-gradient(...) {
background: -webkit-linear-gradient(@arguments);
background: -o-linear-gradient(@arguments);
background: -moz-linear-gradient(@arguments);
background: linear-gradient(@arguments);
}

There's no difference between the 2 versions.

But all of that is not what you want at all. The 2 solutions above will result in a CSS that looks like this:

background: linear-gradient(red yellow blue);

That is because the values are interpreted as individual arguments, and are concatenated in a string with spaces.

What you need is this:

.linear-gradient(@colors) {
background: -webkit-linear-gradient(@colors);
background: -o-linear-gradient(@colors);
background: -moz-linear-gradient(@colors);
background: linear-gradient(@colors);
}

body > header {
.linear-gradient(red, yellow, blue;);
}

This tells LESS that the argument passed into the mixin is a single variable, with comma's inside. That translates to your required output.

How to count Sass mixin variable arguments

You can use the length function:

@mixin my_func( $args... ) {
@if length($args) == 4 {
... output here ...
}

@else {
... output here ...
}
}

LESS Mixins with Optional Parameters - Skip Undefined Properties

Looks like I am able to leverage the Mixin Guards. By using the when not and if not operators nested inside the mixin, I can check for multiple parameters where the , separator acts as an or.

When @blockEnd or @block are truthy, compile the following

.border(@border; @block: null; @blockEnd: null;) {
border: @border;

& when not(@blockEnd = null), not(@block = null) {
border-block-end: if(not (@blockEnd = null), @blockEnd, @block);
}
}

This will evaluate to:

// LESS
.container {
.border(@border: 1px solid red);
}

// CSS
.container {
border: 1px solid red;
}

It feels quite verbose, but it gets the job done.. Am I missing an easier approach, possibly?



Related Topics



Leave a reply



Submit