LESS Repeat selector declaration inside mixin
I am trying to declare background image icons for some table rows:
.i(@file:'file.png', @type) {
&.@{type} {
td:first-child {
background-image: url('../img/@{file}');
}
}
}
I would like to be able to transfer several types of images at once:
.i('code.png', 'asp, php, rb, py')
and is it efficient to do it:
.i(@file:'file.png', @type) {
&.@{type1},
&.@{type2},
&.@{type3},
&.@{type4}, {
td:first-child {
background-image: url('../img/@{file}');
}
}
}
I know the CSS output will be different, the last code example is for illustration purposes.
Any ideas on how to achieve this rather than just declaring empty selectors as placeholders?
source to share
Updated for LESS 1.5
This code provides a more efficient effect in later versions of LESS using the newer features extract()
and functionality length()
available in LESS 1.5+. The result will be the same as in the original example.
.i(@file:'file.png', @types) {
//find length to make the stop point
@stopIndex: length(@types);
//set up our LESS loop (recursive)
.loopTypes (@index) when (@index =< @stopIndex) {
@class: extract(@types,@index);
//print the CSS
&.@{class} {
td:first-child {
background-image: url('../img/@{file}');
}
}
// next iteration
.loopTypes(@index + 1);
}
// "call" the loopingClass the first time getting first item
.loopTypes (1);
}
.myClass {
.i('code.png'; asp, php, rb, py;);
}
With loops and inline Javascript in LESS 1.3.3
It took hours to come up with (no, I didn't have a ton of free time to work on it, I'm just hopelessly addicted ...). One of the more lengthy parts was figuring out why mine was @stopIndex
not seen as a number using LESS when I was returning an .length
array and throwing a type error. I finally found that I need to explicitly state this in order to see it as a number using the unit()
LESS function .
The solution uses general concepts from these sources:
SMALLER
.i(@file:'file.png', @type) {
//find length to make the stop point
@stopIndex: unit(`(function(){ return @{type}.split(",").length})()`);
//need to get the first item in @type
@firstClass: ~`(function(){
var clsArray = @{type}.replace(/\s+/g, '').split(",");
return clsArray[0];
})()`;
//set up our LESS loop (recursive)
.loopTypes (@index, @captureClass) when (@index < @stopIndex) {
@nextClass: ~`(function(){
var clsArray = @{type}.replace(/\s+/g, '').split(",");
//don't let it try to access past array length
if(@{index} < (@{stopIndex} - 1)) {
return clsArray[@{index} + 1];
}
else { return '' }
})()`;
//print the CSS
&.@{captureClass} {
td:first-child {
background-image: url('../img/@{file}');
}
}
// next iteration
.loopTypes(@index + 1, @nextClass);
}
// define guard expressoin to end the loop when past length
.loopTypes (@stopIndex, @captureClass) {}
// "call" the loopingClass the first time getting first item
.loopTypes (0, @firstClass);
}
.myClass {
.i('code.png', 'asp, php, rb, py');
}
CSS output
.myClass.asp td:first-child {
background-image: url('../img/code.png');
}
.myClass.php td:first-child {
background-image: url('../img/code.png');
}
.myClass.rb td:first-child {
background-image: url('../img/code.png');
}
.myClass.py td:first-child {
background-image: url('../img/code.png');
}
source to share