How to use the default variable for only one of a few variables in less - variables

Here is my mixin
.test(#color:black; #width:100px; #height:50px) {
width:#width;
height:#height;
background:#color;
}
Here is where it's called later
.mydiv {.test('use-mixin-color'; 300px; 150px);}
How can I override the size of .mydiv, while using the color defined in the mixin?
Everything I have tried overrides the mixin color.

To Use mixin in LESS, pass those parameter to override mixin default value :
Soluations :
.test(#color:black; #width:100px; #height:50px) {
width : #width;
height : #height;
background : #color;
}
.mydiv {
.test(#width : 300px; #height : 150px);
}
OUTPUT :
.mydiv {
width: 300px;
height: 150px;
background: black;
}
Helpful :)

In addition to the accepted answer. There're multiple methods (actually infinite) but if you want your mixin to be most easy for use you can provide a "specialization" for a specific argument value or number of arguments. Like this for example:
// usage:
.foo {.test(red, 1px, 2px)}
.bar {.test(3px, 4px)}
// impl.:
.test(#color, #width, #height) {
width: #width;
height: #height;
background: #color;
}
.test(#width, #height) { // <- "no color" specialization
.test(black, #width, #height);
}
Demo.
Also think twice before adding default parameter values for a mixin like:
.test(#color: black, #width: 100px, #height: 50px) { ...
People tend to overuse this feature while it's rarely really necessary (and only creates an extra code-noise) except some specific use-cases.
I.e. consider if you actually expect your mixin to be invoked as:
test;
test(blue, 4em);
// etc.
Do you?
It's usually a good idea to start without default parameter values (at least to protect the mixin against accidental misuse), i.e.:
.test(#color, #width, #height) { ...
and add them later only where and when they are necessary.

Related

How to achieve '.class1.class2' in CSS output with no space in between

In CSS '.class1.class2' with no space between classes means:
'Select only those elements that have AT LEAST those 2 classes';
How can I declare that in LESS?
What I am getting at is:
Class featureCheckbox is declared below ...
.featureCheckbox
{
float: left;
margin-bottom: 6px;
height: 30px;
width: 300px;
font-size: 16px;
}
I wish to override 'width: 300px' with 'width: 150px' for elements that only have class="featureCheckbox class2" whilst picking up the other non-width rules associated with class featureCheckbox.
Use & to reference the current selector.
.featureCheckbox {
// styles
&.class2 {
// overrides
}
}
This will compile to:
.featureCheckbox {
/* styles */
}
.featureCheckbox.class2 {
/* overrides */
}
You can use & character for this as below:
.featureCheckbox{
&.class2 {}
}
Less is backwards compatible to CSS, basic CSS selectors work identically in LESS.
Just write
.featureCheckbox.class2 {
...
like you would in CSS.

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

Overriding mixins in LESS

when defining a mixin multiple times in LESS, and later calling that mixin as follows
.background-color() {
background: red;
}
.background-color() {
background: yellow;
}
body {
.background-color;
}
the result will be a combined output from all the defined mixins
body {
background: red; // << output from mixin #1
background: yellow; // << output from mixin #2
}
while when you apply the same scenario in both Sass & Stylus ( using their own syntax of course ), when you call a mixin that is defined multiple times across your stylesheets, Only the last defined one will be executed ( it will override all previously defined mixins ) as follows.
result Sass and Stylus
body {
background: yellow; // << output from mixin #2
}
how can I override a mixin in LESS so that the output will be from the last defined mixin ?
You can not override them, alternatively use a variable to define the 'background-color'. For Less variables the last declared win.
Also read Pattern-matching
In Less all matching mixins are compiled in the source. You can use namespace to prevent name collisions, for instance:
#ns1 {
.background-color() {
background: red;
}
}
#ns2 {
.background-color() {
background: yellow;
}
}
than you can use:
body {
#ns2 > .background-color;
}
Double properties are also not removed to make some browser hacks possible, example:
#myElement {
width: 300px;
width: 500px\9;
}
To find a solution for your use case you should reformulate your question and explain why you have these same named mixins in the first place.

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.