Can You Do a JavaScript for Loop Inside of Less CSS

Can you do a javascript for loop inside of LESS css?

I will recommend to checkout Twitter Bootsrap. They are building their grid system that way. They loop, with recursion, in a less mixin, instead of typing every class they need.

The interesting part is in mixins.less file, in the less directory, below "// The Grid" comment (line 516). The interesting portion is:

#grid {

.core (@gridColumnWidth, @gridGutterWidth) {

.spanX (@index) when (@index > 0) {
(~".span@{index}") { .span(@index); }
.spanX(@index - 1);
}
.spanX (0) {}

...

.span (@columns) {
width: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1));
}
...

Which is called in grid.less file in less directory this way:

#grid > .core(@gridColumnWidth, @gridGutterWidth);

Which produce (among other things):

.span12 {
width: 940px;
}
.span11 {
width: 860px;
}
.span10 {
width: 780px;
}
...

in bootstrap.css line 170.

For @gridColumnWidth, @gridGutterWidth and the rest of variables check variables.less file (line 184)

Be sure to have the last version of lessc node compiler installed.

can I write a loop for css

You can't do loops with pure CSS, however, if you're using something like SASS or LESS then you can do both like:

SASS:

@for $i from 1 through 4
.#{$class-slug}-#{$i}
width: 60px + $i

LESS:

Can you do a javascript for loop inside of LESS css?

However, assuming you just want to apply the same style to each nested div, you can just do

.containerLength > div{
float: left;
}

or perhaps create a class named .float-left and apply it to each element you want floated right.

styling several Div inside a javascript loop

This isn't something I would use divs for since they provide no semantic meaning and you are creating tabular data.

I would instead use a table which is designed for just this purpose.

Additionally styling the element directly is generally considered poor practise. It's more often than not best to CSS to do this so you do not repeat yourself and are able to easily change styles.

I've written an example that demonstrates using both recommendations.

// Create a table and bodyvar table = document.createElement("table"); var body = document.createElement("tbody");
// Loop through the rows and columns to add itemsvar count = 1;for (var i = 1; i < 4; i++) {
// Create a new row var row = document.createElement("tr"); for (var j = 1; j < 4; j++) { var cell = document.createElement("td"); cell.id = count++; // Set the id cell.innerHTML = cell.id; // Set innerHTML to show number for example row.appendChild(cell); // Add the cell to the row } body.appendChild(row); // Add the row to the body}
// Add the body to the table and the table to the documenttable.appendChild(body);document.body.appendChild(table);
table {  border: 1px solid blue;  /* Add the border to the whole table */  border-left-width: 0;  /*  But no border on the left hand side */  border-collapse: separate;  /*  Ensure borders are visible */  border-spacing: 0;  /*  But with no spaces */}
table td { border-left: 1px solid blue; /* Add internal borders to cells */ border-top: 1px solid blue;}
tbody tr:first-child td { border-top: none; /* Make sure we don't have a double border on top */}

CSS LESS - add variable in loop

You could move the colors into an array then fetch by index, e.g:

@colors: 'color-item-1' #f00, 'color-item-2' #0f0, 'color-item-3' #00f;

.generate-item(3);

.generate-item(@n, @i: 1) when (@i =< @n) {
.item@{i} {
color: extract(extract(@colors, @i),2);
}
.generate-item(@n, (@i + 1));
}

How come this JQuery loop doesn't change CSS with elements less than 4

The issue is because your code looks at all .product elements in the DOM, not specifically those within each ul in the each() loop.

To correct this you can use $(this) to reference the current ul, then retrieve its child li elements:

jQuery($ => {
$('ul.products').each(function() {
let $li = $(this).children('.product');
if ($li.length < 4) {
$li.css("background-color", "yellow");
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<ul class="products">
<li class="product">Test</li>
<li class="product">Test</li>
<li class="product">Test</li>
<li class="product">Test</li>
<li class="product">Test</li>
</ul>

<ul class="products">
<li class="product">Test</li>
<li class="product">Test</li>
<li class="product">Test</li>
</ul>

LESS Mixin for loop

Looking at the docs I'd say it would look like:

.foo(4);

.foo(@n, @i: 1) when (@i =< @n) {
&:nth-child(@{i}) {
.animation-delay(100ms + (@i * 20));
}
.foo(@n, (@i + 1));
}

Tested with LESS2CSS using animation-delay property instead of your function:

.foo(4);

.foo(@n, @i: 1) when (@i =< @n) {
&:nth-child(@{i}) {
animation-delay: (100ms + (@i * 20));
}
.foo(@n, (@i + 1));
}

Generates:

:nth-child(1) {
animation-delay: 120ms;
}
:nth-child(2) {
animation-delay: 140ms;
}
:nth-child(3) {
animation-delay: 160ms;
}
:nth-child(4) {
animation-delay: 180ms;
}

LESS CSS nested loops for header elements

This mixin will work in LESS 1.6+. The em at the end of the font-size calculation was kicking up an error and is not necessary as em units are already being used in the calculation.

.headers-generator(@n; @i : 1) when (@i =< @n)
{
h@{i} {
font-size: (2em - (@i - 1) * 0.2);
}

.headers-generator(@n; (@i + 1));
}

.headers-generator(6);

Less css: Maximum call stack size with loop in loop

The problem in your case is because the e() (or ~()) function's output is always a string and you cannot use it to perform mathematical operations or comparisons etc. You can verify this by adding the below line in your @media query (and commenting out the mixin calls).

columnIsNumber: isnumber(@column); 
/* with your current method this will always return false */

To overcome this issue, you should avoid using the e() function for any variable which you would like to perform a mathematical operation on. For instance, you can change your mixin to be like below (refer inline comments for changes made):

@prefixes: 'sm', 'md', 'lg';
@breakpoints: '0', '100rem', '140rem';
@columns: 2, 6, 12; /* note the exclusion of quotes */

.generate-offset(@n, @tag, @i: 1) when (@i < @n) {
.offset--@{tag}-@{i} {
margin-left: (@i * 100% / @n);
}
.generate-offset(@n, @tag, (@i + 1));
}

// Grid loops

.loop(@index, @count) when (@index > 0){
// extract variables
@current: (@count - @index);
@breakpoint: e(extract(@breakpoints, @current));
@column: extract(@columns, @current); /* avoid using e() */
@prefix: e(extract(@prefixes, @current));
@media (min-width: @breakpoint) {
.generate-columns(@column, @prefix);
/*columnIsNumber: isnumber(@column);*/
.generate-offset(@column, @prefix);
}

.loop ((@index - 1), @count);
}

// run
@grids: length(@breakpoints);
.loop(@grids, (@grids + 1));

Of-course you could do it with your own code (with quotes in variable declaration and e() in the mixin) using a bit of JS evaluation. But I wouldn't recommend this approach as it just adds to the complexity in my view.

@media (min-width: @breakpoint) {
.generate-columns(@column, @prefix);
@col: `function(){return @{column}}()`; /* JS evaluation */
/*columnIsNumber: isnumber(@col);*/
.generate-offset(@col, @prefix);
}

or

@media (min-width: @breakpoint) {
.generate-columns(@column, @prefix);
@col: `function(){return parseInt(@{column},10)}()`; /* JS evaluation */
/*columnIsNumber: isnumber(@col);*/
.generate-offset(@col, @prefix);
}


Related Topics



Leave a reply



Submit