Blog

Nesting with CSS: the Good the Bad and the BEM

paul 0 Comments Web Development

Here at Zoocha we use preprocessor for almost all our frontend work. Predominantly we use SASS although some projects are on LESS, partly for historical reasons. No-one can deny that it’s a really powerful way of writing CSS, giving you access to variables, mixin functions, and the apparent Holy Grail: nesting. The thing about all of the above though, and I think something that often gets forgotten is these are all tools to make the developer’s life easier. The result is still compiled down to CSS. 

"What’s the problem with making our lives easier?" I hear you developers cry. Nothing. Not in theory anyway. The thing is though, we don’t build websites for the code. We build them for the content. Your end user doesn’t give a damn how easy your life was building the site, they just want to be able to use it!

Anyway. Back to the point. I’m focusing on nesting in this post because in my mind it's both the best and worst feature of pre-processed CSS. Nesting, to clarify, lets you do this:


.blog-post {
  …
  .title { … }
  .teaser-image { … }
}

Nice and neat, huh? It lets us encapsulate our styles, ‘namespacing’ them so they’re only applied to the component we need. Cool! Top marks. The above code compiles down to this:

.blog-post { … }
.blog-post .title { … }
.blog-post .teaser-image { … }

Ok, not bad either. All good so far. BUT: what happens if we have something that’s similar to a blog post, say a news item that shares most of the styles. (from hereon I’m going to use SASS for brevity, but the priciniple applies to all others like LESS, etc) No worries, with SASS I can just do this:

.news-item,
.blog-post {
  …
  .title { … }
  .teaser-image { … }
}

Sweet! I just add one selector and it’s all sorted, right? Right? Not quite. The compiled CSS ends up like this:

.blog-post,
.news-item { … }

.blog-post .title,
.news-item .title { … }

.blog-post .teaser-image,
.news-item .teaser-image { … }

I know that still doesn't look too bad. There are now double the number of selectors in the sheet though. Repetition is what we thought preprocessors avoided. For smaller cases this might be a problem, but we recently had a problem where we were hitting IE’s mythical 4096 selector limit (separate debate there entirely I appreicate!). Looking into the project we saw that in some places, selectors were being replicated thirty times, leading to huge selector bloat.

This is not good for several reasons:

  • First and most obviously, file size. More selectors means more bytes, which means more of your data allowance being gobbled up
  • Secondly: Computation power. The browser now has to parse all these rules to work out if they apply to the page, which slows down the load, performance, and also eats into your battery.
  • Thirdly: this is a debatable one (though not in my eyes), but we know we can do better here. We’re not playing on the strengths of CSS.

So what’s the solution? There are lots. I’m going to talk through my approach for now, but don’t treat it as gospel. In the above example the better way to approach this would be to have to take a step back and see that these two things are, essentially the same. So we can change our classes to something generic and use them for both, without writing any more CSS, e.g.


.post {
  .title {}
  .teaser-image {}
}

Then we just use the same classes in both places. Magic. We can go one step better though by using a naming convention. In our case we use BEM (or try to). Now BEM isn’t a magic bullet, it literally just is a naming convention, a way of thinking. Other people have explained BEM much better than I can, so I suggest you try them (Harry Roberts as usual has a great post on the subject: http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/)

We can actually avoid all nesting completely, if we use BEM:

.post {}
.post__title {}
.post__image {}

If we need something specific for our blog post we can combine classes, e.g.

.post--blog {
  // different styles
}

<article class=”post post--blog”>

In the example above this would’ve saved ~ 1000 selectors from our compiled CSS!

A common argument is that we have to add lots of classes to our HTML and that gets cluttered. To me this is not an issue (within reason) - the savings on page weight and  developer sanity are huge, as it will often remove specificity issues because there aren’t huge selectors like .blog-post-list .blog-post .blog-post-title a span.badge  (this is made up, but you get the idea)

To sum up: nesting isn't bad, but the danger of using preprocessors is that it's difficult to see what you're producing out of the other end. My recommendation is, by all means use it but do so sparingly and check the compiled CSS from time to time so you know what's happening. Also - the 'Inception Rule' is a good one to follow (don't nest by more than three levels)! Finally: take a step back and think before you start coding. See if there's a similar component that can be tweaked to make a common set of rules you can share, and life will be much better (disclaimer: life may not actually change or improve!)

 

Leave a reply