Concatenate String in LESS in loop - css

I'm working on converting Unsemantic from SASS to LESS and while I'm building the loop to create my classes:
.populateGridClasses (#index, #interval) when (#index > 0) {
#num: #index * #interval;
(~".eh-grid-#{num}, .eh-mobile-grid-#{num}, .eh-tablet-grid-#{num}") {
.grid();
}
.populateGridClasses(#index - 1, #interval);
}
.populateGridClasses (0, #interval) {}
// Create the grids in an inverval of 5
.populateGridClasses(20, 5);
// Create the grids in thirds
.populateGridClasses(3, 33);
It creates the classes as so:
.eh-grid-100, .eh-mobile-grid-100, .eh-tablet-grid-100 {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0 10px;
}
.eh-grid-95, .eh-mobile-grid-95, .eh-tablet-grid-95 {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0 10px;
}
...
Obviously, that could be condesnsed so that all 6 of those classes are defined at once. So my idea is to use the loop to create a giant string that I'll then add the .grid() mixin to:
#test: "";
.populateGridClasses4 (#index, #interval) when (#index > 0) {
#num: #index * #interval;
#ntest: ".eh-grid-#{num}, .eh-mobile-grid-#{num}, .eh-tablet-grid-#{num}";
#test: "#{test}#{ntest}";
.populateGridClasses4(#index - 1, #interval);
}
.populateGridClasses4 (0, #interval) {}
.populateGridClasses4(20, 5);
("#{test}"){
padding-left: 1px;
}
But that gives me a LESS error LESS: Out of stack space. Any idea on how I can create this massive string so I can create 69 classes and only define them once? Programmatically, of course.

You could try passing another attribute to the mixin ... like this, where I added to your code the #t1 to the arguments and define the #t2 in the loop, and pass it on. Now you'll be writing to a variable only in the scope of one loop step, and not trying to overwrite the same variable over again in the recursion (does not agree with less). So this is your code, that should not get the error you mention anymore:
#test: "";
.populateGridClasses4 (#index, #interval, #t1) when (#index > 0) {
#num: #index * #interval;
#ntest: ".eh-grid-#{num}, .eh-mobile-grid-#{num}, .eh-tablet-grid-#{num}";
#t2: ~"#{t1}#{ntest}";
.populateGridClasses4(#index - 1, #interval,#t2);
}
.populateGridClasses4 (0, #interval,#t1) {}
.populateGridClasses4(20, 5, #test);
#{t2} {
padding-left: 1px;
}
Also you need use ~ for class interpolation, not to return the class names between quotation marks.
Edit: The above will only work in 1.3.3, but for your approach to work in 1.4 you need to tweak it a little. Also I noticed that the way you were joining the strings did not add commas between class names of each loop, so I added another step here, this should now do the right thing in1.4 and previous versions of LESS.
.populateGridClasses4(1,#num,#t1) {
#test: ~"#{t1}, .eh-grid-#{num}, .eh-mobile-grid-#{num}, .eh-tablet-grid-#{num}";
}
.populateGridClasses4(#index, #interval, #t1) when (#index > 1) {
#num: (#index * #interval);
#t2: "#{t1}, .eh-grid-#{num}, .eh-mobile-grid-#{num}, .eh-tablet-grid-#{num}";
.populateGridClasses4((#index - 1),#interval,#t2);
}
.populateGridClasses4(#index,#interval) {
#num: (#index * #interval);
#t2: ".eh-grid-#{num}, .eh-mobile-grid-#{num}, .eh-tablet-grid-#{num}";
.populateGridClasses4((#index - 1), #interval, #t2);
}
.populateGridClasses4(20, 5);
#{test} { padding-left: 1px; }
the output CSS is:
.eh-grid-100, .eh-mobile-grid-100, .eh-tablet-grid-100, .eh-grid-95, .eh-mobile-grid-95, .eh-tablet-grid-95, .eh-grid-90, .eh-mobile-grid-90, .eh-tablet-grid-90, .eh-grid-85, .eh-mobile-grid-85, .eh-tablet-grid-85, .eh-grid-80, .eh-mobile-grid-80, .eh-tablet-grid-80, .eh-grid-75, .eh-mobile-grid-75, .eh-tablet-grid-75, .eh-grid-70, .eh-mobile-grid-70, .eh-tablet-grid-70, .eh-grid-65, .eh-mobile-grid-65, .eh-tablet-grid-65, .eh-grid-60, .eh-mobile-grid-60, .eh-tablet-grid-60, .eh-grid-55, .eh-mobile-grid-55, .eh-tablet-grid-55, .eh-grid-50, .eh-mobile-grid-50, .eh-tablet-grid-50, .eh-grid-45, .eh-mobile-grid-45, .eh-tablet-grid-45, .eh-grid-40, .eh-mobile-grid-40, .eh-tablet-grid-40, .eh-grid-35, .eh-mobile-grid-35, .eh-tablet-grid-35, .eh-grid-30, .eh-mobile-grid-30, .eh-tablet-grid-30, .eh-grid-25, .eh-mobile-grid-25, .eh-tablet-grid-25, .eh-grid-20, .eh-mobile-grid-20, .eh-tablet-grid-20, .eh-grid-15, .eh-mobile-grid-15, .eh-tablet-grid-15, .eh-grid-10, .eh-mobile-grid-10, .eh-tablet-grid-10, .eh-grid-5, .eh-mobile-grid-5, .eh-tablet-grid-5 {
padding-left: 1px;
}

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);
}
}

Pass multiple property names, values and set them using one mixin. Is it possible?

Here is a ruleset in which I have my mixins, .greyMixin() and .disabled(). The problem is that I am unable to find a way to write multiple properties in one mixin. As one can see the result where color and background are separated. I want them in one declaration.
.formater(#className; #rules){
.#{className}{
#rules();
}
}
.greyMixin(#property, #g, #a:1){
#rgba: rgba(#g,#g,#g,#a);
.mixin();
.mixin() when((#a) < 1) and (#a > 0){
#{property}:#rgba;
}& when ((#a) = 1){
#{property}:#rgba;
}& when ((#a) = 0){
#{property}:#rgba;
}
}
.disabled(#property, #g, #a:1){
#rgba: rgba(#g,#g,#g,#a);
#rgb:rgb(#g,#g,#g);
.mixin();
.mixin() when((#a) < 1) and (#a > 0){
&:disabled,&.disabled {
&:hover,&:focus,&:active{
#{property}:#rgba;
}
}& when ((#a) = 1){
&:disabled,&.disabled {
&:hover,&:focus,&:active{
#{property}:#rgb;
}
}
}& when ((#a) = 0){
&:disabled,&.disabled {
&:hover,&:focus,&:active{
#{property}:#rgba;
}
}
}
}
}
.formater(colourclass;{
.greyMixin(color,25,1);
.greyMixin(background,110,0.8);
.disabled(color,240,0.8);
.disabled(background, 10,0.4)});
and the result is:
.colourclass {
color: #191919;
background: rgba(110, 110, 110, 0.8);
}
.colourclass:disabled:hover,
.colourclass.disabled:hover,
.colourclass:disabled:focus,
.colourclass.disabled:focus,
.colourclass:disabled:active,
.colourclass.disabled:active {
color: rgba(240, 240, 240, 0.8);
}
.colourclass:disabled:hover,
.colourclass.disabled:hover,
.colourclass:disabled:focus,
.colourclass.disabled:focus,
.colourclass:disabled:active,
.colourclass.disabled:active {
background: rgba(10, 10, 10, 0.4);
}
I am using less.js 2.5.3; Windows 7; Winless compiler 1.9.1.
For this case, you can use looping and array list like in the below snippet. As you can notice, the input parameters are all arrays instead of having just a single value. Within the mixin, we can use extract function to extract the property, its color value and alpha based on the index and then use the loops to create the properties.
Note: I didn't understand why you need those guards with the .mixin() because all cases seem to be setting the same property and output. So, I have removed it in the below snippet.
I have done the changes only for one mixin (.greyMixin) but you can do the same for the other mixin also.
.formater(#className; #rules){
.#{className}{
#rules();
}
}
.greyMixin(#properties; #g; #a:1){
#propCount: length(#properties);
.loop-properties(#index) when (#index > 0){
#property: extract(#properties, #index);
#col: extract(#g, #index);
#alpha: extract(#a, #index);
#rgba: rgba(#col,#col,#col,#alpha);
#{property}:#rgba;
.loop-properties(#index - 1);
}
.loop-properties(#propCount);
}
.formater(colourclass;{
.greyMixin(color, background;25, 110;1, 0.8);
});
earlier I had an issue where in the output I got
background: rgba(#646464,#646464,#646464,0.8);
so I removed the #col: rgba(#{col},#{col},#{col},#{alpha});
.colourMixin(#properties; #var){
#pcount:length(#properties);
.recurP(#index) when (#index > 0){
#property: extract(#properties, #index);
#colour: extract(#var, #index);
#{property}:#colour;
.recurP(#index - 1);
}
.recurP(#pcount);
}
now it is taking a variable.

& 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 {...}
...

SASS calculate column widths for grid

I have written this piece of code to calculate column widths for my grid system:
#mixin calc-width($index, $type) {
$column-calculation: (100% - ($gutter-width-procent * ($column-count - 1))) / $column-count;
$column-width: ($column-calculation * $index);
$gutter: ($gutter-width-procent * ($index - 1));
#if ($index > 0) {
#if ($type != 'width') {
#{$type}: $column-width + $gutter + $gutter-width-procent;
} #else {
#{$type}: $column-width + $gutter;
}
}
}
I am calling that up in a different function like this:
#for $index from 1 through $column-count {
&.size-#{$index} {
#include calc-width($index, 'width');
}
}
With the variables of:
$column-count: 12 !default; //12
$row-max-width: 1024;
$gutter-width-px: 15px !default; //In px
$gutter-width-procent: percentage($gutter-width-px / $row-max-width);
I like the system. But there is one thing that doesnt seem correct...
Can i do this line on another way, then substracting from 100%?
$column-calculation: (100% - ($gutter-width-procent * ($column-count - 1))) / $column-count;
I may be getting the wrong end of the stick here but if if you used box-sizing: border-box; and padding for your gutters then you wouldn't have to do any calculation. There's a great post about border-box here.
Not really sure, if this solves your problem, but i wouldn't create the grid gutters like that. You can easily create them if you use "box-sizing", a negative margin on the parent and a padding for every column. So your ("pseudo")-HTML could look like:
.parent
.column
.column
.column
And your CSS like that:
.parent {
margin-left: -GUTTER;
}
.child {
padding-left: GUTTER;
}
Your SASS function to create the widths for the columns could then be simplified as well. I made a pen to show you one way to solve your gutter problem.
This SASS function is just for testing and doesn't check for duplicates (.size1-2 (50%) and .size2-4) and other stuff.

Defining Variable Variables using LESS CSS

Say I have three separate color schemes that are used on various pages in a site. Each color has a a light, medium and dark tint defined, and the color scheme is defined by a class in the body. Assume that the "red" color scheme is the default. Like this:
Color Definitions:
#red-lt: #121;
#red-md: #232;
#red-dk: #343;
#green-lt: #454;
#green-md: #565;
#green-dk: #676;
#blue-lt: #787;
#blue-md: #898;
#blue-dk: #909;
Basic Default Style Example
body { background-color: #red-dk;
#container { background-color: #red-md;
p { color: #red-dk; }
}
}
Different Color Scheme Style Example
body.green { background-color: #green-dk;
#container { background-color: #green-md;
p { color: #green-dk; }
}
}
I'd like to use variables so that I don't have to re-write all of the color variations for each scheme, so that I can just write something like this:
body.[color-var] { background-color: #[color-var]-dk;
#container { background-color: #[color-var]-md;
p { color: #[color-var]-dk; }
}
}
…but I can't quite wrap my head around how to accomplish that. Help…?
Use interpolation and escaping, parentheses in the selector and parametric mixins to get the desired effect:
Dynamic variables by interpolation: In a string, "#{variable}" is replaced with the value of the variable. They can also be nested: Given #{#{var}-foo} and #var: bar;, the result is "barfoo".
The resulting value is quoted. To remove these quotes, prefix ~.
Dynamic selectors by Selector interpolation: body.#{var} turns into body.bar.
Example:
#red-md: #232;
#red-dk: #343;
.setColor(#color) {
body.#{color} { background-color: ~"#{#{color}-dk}";
#container { background-color: ~"#{#{color}-md}";
p { color: ~"#{#{color}-md}"; }
}
}
}
.setColor(~"red"); // Escape to prevent "red" turning "#FF0000"
//.setColor(~"blue"); etc..
Turns into:
body.red {
background-color: #334433;
}
body.red #container {
background-color: #223322;
}
body.red #container p {
color: #223322;
}
Note: When the answer was originally written, selector interpolation did not exist. See the previous revision for the solution if you're working with an old LESS compiler (before LESS 1.3.1a). Support for the old method will be dropped in LESS 1.4.0.
If those values really follow a predictable format like that, seems like a perfect case for a parametric mixin:
Less:
#red: #232;
#green: #565;
#blue: #898;
.theme (#color) {
background-color: #color - #111;
#container {
background-color: #color;
p { color: #color + #111; }
}
}
body.red {
.theme(#red);
}
Compiled CSS:
body.red{background-color:#112211;}
body.red #container{background-color:#223322;}
body.red #container p{color:#334433;}
I know this question is pretty old, but for those that come to this post my answer maybe can help
I`m not really sure for what you want to use this, but one of my suggestion is based on #ScottS answer. On my real world, I need to create a web app, where it would show several brands and each brand have their own text color, background and so on... so I started to chase a way to accomplish this in LESS, what I could easily do on SASS and the result is below:
LESS
// Code from Seven Phase Max
// ............................................................
// .for
.for(#i, #n) {.-each(#i)}
.for(#n) when (isnumber(#n)) {.for(1, #n)}
.for(#i, #n) when not (#i = #n) {
.for((#i + (#n - #i) / abs(#n - #i)), #n);
}
// ............................................................
// .for-each
.for(#array) when (default()) {.for-impl_(length(#array))}
.for-impl_(#i) when (#i > 1) {.for-impl_((#i - 1))}
.for-impl_(#i) {.-each(extract(#array, #i))}
// Brands
#dodge : "dodge";
#ford : "ford";
#chev : "chev";
// Colors
#dodge-color : "#fff";
#ford-color : "#000";
#chev-color : "#ff0";
// Setting variables and escaping than
#brands: ~"dodge" ~"ford" ~"chev";
// Define our variable
.define(#var) {
#brand-color: '#{var}-color';
}
// Starting the mixin
.color() {
// Generating the loop to each brand
.for(#brands); .-each(#name) {
// After loop happens, it checks what brand is being called
.define(#name);
// When the brand is found, match the selector and color
.brand-#{name} & {
color: ##brand-color;
}
}
}
.carColor {
.color();
}
Te result will be:
CSS
.brand-dodge .carColor {
color: "#fff";
}
.brand-ford .carColor {
color: "#000";
}
.brand-chev .carColor {
color: "#ff0";
}
This is very tricky and I had to use several elements to get what I needed, first used a set of mixins provided by Seven Phase Max and you can find it here and than, the #ScottS answer was the piece that was missing fro my puzzle... hope this helps you and others that need to create a set of Variables to be part of another variable and create a more dynamic less file.
You can copy my entire code and test at http://lesstester.com/
Try this
#red-lt: #121;
#red-md: #232;
#red-dk: #343;
#green-lt: #454;
#green-md: #565;
#green-dk: #676;
#blue-lt: #787;
#blue-md: #898;
#blue-dk: #909;
#color: 'red-lt';
div{
background: ##color;
border: 1px solid lighten(##color,20%);
}
To my knowledge, variable variable names are not supported in LESS. You could however restructure your declarations in a more semantic manner:
/* declare palette */
#red-lt: #121;
#red-md: #232;
#red-dk: #343;
#green-lt: #454;
#green-md: #565;
#green-dk: #676;
#blue-lt: #787;
#blue-md: #898;
#blue-dk: #909;
/* declare variables based on palette colors */
#lt: #red-lt;
#md: #red-md;
#dk: #red-dk;
/* ...and only use them for main declarations */
body { background-color: #dk;
#container { background-color: #md;
p { color: #dk; }
}
}
This should let you switch between palettes quite painlessly by avoiding explicit color references.

Resources