Validity of .LESS code - less

I got a .less file and it has codes written in this fashion:
.btn-form{
.button-toggle( #brand-black; #brand-white; #btnform-color; #btnform-hover-color; #border-color);
}
What does this code mean?

In your example, .button-toggle is a mixin, declared elsewhere in your code (possibly an imported Less file). The declaration might be something like:
.button-toggle(#brand-black; #brand-white; #btnform-color; #btnform-hover-color; #border-color) {
background: #btnform-color;
color: #brand-black;
&:hover {
background: #btnform-hover-color;
color: #brand-white;
}
border-color: #border-color;
// other CSS properties or nested selectors
}
It receives as parameters several variables, which should also be declared somewhere before you call the mixin, like:
#brand-black: black;
#brand-white: #fff;
#btnform-color: blue;
#btnform-hover-color: red;
#border-color: rgb(255,255,0);
You are calling the mixin when you place it inside a block, as you did, and it will generate CSS according to its definition and the parameters you are passing.
For example, if you call your code block preceded by those variable declarations and the mixin declaration I included above in a LESS compiler such as the online service http://lesstester.com/ you will get this CSS result:
.btn-form {
background: #0000ff;
color: #000000;
border-color: #ffff00;
}
.btn-form:hover {
background: #ff0000;
color: #ffffff;
}

Related

Can whole declaration be stored as #variable value in Less?

All my Less variables are editable within a CMS-module and are assigned to the Less compiler. It works, if I only use the values like color, font-size, etc.:
body {
background-color: #bgColor;
}
I've created another field for custom Less, which I would like to add at the end of my Less file, like:
body {
background-color: #bgColor;
}
#customLess /* desired OUTPUT: body { color: white; }*/
Unfortunately this leads to an ParseError.
I'd like to avoid to merge the existing Less and custom Less. I'm not looking for mixins, I guess.
Is it possible to put whole declarations in a #variable?
It is very much possible to put whole declarations (including the selector, property + value pair) inside a variable. Those are called as detached rulesets.
While calling them, braces (()) must be added. If not, the call will fail and result in compilation error. Below is an extract from the official website.
Parentheses after a detached ruleset call are mandatory. The call #detached-ruleset; would NOT work.
#customLess: {
body{
color: white;
}
};
#bgColor: red;
body {
background-color: #bgColor;
}
#customLess();

Possible to reference extended property in less?

