Nesting Selectors - Possible

Is there a way to nest CSS selectors?

With the current CSS (2.1) version, nesting selectors isn't possible.

You'll have to use something called a CSS preprocessor which does several things, including allowing nested selectors.

I'd recommend SASS (SCSS), and another out there is LESS. You'll need some extra things setup on your PC/Mac for automatically converting preprocessor files to regular CSS files - plenty of other questions and research points on that out there.

If you use SCSS, you can check out what its like on SassMeister so you can see what the nested selectors will look like compiled.

Nesting selectors - possible?

Nesting CSS selectors is not possible with standard CSS, but there are other tools like SASS, LESS, and XCSS which allow you to write rules in the way you're describing.

These tools generally "compile" into real CSS which handles converting the nested selector syntax into real CSS rules.

Nesting CSS selectors without increasing specificity

These days, in 2018, this is getting close to possible.

First of all, CSS4 will have a way that allows you to create more specific selectors without increasing specificity:

:where(.special-section) p {
color: red;
}

This will set the paragraph color inside .special-section to red, but with a specificity of 001 (i.e. the same specificity that a plain p selector would have).

The spec still calls this special pseudo-class :something(), but chances are it's going to be called :where(). (Side note: I really want this to be known as the "honey badger selector").

But that's still in the future.

However, there is actually a way to achieve this today, if you don't have to support IE anymore (or are happy with less-than-perfect fallbacks), and that is by using custom properties a.k.a. CSS variables.

So you want this:

.special-section p { color: red; }
.weird-font { color: magenta; }
p { color: green; }

but with the first part having a specificity that's lower than any selector with a class in it. You can do it like this:

.special-section p { --low-specificity-color: red; }
.weird-font { color: magenta; }
p { color: var(--low-specificity-color, green); }

If you run the below snippet in a modern browser, you should notice that the second paragraph is red, because it's in a special section, but the third paragraph is magenta, because it's .weird-font -- even though .weird-font has 010 specificity and .special-section p has 011.

.special-section p { --low-specificity-color: red; }.weird-font        { color: magenta; }p                  { color: var(--low-specificity-color, green); }
<p>This is a paragraph.</p>
<section class="special-section"> <p>This is a paragraph inside a special section.</p> <p class="weird-font">This is a paragraph with a weird font inside a special section.</p></section>
<p class="weird-font">This is a paragraph with a weird font.</p>
<div class="weird-font">This is a div with a weird font.</div>

nesting inside css :not() selectors

:not() only accepts one simple selector at a time; this is mentioned in the Selectors 3 spec:

The negation pseudo-class, :not(X), is a functional notation taking a simple selector (excluding the negation pseudo-class itself) as an argument. It represents an element that is not represented by its argument.

The simple selectors in your example would be the two div tokens that you have. Other simple selectors include class selectors, ID selectors, attribute selectors and pseudo-classes. It does not accept more than one simple selector, nor does it accept combinators like > or space.

Depending on which elements you're trying to select exactly, there may not be a way to exclude div > div:

  • If you only want to select elements that are children of a div, that are themselves not div, use this instead:

    div > :not(div)
  • If you only want to select div elements whose parent element is not a div, use this instead:

    :not(div) > div

If you want to use this negation by itself, selecting all other elements, then there isn't a way using just a selector.

The only other viable workaround in CSS that I can think of is to apply styles to the elements you want without the :not() expression, then undo them for div > div. This works for any set of elements you're trying to target; the disadvantage is that not all properties can be easily reset.

Alternatively, if you're using jQuery, which does support :not(div > div) unlike the CSS version, you can place the selector in a script and, for instance, have jQuery apply a class name to those elements then target that class in your CSS.

CSS Selector Nesting

No it is not. However, if you use Preprocessors like SASS or LESS (to name only the most popular ones) it is.

Depending on what you need, you should look into one of those. They are definitely worth it, since they can ease your work significantly not only with nesting selectors but also introducing variables, mixins, loops and other handy stuff.

Introduction to and Comparison of CSS-Preprocessors

Nesting CSS classes

Not possible with vanilla CSS. However you can use something like:

  • Sass

Sass makes CSS fun again. Sass is an
extension of CSS3, adding nested
rules, variables, mixins, selector
inheritance, and more. It’s translated
to well-formatted, standard CSS using
the command line tool or a
web-framework plugin.

Or

  • Less

Rather than constructing long selector
names to specify inheritance, in Less
you can simply nest selectors inside
other selectors. This makes
inheritance clear and style sheets
shorter.

Example:

#header {
color: red;
a {
font-weight: bold;
text-decoration: none;
}
}

Nested selectors performance impact and LESS

That is correct. Browsers evaluate selectors from right to left. It will try to find a span inside a li.pinfo-box and so on.

One rule of thumb to folllow when writing LESS is: do not nest more than 3-4 levels.

This will prevent your selectors from growing to big, while you will still be able to benefit from the nesting feature in LESS.

A good example of "useless" nesting is when styling lists. Sometimes I write the selectors like this:

#wrapper .blog-post ul, #wrapper .blog-post ul li

Is it really necessary to specify that the li must be inside a ul? It will probably be enough writing:

#wrapper .blog-post li

All of this is good to know. BUT: This is not the first thing to dive into when trying to optimize your sites performance. Spend some time lower the number of request or something else instead.



Related Topics



Leave a reply



Submit