Your nesting is harmful - On abusing a preprocessor’s feature

477 阅读5分钟
原文链接: medium.com

Two years ago we’ve started adding a preprocessor, Sass to be more precisely, to our toolchain. I was super excited. I was extremely happy about the low entrance barrier and all the new opportunities: Variables, Nesting, Mixins and Extends felt like a huge empowerment and a lot more “programmy” to me. What started as a wonderful journey at the time ended up in a not so beautiful picture about the usage of preprocessors. I’ve learned a lot in the last two years and I’ve seen some of these opportunities used in an alarming way, especially nesting.

I remember my first Sass stylesheets and the deep levels of nesting I used there, which I was really proud of. I nested everything into everything, which made sense to me to some extent, not knowing that this “technique” did way more harm than good.

I didn’t pay my CSS files much attention at this time, I just looked at them very rarely, because now I had this new shiny toy to play with. This was one of my first mistakes. When I recently looked into these old files again, I was totally shocked by the long selector chains I had produced back then.

//CSS
.main-nav .nav-list .nav-element .nav-link .nav-decoration:before {
…;
}

I lost my focus about what I was putting out there. At the end it’s the CSS file which gets used — not my nicely-plugged Sass monster(which looked more like a beautiful unicorn riding on a rainbow to me at the time). And super long spaghetti selectors don’t make our CSS load faster — we know that.
The much bigger deal is the huge amount of specificity I needlessly had put onto my selectors. Every time I had to overwrite some styles I built even longer chains, started the usage of IDs and actually reached !important a lot more often.

None of this is anything you want in your stylesheets and none of this is anything you want somebody else to work with.

“You have to use the ‘Inception Rule’, stupid” you may say.

Yeah, you’re right, and as soon as I learned about it, I started doing so, even refactored a view of my Sass stylesheets to get used to it. It made things better, much better. I told everybody with whom I was talking about preprocessors about this rule. Never go deeper than three levels.

Of course there are exceptions to this rule as they are for every rule ever invented.

But over the years, the projects I was working on grew bigger and bigger. And also my knowledge about CSS architecture improved. Now I see more and more pitfalls in the usage of this actually nice feature.

In the following I’m going to list a few points I’ve concerns about.

Needlessly nested selectors make our stylesheets more complicated. Needlessly nested selectors? Here’s an example:

//Sass
.element {
…;
.element-part {
…;
}
.element-another-part {
…;
.element-even-more-selectors {
…;
}
}
.element-because-its-fun {
…;
}
}

This may look familiar or even usual to many of you. Some of you may say “what’s wrong with it?” I will show you why this is far from ideal.

First of all: .element-even-more-selectors {…}(max. nesting level of 3) will give us the following output: .element .element-part .element-another-part .element-even-more-selectors { … }. Are you sure this is really what you wanted to write? I highly doubt that.

Secondly: Imagine every selector in your well-nested group has more than one rule, let’s say each of them has around 10–15 declarations. Our now 15 lines of code grow to around 75 lines and it gets messy.

I’ve seen developers who tried to kinda mimic the DOM structure inside their style sheets. This leads to extremely specific styles which exactly match the DOM at the moment of writing. But the DOM will change — Take this as a promise. So mimicking the DOM in your style sheets makes the whole construct just more and more rigid and takes away the flexibility you need to quickly change something. You do not want to do that.

CSS specificity is a huge deal breaker. Besides naming elements this might be one of the harder parts in writing CSS. I always love to reference this chart by Andy Clarke to make sure everybody is on the same page: www.stuffandnonsense.co.uk/archives/cs…

Specificity isn’t a preprocessor problem per se, but the opportunity to nest elements often makes it an even bigger problem than it was before.
Let’s take a look at the following, simple example!

//Sass
.blog {
width: 100%;
margin-bottom: 3rem;
.post {
                    
width: 90%;
margin-bottom: 2rem;
}
}

At a first glance there’s nothing wrong with it. But let’s say, that we have also an archive page which contains posts. We now have to write the styles for the archive page into another contextual class even if .post inside .archive has the same styles.

The possibility of easily nesting selectors makes us do it even when it wouldn’t be necessary. Just because something can be done doesn’t mean it has to be done. Try to resist the urge of nesting something because it makes sense in the first place.

Source maps are wonderful and I still remember the days working without them — it wasn’t fun at all.
But there are still some bumps on the road. I usually work with Sass, but in my current project we’re using Less. It’s okay and for the most basic usage of preprocessors there’s not much of a difference between Sass and Less. Still, one difference is super annoying: At the time of writing, Chrome and Less have a little problem with each other. The Chrome dev tools will just give you the line number for the upmost selector. So if you have nested monstrosities like the ones described earlier, just imagine you’re looking for something which is 3 levels deep somewhere in there. Have fun finding the right line number!

The parent selector is a nice little neat thing. Here’s a basic example:

//Sass
                      
.parent-selector {
font-size: 2em;
line-height: 1.618;
color: tomato;
  &.child-selector { font-size: 1em; }
}
//CSS
                        
.parent-selector {
font-size: 2em;
line-height: 1.618;
color: tomato;
}
.parent-selector.child-selector { font-size: 1em; }

In context of selector nesting this feature can harm the structure and clarity inside your Sass files. Of course you don’t have to write your parent class name over and over again, which is cool, because all developers are lazy. But… let’s take a look at this screenshot:

Hint: There are more things here which should be done differently than just the usage of the parent selector.

Yep, you can’t see which one is our parent selector because we have deeply nested selectors right here und you start scrolling, mentally jumping around, if this is nested within that and this was the parent of that, maybe this is our parent. Or wait could it be… Screw you! Nobody wants to do that.

“With great power comes great responsibility.”

The parent selector gives us nice opportunities but with great power comes great responsibility. An overuse of the parent selector makes your document harder to scan and to understand.
Put more time into structuring your code base in the first place. Keep your selectors neat and tidy.

I try to constrain myself to just :pseudo classes and classes which describe the state of a given module — something like .is-active.

//Sass
.link {
text-decoration: none;
color: red;
&:hover { text-decoration: underline; }
                              
}

This doesn’t make the document needlessly complicated and ties selectors together which are meant to be together.

After a selector deep dive it’s time to come up and take a deep breath. Reconsider, restructure and get rid of stuff which makes things more complicated than they have to be. Just because something can be done doesn’t mean it has to be done.

Put more time and effort into structuring and naming the elements on your page and stop throwing them into your Sass files wherever they stick. If you have to add new selectors think twice (or even more) if it really makes sense to nest them and if so always take a look at the CSS output. You will be surprised, more often than you expected.

Credits for the headline image: http://crzisme.deviantart.com/art/Inception-Maze-Wallpaper-194388039

If you liked my article I would be more than happy if you hit the recommend button and share it with your dear friends and followers.