Less lists as a mixin argument(s)
It seams to be a difference between
e("A, B, C")
or~"A, B, C"
andA, B, C
Yes, both e("A, B, C")
and ~"A, B, C"
create so-called "anonymous value" type which is never considered as a meaningful type (it's not a list, not a number, not even a string). Basically an escaped values are just something like "Don't touch me" or "I know what I'm doing!" stuff, they are just being output "as is" and the compiler never tries to understand what's inside. This is basically what exactly the escaped values are for: "print" out something the compiler can't understand.
In general notice that you can use both comma and space as the value delimiter in a list. For example you can use .loop-strings(A B C, 1 2 3, X Y Z;);
(two-dimensional list as a single parameter, so with a multi-argument mixin you even can get a tree-dimensional list in one line). Is there any particular reason you need to use quoted and/or escaped values? For example you could write it just as:
test {
.loop-lists(A, B, C; 1, 2, 3; X, Y, Z);
}
.loop-lists(@lists...) {
.loop(length(@lists));
.loop(@i) when (@i > 0) {
.loop((@i - 1));
.do-something-with(extract(@lists, @i));
}
}
.do-something-with(@list) {
v1: extract(@list, 1);
v2: extract(@list, 2);
v3: extract(@list, 3);
}
---
extract(A, B, C, 2);
For the moment this is incorrect extract
syntax, extract
accepts only two parameters so you could write this as:
extract(A B C, 2);
Or as:
@list: A, B, C;
extract(@list, 2);
---
Here's an example with couple of additional generic hints:
test {
.do-something(A B C, 1 2 3, X Y Z; foo bar, baz; banana);
}
.do-something(@p1, @p2, @p3) {
args1: @arguments; // 3D list
args2: extract(@arguments, 1); // 2D list: A B C, 1 2 3, X Y Z
args3: extract(extract(@arguments, 1), 1); // 1D list: A B C
args4: extract(extract(extract(@arguments, 1), 1), 1); // single value: A
p1- : @p1; // A B C, 1 2 3, X Y Z
p1-1: extract(@p1, 1); // A B C
p1-3: extract(@p1, 3); // X Y Z
@p2-1: extract(@p2, 1); // foo bar
p2-1: @p2-1; // foo bar
p2-1-2: extract(@p2-1, 2); // bar
p2-2: extract(@p2, 2); // baz
p3- : @p3; // banana
p3-1: extract(@p3, 1); // banana
// etc.
quoted-p2: "@{p2}"; // if you need a quoted string do it in reverse (i.e. non-quoted list to a quoted string)
}
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.
Less CSS: Can I call a mixin as an argument when calling another mixin?
As discussed in comments, Less mixins are not functions and the mixin calls cannot return any value. Because of this, one mixin (or its output value) cannot be passed as an argument to another mixin.
Having said that, we can still set a variable within a mixin, call the mixin within each selector block where it is required and make use of the variable defined within it. The mixin call effectively exposes the variable defined within it to the parent scope.
Below is a sample snippet which would call the contrast mixin and assign the calculated value as the text color and border color of the element.
// color variables for user's color
@userColor: #13acae;
@darkUser: hsl(hue(@userColor), saturation(@userColor), lightness(tint(@userColor, 30%)));
@lightUser: hsl(hue(@userColor), saturation(@userColor), lightness(shade(@userColor, 30%)));
// color mixin to alter user's color using Less 'darken' and 'contrast' functions
.contrastColorDark(@percent) {
@color: darken(contrast(@userColor, @darkUser, @lightUser), @percent);
//color: darken(contrast(@userColor, @darkUser, @lightUser), @percent);
}
// border mixin
.border(@width, @color) {
border: @width solid @color;
}
// CSS rule using both mixins
.thing {
.contrastColorDark(10%);
color: @color;
.border(1px, @color);
}
.thing2 {
.contrastColorDark(50%);
color: @color;
.border(1px, @color);
}
LESS mixin: How to loop through passed in arguments
See Mixin Arguments, List Functions and Loops.
With a thing like "for" the snippet can be converted to something like:
@import "loops/for";
#usage {
.align(hcenter, top, bottom, etc);
}
.align(@styles...) {
position: absolute;
content: '';
display: block;
.for(@styles); .-each(@style) {
& when (@style = center) {
margin-left: auto;
margin-right: auto;
margin-top: auto;
margin-bottom: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
& when (@style = hcenter) {
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
}
& when (@style = vcenter) {
margin-top: auto;
margin-bottom: auto;
top: 0;
bottom: 0;
}
& when (@style = top) {
top: 0;
}
& when (@style = bottom) {
bottom: 0;
}
& when (@style = right) {
right: 0;
}
& when (@style = left) {
left: 0;
}
}
}
---
Actually above code can be optimized to more compact:
.align(@styles...) {
position: absolute;
content: '';
display: block;
.center(@pos) {
margin-@{pos}: auto;
@{pos}: 0;
}
.for(@styles);
.-each(center) {.-each(hcenter); .-each(vcenter)}
.-each(hcenter) {.center(left); .center(right)}
.-each(vcenter) {.center(top); .center(bottom)}
.-each(@style) when (default()) {@{style}: 0}
}
Though this way it may look more confusing for one not too familiar with Less.
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;
}
How to pass a comma-separated list to a mixin as a single argument
.gradientMultiple(top,
rgba(255, 255, 255, 1) 0%,
rgba(254, 254, 254, 1) 16%,
rgba(252, 252, 252, 1) 36%,
rgba(239, 239, 239, 1) 66%,
rgba( 18, 34, 106, 1) 66%,
rgba( 13, 31, 136, 1) 84%;);
Also see:
- 0
- 1
- 2
- and finally the lead remark of 3
pass a list to a mixin as a single argument with SASS
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);
}
via: http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#variable_arguments
Related Topics
How to Stick a Footer to Bottom in CSS
How to Use a CSS Wildcard in the Middle of an Attribute Selector
Equal Height of Elements Inside Grid Item with CSS Grid Layout
CSS Opacity and Child Elements
How to Overwrite Angular 2 Material Styles
Webkit Backface Visibility Not Working
Transparent Rounded Corners on Google Map
How to Apply a CSS Transition to the Overflow Property
Are CSS3 ::Before and ::After Pseudo Elements Supported by IE9 or Not
How to Get "Position:Fixed" CSS to Work in IE 7+ with Transitional Doctype
Inverted' Border-Radius Possible
Browser Support for CSS :First-Child and :Last-Child
Why Can't I Animate Custom Properties (Aka CSS Variables)
Make CSS3 Triangle with Linear Gradient