Is it possible to extend a extended property in less? I have definitions in one (distributed) file and need to add !important to the existing property in my special case.
As example I have a less file defining this class
.pfx-grey-light-bg {
background-color: #e5e5e7;
}
I'd like to reference this less file now but extend the color to important
.pfx-metro-orange-dark-bg:extend(.pfx-orange-dark-bg){
//Pseudo code
//background-color: &extended.backgroundColor !important
}
The result should be
.pfx-metro-grey-light-bg {
background-color: #e5e5e7 !important;
}
No, you cannot extend a single property alone in that way. You can extend the whole ruleset but when you extend, the selectors are combined and so the !important would have to apply either to both the selectors or to none.
In your case the property values are different and hence the selectors cannot be grouped together. However, if the background-color is the only property within the original class that you wish to be applied to the derived class (or) if you wish to apply all properties of the original class to the derived class and append !important to all of them then you can use the below.
.pfx-grey-light-bg {
background-color: #e5e5e7;
}
.pfx-metro-orange-dark-bg{
.pfx-grey-light-bg !important;
}
When compiled, it would produce the following output:
.pfx-grey-light-bg {
background-color: #e5e5e7;
}
.pfx-metro-orange-dark-bg {
background-color: #e5e5e7 !important;
}
Or, if your base class has multiple properties and you want to apply only the background-color to the derived class, then you have three options as follows:
Option 1: Use variables
#color: #e5e5e7;
.pfx-grey-light-bg {
background-color: #color;
color: #fff;
}
.pfx-metro-orange-dark-bg{
background-color: #color !important;
}
Option 2: Write a dummy mixin and use it like below. This will not cause any extra lines of code in the output CSS because the mixin has parentheses and hence will not be output.
.dummy-mixin(){
background-color: #e5e5e7;
}
.pfx-grey-light-bg {
.dummy-mixin;
color: #fff;
}
.pfx-metro-orange-dark-bg{
.dummy-mixin !important;
padding: 10px;
}
Option 3: More complex using guarded mixins and an optional #important parameter to decide on whether to append !important or not. I would not recommend this unless you have very pressing needs.
.dummy-mixin(#color, #important: no){
& when (#important = no){
background-color: #color;
}
& when (#important = yes){
background-cokor: #color !important;
}
}
.pfx-grey-light-bg {
.dummy-mixin(#e5e5e7);
color: #fff;
}
.pfx-metro-orange-dark-bg{
.dummy-mixin(#e5e5e7; yes);
padding: 10px;
}

Less mixin and variables

I have the following mixin:
.iconFont(#color: #green, #font-size: 18px){
color: #color;
font-size: #font-size;
}
If I want only to change the second variable value, I need to write the first variable default value?
h1{
.iconFont(#green, 14px);
}
No, there is no need to specify the default value for the first parameter while calling the function. Instead you can just use named parameters feature to explicitly let the compiler know that the value you are passing in the mixin call is for the 2nd parameter.
.sample{
.iconFont(#font-size:14px);
}
The above Less code when compiled would produce the below output. (Note: I had set the #green as #00ff00.)
.sample {
color: #00ff00;
font-size: 14px;
}
While using the named parameter feature, even the order in which the parameters are passed does not matter. For example, the same mixin can be called as follows:
.sample2{
.iconFont(#font-size:24px, #color: #070707);
}
And it would produce the below as output.
.sample2 {
color: #070707;
font-size: 24px;
}

Change variable used in mixin depending on scope

In the Lazy Loading section of the Less language features, it states:
When defining a variable twice, the last definition of the variable is used, searching from the current scope upwards. This is similar to css itself where the last property inside a definition is used to determine the value.
I'd like to overwrite a global variable, but this doesn't seem to work:
#border: #fff;
.table {
border: #border;
}
.table-summary {
#border: #000;
.table
}
Compiles to
.table {
border: #ffffff;
}
.table-summary {
border: #ffffff; // I want this to be #000
}
Currently the global scope has higher precedence than caller scope for a mixin (unless the mixin is defined inside parametric namespace). For more more details see #1316, some people consider this is a bug but there's no well-defined agreement on that.
Either way, the recommendation is to minimize use of non-parametric mixins and to not rely on indirect parameter passing whenever possible. Your example is a perfect use-case for a parametric mixin (even if your the code becomes slightly more verbose):
#border-default: #fff;
.table-base(#border: #border-default) {
border: #border;
}
.table {
.table-base;
}
.table-summary {
.table-base(#000);
}
Alt. if for some reason you can't modify the .table class (for example if it's defined in an external library) then just forget about any variables and override the property directly, the most optimal way would be:
#border: #fff;
.table {
border: #border;
}
.table-summary:extend(.table) {
border-color: #000;
}
---
Technically, there's method to achieve what you want with the code quite close to your original snippet but I doubt it is something to be really recommended:
#border: #fff;
.table {
border: #border;
}
.-;.-() { // dummy parametric namespace
.table-summary {
#border: #000;
.table;
}
} // end of dummy parametric namespace

LESS condition based on CSS class to set a LESS variable

I need to set a Less variable to match the website's active theme, ie, each theme has a different color.
I'd like to set #themeColor to the right color, based on the HTML's body CSS class that defines the theme.
For example:
body.themeBlue { #themeColor: blue; }
body.themeRed { #themeColor: red; }
This way I'd only need to use the #themeColor variable inside the other Less files.
Can anyone help?
According to this (http://www.lesscss.org/#-scope) it is possible to do something like that, but I can't make it work. what is going on here?
The LESS file cannot read the actual class applied to the html body element at run time (you would probably need to implement a javascript solution to do something like that).
If you just want to have all themed css ready for use based on the body class, the best way to implement this to have all the necessary theme based css in a mixin, then apply it under the theme classes. This reduces code duplication. For example:
LESS
//mixin with all css that depends on your color
.mainThemeDependentCss() {
#contrast: lighten(#themeColor, 20%);
h1 {color: #themeColor;}
p {background-color: #contrast;}
}
//use the mixin in the themes
body.themeBlue {
#themeColor: blue;
.mainThemeDependentCss();
}
body.themeRed {
#themeColor: red;
.mainThemeDependentCss();
}
CSS Output
body.themeBlue h1 {
color: #0000ff;
}
body.themeBlue p {
background-color: #6666ff;
}
body.themeRed h1 {
color: #ff0000;
}
body.themeRed p {
background-color: #ff6666;
}
For some other answers that deal with aspects or ways of theming, see:
LESS CSS - Change variable value for theme colors depending on body class
LESS.css variable depending on class
LESS CSS: abusing the & Operator when nesting?
Variables in Less are actually constants and will only be defined once.
Scope works within its code braces, so you would need to nest your CSS within each theme you want (which means duplication).
This is not ideal as you would need to do this:
body.themeBlue {
#color: blue;
/* your css here */
}
body.themeRed {
#color: red;
/* your css here AGAIN :( */
}
You could, however, try to use variables like this:
#color: black;
#colorRed: red;
#colorBlue: blue;
h1 {
color: #color; // black
body.themeRed & {
color: #colorRed; // red
}
body.themeBlue & {
color: #colorBlue; // blue
}
}
You would only need to declare the colours once, but you would need to constantly do the "body.themeRed" etc. prefixes where the colour varies depending on the theme.
You could actually use #import to load your theme! So common.less would contain all your default styles and #themeColor will be applied to it.
.mainThemeDependentCss() {
//file with all themed styles
#import 'common.less';
}
//use the mixin in the themes
body.themeBlue {
#themeColor: blue;
.mainThemeDependentCss();
}
body.themeRed {
#themeColor: red;
.mainThemeDependentCss();
}
BTW you should avoid using body selector in your common.less, because it wouldn't work.