Dynamically Define a Variable in Less CSS

Dynamically define a variable in LESS CSS

This Cannot Be Done

What you desire to do is not currently possible in LESS. I can think of two possible "workarounds" if you know ahead of time what variable names you want to allow to be used (in other words, not fully dynamic). Then something like one of the following could be done:

Idea #1 (Variable Variables)

.define(@var) {
@fooBar: 0;
@fooTwo: 2;
@fooYep: 4;

@fooSet: 'foo@{var}';
}

.define(Two);
.test {
.define(Bar);
prop: @@fooSet;
}
.test2 {
prop: @@fooSet;
}

Idea #2 (Parametric Mixins)

LESS

.define(@var) {
.foo() when (@var = Bar) {
@fooBar: 0;
}
.foo() when (@var = Two) {
@fooTwo: 2;
}
.foo() when (@var = Yep) {
@fooYep: 4;
}
.foo();
}

.define(Two);
.test {
.define(Bar);
prop: @fooBar;
}
.test2 {
prop: @fooTwo;
}

CSS Output (for both ideas)

.test {
prop: 0;
}
.test2 {
prop: 2;
}

Conclusion

But I'm not sure how useful either would really be, nor do I know if it could have any real application in your actual use case (since you mention the above is not the real use case). If you want a fully dynamic variable in LESS, then it cannot be done through LESS itself.

Dynamic Variable Names in LESS CSS

You can use Variable Names. And I've tested the code at http://lesstester.com/, it works.

@horizontal-default-color: #fff;
@horizontal-inverse-color: #000;

.horizontal-variant(@variant) {
@color: "horizontal-@{variant}-color";
color: @@color;
}

.horizontal-default{
.horizontal-variant(default);
}
.horizontal-inverse{
.horizontal-variant(inverse);
}

Defining Variable Variables using LESS CSS

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.

less css calling dynamic variables from a loop

I have just been trying todo the same thing today with LESS. The solution I came up with is to use a Parametric Mixin to create (define) the variable, see updated exmaple:

@color1:#06A1C0;
@color2:#8F4F9F;
@color3:#ED1D24;
@color4:#5A9283;
@color5:#B38C51;
@color6:#EC008C;
@color7:#8F4F9F;

@iterations: 7;

.define(@var) {
@colorSet: 'color@{var}';
}

.mixin-loop (@index) when (@index > 0) {
color@{index}:hover{
.define(@index);
color: @@colorSet;
}

.mixin-loop(@index - 1);
}
.mixin-loop (0) {}
.mixin-loop(@iterations);

Hope this helps.

Dynamic LESS mixin

So there are basically two parts to this question. The first is how to dynamically interpolate your variable names in your mixin, and the second is how to figure out if the variable you interpolated even exists.

The first part can be done like so:

@body-margin: 50px;

.spacing(@id) {
margin: ~"@{@{id}-margin}";
}

If you do that, then using

body {
.spacing('body);
}

Will give you your expected CSS output of

body {
margin: 50px;
}

Read more about that here: Defining Variable Variables using LESS CSS.

The second part, determining whether the interpolated variable even exists, I don't think you can do in LESS. You are going to have to define all possible variables ahead of time, but that doesn't mean you can't get clever with how you define those variables.

Say you don't want to define a variable for @body-padding-mobile. In that case, you can do one of two things, whichever you think is more helpful for you.

The first is that you could set the variable value equal to whatever the default value is in CSS (0, in the case of padding), or else just initial.

Or, if you're afraid that will mean you end up overwriting styles you don't want to overwrite, the more hacky solution is to just make the variable equal to an invalid value, so the browser never applies the style. For example: @body-padding-mobile: fishsticks.


Assuming you've declared all the variables you need for the mixin, you can use this mixin to get what you want:

.spacing(@id) {
margin: ~"@{@{id}-margin}";
padding: ~"@{@{id}-padding}";
@media (max-width: 900px) {
margin: ~"@{@{id}-margin-tablet}";
padding: ~"@{@{id}-padding-tablet}";
}
@media (max-width: 500px) {
margin: ~"@{@{id}-margin-mobile}";
padding:~"@{@{id}-padding-mobile}";
}
}

So if we start with this:

@body-margin: 50px;
@body-margin-tablet: 30px;
@body-margin-mobile: 20px;

@body-padding: 150px;
@body-padding-tablet: 130px;
@body-padding-mobile: 0;

body {
.spacing('body');
}

We'll get this:

body {
margin: 50px;
padding: 150px;
}
@media (max-width: 900px) {
body {
margin: 30px;
padding: 130px;
}
}
@media (max-width: 500px) {
body {
margin: 20px;
padding: 0;
}
}

Dynamic Variable Names with Less

use:

@cyan:    "cyan-@{palette}";
p{
color: @@cyan;
}

or

    @whitename: "white-@{palette}";
@white: @@whitename;

p{
color: @white;
}

Pass dynamic variable from HTML to less.css file

I would recommend you to do something like the following:

  • Give the user a pre-defined list of theme colors to choose from (a drop-down maybe). Don't allow for entering any color they wish to, that would be a pain.
  • When the select any color append, the color name to the body as a class using jQuery/JS.
  • In Less, write the below code, compile it statically and link the compiled CSS to your page.

    body { 
    background-color: red; /* default */
    &.red {background-color: red;}
    &.green{background-color: green;}
    &.blue{background-color: blue;}
    }

window.onload = function() {

document.querySelector('#color-chooser').addEventListener('change', function() {

document.body.className = this.value;

});

}
/* compiled CSS based on the Less code provided above */

body {

background-color: red;

/* default */

}

body.red {

background-color: red;

}

body.green {

background-color: green;

}

body.blue {

background-color: blue;

}
<label>Select Background Color:</label>

<select id='color-chooser'>

<option value='red'>Red</option>

<option value='blue'>Blue</option>

<option value='green'>Green (Hex)</option>

</select>

Resolving dynamic variables in LESS

Missing Brackets

You are missing a set of needed brackets to resolve the variable:

LESS

//imported from another file
@button-primary: cyan;
@button-success: green;
@button-info: orange;
@button-warning: yellow;
@button-danger: red;

//in your mixin file
.loop-class(~"primary", ~"success", ~"info", ~"warning", ~"danger";);
.loop-class(@list, @index: 1) when (isstring(extract(@list, @index))) {
@status: extract(@list, @index);

.button-@{status} {
color: ~'@{button-@{status}}'; /* two more brackets needed */
| |
here here
}
.loop-class(@list, (@index + 1));
}

CSS Output

.button-primary {
color: #00ffff;
}
.button-success {
color: #008000;
}
.button-info {
color: #ffa500;
}
.button-warning {
color: #ffff00;
}
.button-danger {
color: #ff0000;
}

Cleaner More Friendly Code

Also, as a matter of less cluttered and more user friendly code, you can remove your multiple string interpolations needed for the mixing call by changing isstring to iskeyword in your mixin:

.loop-class(primary, success, info, warning, danger;); /* cleaner code on call */
.loop-class(@list, @index: 1) when (iskeyword(extract(@list, @index))) {
@status: extract(@list, @index);

.button-@{status} {
color: ~'@{button-@{status}}';
}
.loop-class(@list, (@index + 1));
}


Related Topics



Leave a reply



Submit