Referencing parent with multiple levels of nesting in LESS - less

I have the following LESS:
.container {
.column, .columns {
.one& {
width: 40px;
}
}
}
When I compile I'm getting the following for my CSS:
.one.container .column,
.one.container .columns {
width: 40px;
}
But I expected to get:
.container .one.column,
.container .one.columns {
width: 40px;
}
It appears the parent operator (&) in LESS is actually referencing what I'd expect to be the grandparent. Am I nesting things properly? The docs don't show any examples of nesting more than one level deep. Can I achieve my desired output with nesting?
I'm using lessc 1.3.3 installed via npm.

It's important to think of & as more of a "parentage" combinator, rather than a "parent" combinator. That is, it takes the whole nested string of selectors up to that point (no matter how many levels deep) and acts as the equivalent of a string replacement holder. So with a reduced version of your example...
.container {
.column {
.one& {
width: 40px;
}
}
}
...the selector string at that level is .container .column. This is what is "replaced" in the position of the &, so when you concatenate to the beginning as you do above, it gets attached at the beginning of the whole selector string and you end up with your:
.one.container .column {width 40px;}
But if you concatenate from the end (no space between & and .) then...
.container {
.column {
&.one {
width: 40px;
}
}
}
...becomes:
.container .column.one {width 40px;}
This last one is really the class combination you want, though just not quite in the same order you were hoping for. But order does not matter to the browser, .one.column or .column.one are the same, it just means an element that has both individual classes applied to it like so:
<div class="column one"></div>
<div class="one column"></div>
Both of those are equivalent, and either .one.column or .column.one as a selector is going to select both elements, because both elements have both classes.
If order is absolutely vital to you (you just must have your generated CSS be as you are seeking), then you would need to do a bit of repetition like this:
.container {
.column {
...generic column code here...
}
.one {
&.column {
width: 40px;
...any other code dependent on combination of .one.column here...
}
}
}

Related

LESS: how to convert a list of called mixins to a for loop with a unique call

I crated many mixins to generate different kinds of classes for various purposes. Specifically I have to use a unique colorizer set using the standard bootstrap variable name, such as (only an example):
#type-primary: #fff;
#type-success: #f00;
#type-info: #ff0;
#type-default: #000;
#type-warning: #0f0;
#type-danger: #0ff;
Actually I created my mixins in the following form, with a "mother" as prefix to which I attached various suffixes
.text
{
&-primary { .color_text(#type-primary); }
&-success { .color_text(#type-success); }
&-info { .color_text(#type-info); }
&-default { .color_text(#type-default); }
&-warning { .color_text(#type-warning); }
&-danger { .color_text(#type-danger); }
}
After this, I can then create the final called mixin such as (so simple because it's only an example)
.color_text (#color)
{
color:#color;
}
I woud like to automate and optimize .text mixin to avoid many repeated rows, I think with a for loop. How could be possible?
Final results should be (in this case)
.text-primary {
color: #fff;
}
.text-success {
color: #f00;
}
.text-info {
color: #ff0;
}
.text-default {
color: #000;
}
.text-warning {
color: #0f0;
}
.text-danger {
color: #0ff;
}
In PSEUDO-CODE something like this could be ideal
#type-primary: #fff;
#type-success: #f00;
#type-info: #ff0;
.createContextClass("classNamePrefix",{#type-primary,#type-success,#type-info},mixinToBeCalled);
// Another call could be
.createContextClass("otherClassNamePrefix",{#type-primary,#type-success},otherMixinToBeCalled);
where, in relation to my original code, classNamePrefix should be the name of first part of final CSS class, then is passed an array with all kind of suffix that I wish in final CSS code, and mixinToBeCalled is the mixin that creates all css rules for final .text-primary, .text-success, .text-info.
For the moment, following Seven-Phases-Max' suggestion, I improved his solution in the following way

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.

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.

How can I target an element within a class using less?

I would like to target specific elements within a class using less.
In this case, I would like to target elements of class button, but within that I would like to target an anchor tag a.
Currently I have:
.button {
/* lots of bits and pieces go here, hence
the need to keep it at a class level
*/
/* further down, but still in .button */
/* Attempt 1 - fails: compiled = a .button (note the space)
a& {
height:20px;
}
/* Attempt 2 - fails: compiled = .buttona
&a {
height:20px;
}
}
I basically want it to compile to:
a.button
This is so I can create elements such as:
<a class="button">
<button class="button">
But slightly alter it when its an anchor. I don't want to throw in the it's a bug in less! card too early, but if I use &.another-class it works as expected (compiled: .button.another-class, but not when targeting elements
You're using an old version of less. The code below generates the correct CSS using less 1.3.3
.button {
a& {
height:20px;
}
}
generates:
a.button {
height: 20px;
}
#Allen Bargi answer is correct, yet only for this specific scenario. I am a little confuse about what you want to achive.
As #Allen Bargi pointed out, this will target "a" lements with a "button" class and generates a
.button {
a& {
height:20px;
}
}
It generates:
a.button {
height: 20px;
}
Meanwhile, this below will target "a" elements contained whitin an element with a "button" class. which seems to me was your original objective.
.button {
a {
height:20px;
}
}
It generates:
.button a {
height:20px;
}
Both solutions migt work fine in this case because you are using the same "button" class for both the parent and the child elements, but they are not targeting the same elements.
I hope this helps.

Reusing LESS nested styles

Let's say that I have a style defined using Less:
ul.unstyled,
ol.unstyled {
margin-left: 0;
list-style: none;
}
Later on, I want to re-use the unstyled class:
.my-list {
.unstyled;
}
This doesn't work, however, and I can't figure out the magic to make it work. Any thoughts?
You can't re-use arbitrary class definitions, only mixins (those starting with a dot). In this case you'll need to duplicate it.
Try this:
.unstyled {
margin-left: 0;
list-style: none;
}
.my-list {
.unstyled;
}
You won't be able to nest .unstyled if it's defined as ul.unstled and ol.unstyled.
Since you can't reuse .unstyled when it's a nested style and you probably don't want to edit the Bootstrap source code, I'd suggest you just assign both classnames to your list:
<ul class="unstyled my-list" />