why is this less code not compiling? - css

I've extracted this piece of less code that is causing a web app to throw an error when it runs an asynchronous task to compile this less code. I've never written less before and from my initial perusal of the docs I can't seem to find whats wrong. Anybody know what's wrong?
This is the error:
ParseError: Unrecognised input in /Users/****/Desktop/testmoreless.css on line 4, column 3:
3
4 .core (#gridColumnWidth, #gridGutterWidth) {
5
This is the entire piece of code:
#grid {
.core (#gridColumnWidth, #gridGutterWidth) {
.spanX (#index) when (#index > 0) {
(~".span#{index}") { .span(#index); }
.spanX(#index - 1);
}
.spanX (0) {}
.offsetX (#index) when (#index > 0) {
(~".offset#{index}") { .offset(#index); }
.offsetX(#index - 1);
}
.offsetX (0) {}
.offset (#columns) {
margin-left: (#gridColumnWidth * #columns) + (#gridGutterWidth * (#columns - 1)) + (#gridGutterWidth * 2);
}
.span (#columns) {
width: (#gridColumnWidth * #columns) + (#gridGutterWidth * (#columns - 1));
}
.row {
margin-left: #gridGutterWidth * -1;
.clearfix();
}
[class*="span"] {
float: left;
margin-left: #gridGutterWidth;
}
// Set the container width, and override it for fixed navbars in media queries
.container,
.navbar-fixed-top .container,
.navbar-fixed-bottom .container { .span(#gridColumns); }
// generate .spanX and .offsetX
.spanX (#gridColumns);
.offsetX (#gridColumns);
}
.fluid (#fluidGridColumnWidth, #fluidGridGutterWidth) {
.spanX (#index) when (#index > 0) {
(~"> .span#{index}") { .span(#index); }
.spanX(#index - 1);
}
.spanX (0) {}
.span (#columns) {
width: (#fluidGridColumnWidth * #columns) + (#fluidGridGutterWidth * (#columns - 1));
}
.row-fluid {
width: 100%;
.clearfix();
> [class*="span"] {
float: left;
margin-left: #fluidGridGutterWidth;
}
> [class*="span"]:first-child {
margin-left: 0;
}
// generate .spanX
.spanX (#gridColumns);
}
}
.input(#gridColumnWidth, #gridGutterWidth) {
.spanX (#index) when (#index > 0) {
(~"input.span#{index}, textarea.span#{index}, .uneditable-input.span#{index}") { .span(#index); }
.spanX(#index - 1);
}
.spanX (0) {}
.span(#columns) {
width: ((#gridColumnWidth) * #columns) + (#gridGutterWidth * (#columns - 1)) - 10;
}
input,
textarea,
.uneditable-input {
margin-left: 0; // override margin-left from core grid system
}
// generate .spanX
.spanX (#gridColumns);
}
}

Take a look at this answer.
Quoting the answer verbatim:
This is what the file had originally:
(~".span#{index}") { .span(#index); }
After reading the LESS change log, I found that they changed the syntax so you can now use variables directly without needing the ~ hack. So I changed my mixin.less to look like this:
.span#{index} { .span(#index); }
There are a couple of other lines that you need to change, but they all follow the same format.
(~".offset#{index}") { .offset(#index); } changes to → .offset#{index} { .offset(#index); }

Related

Generating the value of CSS content in LESS loop

We have a CSS style that adds dots before and after a heading indicating the nesting level of the heading:
.heading.nesting-1:before,.heading.nesting-1:after{content:"\00B7"}
.heading.nesting-2:before,.heading.nesting-2:after{content:"\00B7\00B7"}
.heading.nesting-3:before,.heading.nesting-3:after{content:"\00B7\00B7\00B7"}
...
I have tried the following LESS but it doesn't concatenate the strings correctly
#entity-dot: '\00B7';
#nesting-levels: 9;
.heading {
.nesting-loop (#i) when (#i <= #nesting-levels) {
&.nesting-#{i} {
&:before, &:after {
.nested-dots(#j, #current: "") when (#j > 0) {
#nested-dots: "#{current}#{entity-dot}";
.nested-dots((#j - 1), #nested-dots);
}
.nested-dots(#j: #i, "");
content: "#{nested-dots}";
}
}
.nesting-loop(#i + 1);
}
.nesting-loop (1);
}
The result is:
.heading.nesting-1:before,.heading.nesting-1:after{content:"\00B7"}
.heading.nesting-2:before,.heading.nesting-2:after{content:"\00B7"}
.heading.nesting-3:before,.heading.nesting-3:after{content:"\00B7"}
...
I think I understand that the problem is that the property #nested-dots cannot be iteratively updated in this way but I was wondering if anybody had a solution?
Thanks for your help.
This is how I resolved it with the help of this post
(thank you Martin Turjak)
#nesting-levels: 5;
#entity-space: '\00A0';
#entity-dot: '\00B7';
.content-dots (#numdots) {
//Mixin output
.nested-dots(1, #dots1) {
#dots: "#{dots1}#{entity-dot}";
}
//Mixin iterator
.nested-dots(#index, #dots1) when (#index > 1) {
#dots2: "#{dots1}#{entity-dot}#{entity-space}";
.nested-dots((#index - 1), #dots2);
}
//Call mixin
.nested-dots(#numdots, "");
//Output dots
content: "#{dots}";
}
.heading {
.nesting-loop (#i) when (#i >= 1) {
&.nesting-#{i} {
&:before, &:after {
.content-dots(#i);
}
}
.nesting-loop (#i - 1);
}
.nesting-loop (#nesting-levels);
}
The result is
.heading.nesting-5:before,.heading.nesting-5:after{content:"\00B7\00A0\00B7\00A0\00B7\00A0\00B7\00A0\00B7"}
.heading.nesting-4:before,.heading.nesting-4:after{content:"\00B7\00A0\00B7\00A0\00B7\00A0\00B7"}
.heading.nesting-3:before,.heading.nesting-3:after{content:"\00B7\00A0\00B7\00A0\00B7"}
.heading.nesting-2:before,.heading.nesting-2:after{content:"\00B7\00A0\00B7"}
.heading.nesting-1:before,.heading.nesting-1:after{content:"\00B7"}

How can I use a loop in LESS to create specific class names for typography?

I want to generate 9 typography classes, each with the following:
font-size: 2rem;
line-height: 1rem;
I'll be using standard typographic multipliers for font sizes and line-height. Instead of hard-coding all of these CSS classes, I was wondering if there was a more elegant way of generating them in a loop using LESS.
I found the following from another thread:
#iterations: 5;
.span-loop (#i) when (#i > 0) {
.span-#{i} {
width: ~"#{i}%";
}
.span-loop(#i - 1);
}
.span-loop (#iterations);
Which generates:
.span-5 {
width: 5%;
}
.span-4 {
width: 4%;
}
.span-3 {
width: 3%;
}
.span-2 {
width: 2%;
}
.span-1 {
width: 1%;
}
This is pretty close, but I'd love for my class names to more "named". How can I use a loop to generate classes for:
.small { }
.caption { }
.body { }
.subheader { }
.title { }
.headline { }
etc...
I'm also not tied to LESS, so if there's a better CSS preprocessor language, then I'm happy to use that instead :)
Thank you!
An example from documentation for further modification;)
for more complicated code, it is better to use scss than less
.for(#list, #code) {
& {
.loop(#i: 1) when (#i =< length(#list)) {
#value: extract(#list, #i);
#code();
.loop(#i + 1);
}
.loop();
}
}
#elements: small, caption, body, subheader, title, headline;
.for(#elements, {
#remfont: #i+1;
#remline: ((#i+1) * 1.5 / 3);
.#{value} {
font-size: ~"#{remfont}rem";
line-height: ~"#{remline}rem";
}
});

Multiple selectors in loop in LESS

I am using the following code to generate a column layout using LESS CSS:
.columnBuilder (#index) when (#index =< #columnCount) {
.container_#{columnCount} .grid_#{index} {
width: unit(((#baseWidth / #columnCount) * #index)-10, px);
}
.columnBuilder(#index + 1);
}
Which gives me an output:
.container_24 .grid_1 {
width: 69px;
}
.container_24 .grid_2 {
width: 148px;
}
.container_24 .grid_3 {
width: 227px;
}
etc...
How would i now create a new less function that would give an output of:
.grid_1,
.grid_2,
....,
.grid_N {
display: inline;
float: left;
margin-left: 5px;
margin-right: 5px;
}
Where N is defined as #columnCount: 24;, though the column count is not set, it can be changed to any number. I am aware i could create a body for each grid_X would like to avoid it to keep clutter down.
Using :extend() in LESS 1.4+
This seems to accomplish it more elegantly. You first define the initial values you will want extended in a hard coded .grid_1 class (at present, LESS will not extend dynamically generated classes), then add an extender mixin in your loop to extend to that class. Like so:
.grid_1 { //this acts as the "launch point" for extending them all
display: inline;
float: left;
margin-left: 5px;
margin-right: 5px;
}
.columnBuilder (#index) when (#index =< #columnCount) {
//we are going to use this class twice, so just calculate it once
#gridClass: ~'.grid_#{index}';
//this is your original code except the variable now used for the grid class
.container_#{columnCount} #{gridClass} {
width: unit(((#baseWidth / #columnCount) * #index)-10, px);
}
//this is your extender feature, which does not do so for the initial .grid_1
//which was set above as our launch point.
#{gridClass} {
.extender() when (#index > 1) {
&:extend(.grid_1 all);
}
.extender() when (#index = 1) {}
.extender();
}
//iterate the loop just as you were doing
.columnBuilder(#index + 1);
}
//call the loop starting at 1
.columnBuilder(1);
Output is your expected:
.grid_1,
.grid_2,
....,
.grid_N {
display: inline;
float: left;
margin-left: 5px;
margin-right: 5px;
}
As it turns out, LESS has no native support for something like this and will always create multiple blocks of CSS each with its own body, so you need to run a little hack with mixins. I used the following:
.columnBuilderX (#index) when (#index = 1) {
#isel: ~".grid_#{index}, ";
.columnBuilderX (#index + 1, #isel);
}
.columnBuilderX (#index, #innerSel) when (#index =< (#columnCount - 1)) {
#isel: #innerSel + ~".grid_#{index}, ";
.columnBuilderX (#index + 1, #isel);
}
.columnBuilderX (#index, #innerSel) when (#index = #columnCount) {
#isel: #innerSel + ~".grid_#{index} ";
#{isel} {
display: inline;
float: left;
margin-left: 5px;
margin-right: 5px;
}
.columnBuilderX (#index + 1, #isel);
}
Which produced for me:
.grid_1, .grid_2, .grid_3, .grid_4, .grid_5, .grid_6, .grid_7, .grid_8, .grid_9, .grid_10, .grid_11, .grid_12, .grid_13, .grid_14, .grid_15, .grid_16, .grid_17, .grid_18, .grid_19, .grid_20, .grid_21, .grid_22, .grid_23, .grid_24 {
display: inline;
float: left;
margin-left: 5px;
margin-right: 5px;
}
The first mixin is the initial mixin that is called that does not already have an inner selector, the second mixin requires a second param, which is the variable we create in the first, which then runs recursively until we hit our last column as defined by the when clause, where we add our last selector without the comma, and then use the selector list we have built in to apply our CSS too.
If anybody can come up with something simpler than this, please create an answer.

How do I create nested loops with LESS CSS?

What I know is that this:
#iterations: 8;
.mixin-loop (#index) when (#index > 0) {
.my-class-#{index} {
width: (100% / #index);
}
.mixin-loop(#index - 1);
}
.mixin-loop (0) {}
.mixin-loop(#iterations);
… Will result in this:
.my-class-8{width:12.5%}
.my-class-7{width:14.285714285714286%}
.my-class-6{width:16.666666666666668%}
.my-class-5{width:20%}
.my-class-4{width:25%}
.my-class-3{width:33.333333333333336%}
.my-class-2{width:50%}
.my-class-1{width:100%}
… Making it the LESS equivalent of:
for (var i = 8; i > 0; -- i) {
// …
}
My question is: What would the LESS equivalent of:
for (var i = 8; i > 0; -- i) {
for (var j = 4; j > 0; -- j) {
// …
}
}
… Look like?
Hm, nevermind—Found it myself.
I’m leaving the answer here for posterity’s sake:
#maxi: 8;
.i-loop (#i) when (#i > 0) {
#maxj: 8;
.j-loop (#j) when (#j > 0) {
.my-class-#{i}-#{j} {
width: (100% / #i);
height: (100% / #j);
}
.j-loop(#j - 1);
}
.j-loop (0) {}
.j-loop(#maxj);
.i-loop(#i - 1);
}
.i-loop (0) {}
.i-loop(#maxi);
An Unnested Solution
I'm only offering this as an alternative here for final output code purposes. My answer does not really address nesting of loops directly (as your question is and your own answer found that solution). Rather, it challenges whether nesting is even best to solve the problem you faced.
Assuming a class structure just as you have (say my-class-2-6 for example), you can reduce from 64 output CSS selectors to just 16 by not nesting them and instead using CSS3 attribute selectors (which may not be desirable, depending on target browsers you need to support). Thus this LESS:
#maxi: 8;
#maxj: 8;
#iSelStart: ~'[class^=my-class-';
#jSelStart: ~'[class$=-';
#ijSelEnd: ~']';
.i-loop (#i) when (#i > 0) {
#{iSelStart}#{i}#{ijSelEnd} {
width: (100% / #i);
}
.i-loop(#i - 1);
}
.j-loop (#j) when (#j > 0) {
#{jSelStart}#{j}#{ijSelEnd} {
height: (100% / #j);
}
.j-loop(#j - 1);
}
//stop loops
.i-loop (0) {}
.j-loop (0) {}
//itialize loops
.j-loop(#maxj);
.i-loop(#maxi);
Becomes this CSS:
[class$=-8] {
height: 12.5%;
}
[class$=-7] {
height: 14.285714285714286%;
}
[class$=-6] {
height: 16.666666666666668%;
}
[class$=-5] {
height: 20%;
}
[class$=-4] {
height: 25%;
}
[class$=-3] {
height: 33.333333333333336%;
}
[class$=-2] {
height: 50%;
}
[class$=-1] {
height: 100%;
}
[class^=my-class-8] {
width: 12.5%;
}
[class^=my-class-7] {
width: 14.285714285714286%;
}
[class^=my-class-6] {
width: 16.666666666666668%;
}
[class^=my-class-5] {
width: 20%;
}
[class^=my-class-4] {
width: 25%;
}
[class^=my-class-3] {
width: 33.333333333333336%;
}
[class^=my-class-2] {
width: 50%;
}
[class^=my-class-1] {
width: 100%;
}
So the example of my-class-2-6 would target the start of the class name my-class-2 giving a width: 50% and target the end of the class name -6 which would give a height: 16.666666666666668%;.
Just a thought for any future users facing a similar situation who are only worried about targeting CSS3 browsers.
Update: Added Protection to not Incorrectly Target
As an after thought, it occurred to me that if you have various types of classes that may have an ending of -1 or -2 etc., then your ending CSS may need to have an additional set of code to help filter for just that class. So the j loop code above would need to have a change to the selector string like so:
#{iSelStart}#{ijSelEnd}#{jSelStart}#{j}#{ijSelEnd} { /*properties*/}
Which would then output this format of code:
[class^=my-class-][class$=-1] {
/*properties*/
}
This way it is looking specifically for the my-class- "class" that ends in -1, and would ignore selecting another class like another-class-1 as the original code above would still select. Whether this is an issue or not would purely be related to the design and class naming used in one's site.
Old question but maybe it's worth mentioning that Less can now do this easier
Function
.for(#i, #n, #r){#r();._(#i)}
.for(#n, #r)when(isnumber(#n)){.for(0, #n, #r)}
.for(#i, #n, #r)when not(#i = #n - 1){.for((#i + ((#n - #i) / abs(#n - #i))), #n, #r)}
Usage
.for(3, {._(#i) {
.for(3, {._(#j) {
item-#{i}-#{j} {
i: #i;
j: #j;
}
}});
}});
Example: Codepen
.loop(#n: 1, #m: #n, #k: #n * #m) when(#k > 0) {
.loop(#n, #m, #k - 1);
#i: `Math.floor((#{k} - 1) / #{m})`;
#j: #k - #i * #n - 1;
/*
#i runs up 1 to #n,
#j runs up 1 to #m and
#k runs up 1 to #n * #m
for example:
*/
&:nth-child(#{k}) {
top: 50px * #i;
left: 100px * #j;
}
}
/* using: */
.loop(3,4);

less css grid settup

I'm creating less grid sistem and i dont know how to optimise grid.less
If i chouse #gridColumns: 14; i need to add new lines in grid.less, maybe there is anothes option to automate this?
Variables.less
#gridColumns: 12;
#gridWidth: 62.5em;
#gridGutterWidth: 1.8em;
#grid.less
.l-1 { .grid(1); }
.l-2 { .grid(2); }
.l-3 { .grid(3); }
.l-4 { .grid(4); }
.l-5 { .grid(5); }
.l-6 { .grid(6); }
.l-7 { .grid(7); }
.l-8 { .grid(8); }
.l-9 { .grid(9); }
.l-10 { .grid(10); }
.l-11 { .grid(11); }
.l-12 { .grid(12); }
#mixins.less
.grid(#num) {
width: (100% / #gridColumns) * #num;
position: relative;}
The only sensible way of doing it using LESS is using a recursive mixin like Twitter Bootstrap.
.spanX (#index) when (#index > 0) {
.span#{index} { .span(#index); }
.spanX(#index - 1);
}
.spanX (0) {}
.span (#columns) {
width: (#gridColumnWidth * #columns) + (#gridGutterWidth * (#columns - 1));
}

Resources