Less Lists as a Mixin Argument(S)

Less lists as a mixin argument(s)

It seams to be a difference between e("A, B, C") or ~"A, B, C" and A, 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



Leave a reply



Submit