1

One feature I really love with LESS is nested rules. It makes the stylesheet much cleaner that way and you can find an element very quickly.

I was wondering if there's an option when compiling to optimize selectors. For example...

#global { /* Styles here maybe */ .container { /* Styles here maybe */ #sidebar { /* Styles here maybe */ .title { font-weight: bold; } } } } 

will be compiled to #global .container #sidebar .title { font-weight: bold; }.

But the first two selectors are useless, since #sidebar should be unique in my page.

Is there a way to ask LESS to compile this to #sidebar .title { font-weight: bold; } instead?

6
  • 3
    Your proposition is incorrect; such a selector is useful to exclude pages or states in which the outer ID isn't there but the inner one is. Commented Sep 19, 2014 at 15:36
  • Additionally, specifying multiple IDs might elevate a rule's priority, in case there is also a #myTitle { font-weight: 300; } property (only one ID). When you work with ID-obsessive developers like me, it's useful to have those. Commented Sep 19, 2014 at 15:37
  • 4
    LESS can't assume that #sidebar will always occur as #global .container #sidebar in a given page even if it's unique within that page, which is why it doesn't try to remove the first two selectors by default. But the real question is, why would you nest it there in the first place? This seems more like an authoring mistake than a preprocessor limitation. Commented Sep 19, 2014 at 15:37
  • You're worried about a few milliseconds or perhaps even tenths of seconds of CSS performance optimization? You have nothing else to worry about? Besides the fact that as other posters mention it is somewhere behind impossible, a bad idea, dangerous, and semantically destructive? Commented Sep 19, 2014 at 15:43
  • 1
    @SamuelBolduc don't worry, it's just a wrong assumption. I upvoted the question actually because I highly doubt you're the first or last person to think about this. The question is well founded and well asked, and you learnt something. Perhaps others will as well :) Commented Sep 19, 2014 at 15:52

2 Answers 2

4

Your assumption is wrong that multiple IDs in CSS are redundant. Imagine, as an example, a site where the CMS generates the page type into the output, like that it's the contact page:

<body id="contact"> <section id="content">Blah</section> </body> 

According to your logic, the following piece of CSS would be a candidate for 'optimization':

#contact #content { background:red; } 

Now however, your home page has <body id="home"> of course in this imaginary CMS. And suddenly the content of your homepage has a red background because you decided to erroneously optimize that #contact selector out of the CSS, while it most certainly shouldn't have a red background according to this rule.

So no, LESS cannot do this because it would break code. If you don't want the selectors, don't use them and don't put them in your code.

Sign up to request clarification or add additional context in comments.

1 Comment

Or move the inner rulesets out, if you need the outer ones for other things.
4

Other answers, including the accepted one, have explained convincingly why LESS cannot simplify your nested selectors in the way you want.

Actually, SASS has the ability to do this:

#global { .container { @at-root #sidebar { .title { font-weight: bold; 

The @at-root directive essentially ignores all the higher nesting selectors. I don't know if LESS has something similar. The above compiles into simply

#sidebar { .title { font-weight: bold; 

But there is a deeper issue here, starting with the fact that you "love" nested rules in LESS. Stop loving them quite so much. I don't know about you, but most people love nested rules because they think it's cool to exactly mimic the hierarchical structure of their HTML. The SASS docs even claim this as a benefit:

Sass will let you nest your CSS selectors in a way that follows the same visual hierarchy of your HTML.

So people with HTML such as

<div class="foo"> <ul> <li class="item"> 

write LESS like

.foo { ul { li.item { 

This is a horrible, horrible idea, It makes the structure of CSS completely dependent on the structure of the HTML. If you change one nesting level in the HTML, your CSS breaks. Often this approach is combined with a lot of rules defined against tag names such as ul instead of class names, which aggravates the dependency, so changing the ul to ol in the HTML breaks the rules again. Or it's combined with rules based on Bootstrap classes such as col-md-6, so if you ever change that to col-md-4 things break again.

CSS rules should be orthogonal to the HTML. They represent a different dimension. They represent styling concepts which are applied selectively throughout and across the HTML.

I am guessing that you wrote

#global { .container { #sidebar { .title { font-weight: bold; 

because you are adopting this mistaken idea of mirroring the HTML structure in your LESS. Then, you notice that this compiles down to having selectors which contain multiple IDs, which you imagine must be inefficient (although, actually, the degree of inefficiency is minimal). You yourself are writing extraneous nesting levels in your LESS, then complaining that they may be slowing down performance!

Worse, you've hard-wired assumptions about the HTML structure into your CSS. It's of no consequence that the sidebar happens to fall inside a .container which is inside a global element. So don't write them. Perhaps at some point you decide to change the container class to container-fluid. Boom, instantly your CSS breaks. What is the point of conditionalizing the fact that the title should be bold on it being contained with a container class, which in any case is a layout-related class that has (or should have) nothing to do with styling? If you're going to duplicate your HTML structure in your CSS using preprocessor nesting, just go back to writing inline styles. At least that way you'll only have one file to change when you change your HTML around.

When designing CSS, you should think just as hard about the design of the rules as you do about the design of classes and methods when writing JS. In this case, you need to ask yourself, "What characterizes the situation where I want some title to be bold? What drives that? What is the nature of boldness? What am I indicating by boldness? What is the semantic notion indicated by boldness?"

Let's say that you want all titles to be bold. Then you simply say that:

.title { font-weight: bold } 

Let's say that you want a title to be bold only when it's in the sidebar. Then you simply say that:

#sidebar .title { font-weight: bold; } 

My suggestion here is to go cold turkey. Stop using nesting during a withdrawal period. Write rules with the minimum number of selector components. Refactor your classes to have semantic names (such as title-emphasis). Once you're "sober", you can go back to cautiously using LESS's nesting capability when it is useful, such as perhaps for hover:

#boo { color: red; &:hover { color: blue; } } 

This is actually useful and saves you from writing #boo twice, and groups the rules in an easy-to-understand way.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.