for loop not working in less css mixin - css

I have noticed that a piece of Less I thought was working as expected is not actually generating all the styles I need - my for loop is not working.
The less in question is:
.for(#list, #code) {
& {
.loop(#i:1) when (#i =< length(#list)) {
#value: extract(#list, #i);
#code();
.loop(#i + 1);
}
.loop();
}
}
.role-variants(#variants, #props){
.for(#variants, {
.security_class_#{value} {
#props();
}
});
}
#admin-roles: admin, admin_manager, admin_user, admin_manager_user;
html{
body{
&.admin{
.role-variants(#admin-roles, {display: block;});
}
}
}
on http://less2css.org/ this compiles correctly, generating the classes I expect.
When I compile locally, I only get the following class:
html body.admin .security_class_admin {
display: block
}
My for loop is not working locally, though it seems to be valid and working using the less compiler. Any ideas on how I can modify it to work locally, or perhaps I need to update my environment to a specific version, though it seems to be up to date.
Thanks again for your help.
Jamie

my loop was malformed - this loop now works as expected:
.for(#list, #code) {
& {
.loop(#i) when (#i > 0) {
#value: extract(#list, #i);
#code();
.loop((#i - 1));
}
.loop(length(#list));
}
}

Related

Less Loop basically downgrades performance?

I made this less loop to generate css code needed to a specific task.
(included at bottom of page).
Is it safe to say that writing less-loops reduce development time but also generates unnecessary code styles?
I can see a lot of benefits of using this technique but none of them include performance optimization aspects.
#items : 12;
#color-base : red;
#slice : 30deg;
.looop (#i) when (#i>0){
.looop(#i - 1);
li:nth-child(#{i}){
transform: rotate((#i*#slice)-30) skewY(-2*#slice);
.text {
background : spin(#color-base, 30);
}
}
}
.looop(#items);
You can optimize it a bit:
#items : 12;
#excluded-items: 1, 2, 5;
#color-base : red;
#slice : 30deg;
.looop (#i) when (#i>0) {
.looop(#i - 1);
li:nth-child(#{i}){
transform: rotate((#i*#slice)-30) skewY(-2*#slice);
}
}
.looop(#items);
li {
.text {
background : spin(#color-base, 30);
}
}

SCSS doesn't compile when function is commented out - CompileSass

Unfortunately I'm having to go back through my CSS and re-write some styling to make sure it works for IE8 (client needs it). I have a function that adds z-index to elements,
.mobile-pane {
....
....
/* won't work for IE8 */
/* #for $i from 1 through 4 {
&:nth-child(#{$i}) {
z-index: #{$i};
}
} */
&:first-child {
z-index: 1;
& + .mobile-pane {
z-index: 2;
& + .mobile-pane {
z-index: 3;
& + .mobile-pane {
z-index: 4;
}
}
}
}
}
As you can see, the function is clearly commented out. However (I'm using CompileSASS for Visual Studio), in the output window, I see this:
CompileSass 8:35:55 AM:Sass compilation failed for main.
Error: C:/projectFolder/source/sass/components/header:219: unbound variable $i
In Google WebDev, I'm seeing the function's output, ....:nth-child(2) { z-index:2; } ... and so on, not
.mobile-pane:first-child+.mobile-pane {
z-index: 2;
}
, as I would expect. I'm some-what new to SCSS, so I don't know if this is a known problem, or if CompileSass is not reading the comments correctly.
I understand that I could leave the function in, and just have the IE8 z-index CSS below it, and it will still work, but I wanted to leave the function, in case in the future IE8 was no longer a requirement.
My question - is it normal for SCSS to do this, or is it the extension?
Accessing variables within CSS comments is expected, declaring variables within comments is not.
$i: 100;
/* commenting about #{$i} */
Output:
/* commenting about 100 */
Meanwhile:
/*
$j: 100;
commenting about #{$j} */
Raises an error:
Undefined variable: "$j".
If you want to comment out blocks of code that access variables that don't exist due to being commented out, use double slashes instead:
$j: 100;
.foo {
// content: $j;
}

& as sibling for mixin in LESS

I built a mixin to handle icon sprites in my solution, which basically loops through a list of class names and sets the background position relative to it's index in the sprite
#icon_size-small: 16;
#icon_size-medium: 24;
#icon_size-large: 32;
.commonIcons(#iconSize, #y: 1, #x: 0) {
#posY: (#iconSize * #y);
#posX: (#iconSize * #x);
background: url('images/icons/commonIcons#{iconSize}x#{iconSize}.png') -#posX + 0px -#posY + 0px no-repeat;
height: #iconSize + 0px;
width: #iconSize + 0px;
}
I then call this mixin inside of another one like this
.icons_list-small(#modifier, #x) {
.icon-clock { .commonIcons(#icon_size-small, 1, #x); }
.icon-checkmark { .commonIcons(#icon_size-small, 2, #x); }
.icon-stop { .commonIcons(#icon_size-small, 3, #x); }
etc
and the whole thing is then actually used like this
.small-button {
.icons_list-small(0);
}
So the background position is calculated based on which .icons_list-xxx I use, and the parameter I'm sending in in .small-button decides which y-index is shown (the sprite has 3 variants in a row).
This all works fine when generated as children inside of .small-button, but I've now run up against a case where I need the list generated as sibling selectors to .small-button (giving me .small-button.icon-clock { })
Implementing it like these examples gives me parse errors, understandably:
.small-button.icons_list-small(0);
or
.small-button {
&.icons_list-small(0);
}
So the question: does anyone have a suggestion for what I can do in this instance?
Thanks for any help guys!
Edit: I found a fix myself, but if anyone has a more elegant solution I'd be happy to hear it!
What I did was extend the .icons_list-small mixin like this
.icons_list-small(#modifier, #x) {
#{modifier}.icon -clock { .commonIcons(#icon_size-small, 1, #x); }
Which is then called like this
.icons_list-small(~".icon--inverted", 0);
One solution would be to use the & in your mixin:
.icons_list-small(#x) {
&.icon-clock {
.commonIcons(#icon_size-small, 1, #x);
}
&.icon-checkmark {
.commonIcons(#icon_size-small, 2, #x);
}
&.icon-stop {
.commonIcons(#icon_size-small, 3, #x);
}
}
And when you want to obtain the previous behaviour, to use:
.small-button {
& * {
.icons_list-small(0);
}
}
Which would generate
.small-button *.icon-clock {...}
...
that is equivalent (in CSS) to
.small-button .icon-clock {...}
...
And using it without the & *:
.small-button {
.icons_list-small(0);
}
will generate:
.small-button.icon-clock {...}
...

LESS Repeat selector declaration inside a mixin

I'm 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'd like to be able to pass in multiple image types at once:
.i('code.png', 'asp, php, rb, py')
and have it effectively do this:
.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, short of just declaring a bunch of empty selectors as placeholders?
Updated for LESS 1.5
This code produces the same effect more efficiently in the later versions of LESS, using the newer extract() and length() functions available in LESS 1.5+. Output will be the same as 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
This took a few hours to come up with (no, I didn't have a bunch of free time to work on it, I'm just hopelessly addicted...). One of the parts that took the longest was figuring out why my #stopIndex was not being seen as a number by LESS when I was returning the .length of the array, and throwing a type error. I finally discovered I need to explicitly tell it to see it as a number using the unit() function of LESS.
The solution utilizes general concepts from these sources:
The LESS looping
The Javascript functions in LESS
LESS
.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');
}

Nested pseudoclasses in Less css

I am trying to use LESS CSS to write my CSS but i got a problem with nested pseudoclasses
I
.class1 {
&:nth-of-type(2n) {
.class2{
}
}
}
the output is:
.class1.class2:nth-of-type(2n) {}
but I want to have this:
.class1:nth-of-type(2n) .class2{}
Any ideas?
Not an issue. You probably had a version of LESS CSS that did not produce the correct code. Try the online less converter and see that it works fine. Here is what I get:
(in)
.class1 {
&:nth-of-type(2n) {
.class2{
x:1;
}
}
}
(out)
.class1:nth-of-type(2n) .class2 {
x: 1;
}

Resources