LESS allows parametric mixins, such as:
.transition(@property, @duration){
transition: @property @duration;
-moz-transition: @property @du
In LESS, you can separate arguments using commas OR semi-colons. For single values that include commas, you can terminate that single value with a semi-colon in order to send the list as a single value, like this:
.class {
.background-size(100%, auto;);
}
For multiple values, just use this syntax:
/* Example mixin */
.set-font-properties(@font-family, @size) {
font-family: @font-family;
font-size: @size;
}
/* Usage with comma-separated values */
.class {
.set-font-properties(Arial, sans-serif; 16px);
}
/* Output */
.class {
font-family: Arial, sans-serif;
font-size: 16px;
}
Easy peasy!
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;
}
Current as of LESS 1.4, the documentation (http://lesscss.org/features/#mixins-parametric-feature-mixins-with-multiple-parameters) suggests the proper way to handle this:
Using comma as mixin separator makes it impossible to create comma separated lists as an argument. On the other hand, if the compiler sees at least one semicolon inside mixin call or declaration, it assumes that arguments are separated by semicolons and all commas belong to css lists:
Concretely, mixin:
.transition(@prop-or-props) {
-webkit-transition: @prop-or-props;
-moz-transition: @prop-or-props;
-o-transition: @prop-or-props;
transition: @prop-or-props;
}
usage:
.transition(opacity .2s, transform .3s, -webkit-transform .3s;);
Note that multiple properties are separated by commas and the trailing semi-colon causes the comma separated list to be treated as a single parameter in the mixin.
It would be nicer to define the mixin with a rest...
parameter and be able to extract each element of the arbitrary-length arguments for separate handling, but the use-case I'm thinking of is adding vendor prefixes to transform transitions (so i could call it simply with .transition(opacity .2s, transform .3s)
and have the -webkit-transform
bit added automatically) and perhaps this is better handled by a different utility anyway (gulp-autoprefixer, for example).
Output is the same, but note the difference in how the properties can be passed in the newer versions of LESS by using the semicolon instead of doing an escaped string:
@prop1: color;
@prop2: opacity;
@dur1: 3s;
@dur2: 4s;
.transition(@transString: 0) when not (@transString = 0) {
transition: @transString;
-moz-transition: @transString; /* Firefox 4 */
-webkit-transition: @transString; /* Safari and Chrome */
-o-transition: @transString; /* Opera */
}
.class1 {.transition();}
.class2 {.transition(width 2s, height 2s;);}
^
semicolon here
.class3 {.transition(@prop1 @dur1, @prop2 @dur2;);}
^
semicolon here
The semicolon forces the commas to be evaluated as list separators rather than parameter separators.
We build the correct property arguments as a string for the transition
, then use the escaped value (~
) operator to translate that into the proprietary syntax needed. By using string interpolation (@{variableName}
) we can even embed variables into the process, but the actual input needs to be in the form of an escaped string.
LESS Code
@prop1: color;
@prop2: opacity;
@dur1: 3s;
@dur2: 4s;
.transition(@transString: 0) when not (@transString = 0) {
transition: @transString;
-moz-transition: @transString; /* Firefox 4 */
-webkit-transition: @transString; /* Safari and Chrome */
-o-transition: @transString; /* Opera */
}
.class1 {.transition();}
.class2 {.transition(~" width 2s, height 2s");}
.class3 {.transition(~" @{prop1} @{dur1}, @{prop2} @{dur2}");}
CSS Output
Note: no .class1
is output because the guard expression insures that something is input (though it does not guard against improper input).
.class2 {
transition: width 2s, height 2s;
-moz-transition: width 2s, height 2s;
-webkit-transition: width 2s, height 2s;
-o-transition: width 2s, height 2s;
}
.class3 {
transition: color 3s, opacity 4s;
-moz-transition: color 3s, opacity 4s;
-webkit-transition: color 3s, opacity 4s;
-o-transition: color 3s, opacity 4s;
}
Note: This answer is not added with the intention of saying the existing answers are incorrect or obsolete. All the answers are valid and would still work. This one just provides a different method which in my opinion is a bit more complex but also more flexible in terms of how each argument can be mentioned as key-value pairs.
Advantages of using this method: This method would become more useful when there is a need to perform any extra operation on the values (say like adding unit
as deg
, px
or performing any extra math operations etc) or dynamically adding the vendor prefixes for the @property
also. For example there are times when you might want to pass only transform
as an input property to the mixin but want to add -webkit-transform
for the -webkit-transition
and -moz-transform
for the -moz-transition
etc.
In this method, we make use of the ...
feature which allows us to pass variable number of arguments to a mixin, loop over each argument that is passed, extract
the name of the property along with the additional parameters (like duration, degree of rotation etc) and then use the merge feature that is provided by Less to concatenate the values specified for the property.
.transition(@args...){
.loop-args(@argCount) when (@argCount > 0) {
.loop-args(@argCount - 1);
@arg: extract(@args, @argCount);
@property: extract(@arg,1);
@duration: extract(@arg,2);
-webkit-transition+: @property @duration;
-moz-transition+: @property @duration;
-o-transition+: @property @duration;
transition+: @property @duration;
}
.loop-args(length(@args));
}
div{
.transition(background, 1s; border-color, 2s; color, 2s);
}
.transform(@args...){
.loop-args(@argCount) when (@argCount > 0) {
.loop-args(@argCount - 1);
@arg: extract(@args, @argCount);
@property: extract(@arg,1);
@param: extract(@arg,2);
-webkit-transform+_: ~"@{property}(@{param})";
-moz-transform+_: ~"@{property}(@{param})";
-o-transform+_: ~"@{property}(@{param})";
transform+_: ~"@{property}(@{param})";
}
.loop-args(length(@args));
}
div#div2{
.transform(rotate, 20deg; scale, 1.5; translateX, 10px);
}
The above code when compiled would produce the below output:
div {
-webkit-transition: background 1s, border-color 2s, color 2s;
-moz-transition: background 1s, border-color 2s, color 2s;
-o-transition: background 1s, border-color 2s, color 2s;
transition: background 1s, border-color 2s, color 2s;
}
div#div2 {
-webkit-transform: rotate(20deg) scale(1.5) translateX(10px);
-moz-transform: rotate(20deg) scale(1.5) translateX(10px);
-o-transform: rotate(20deg) scale(1.5) translateX(10px);
transform: rotate(20deg) scale(1.5) translateX(10px);
}
Related Answer:
This should work, I think:
.transition(...) {
transition: @arguments;
-moz-transition: @arguments; /* Firefox 4 */
-webkit-transition: @arguments; /* Safari and Chrome */
-o-transition: @arguments; /* Opera */
}
...
- is a valid less syntax, not something to be replaced.