Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Referencing parent with multiple levels of nesting in LESS

Tags:

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.

like image 257
NoobsArePeople2 Avatar asked Jan 23 '13 05:01

NoobsArePeople2


1 Answers

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...
        }
    }
}
like image 103
ScottS Avatar answered Sep 26 '22 04:09

ScottS