I have a .scss file that, among other things contains this:
nav {
font-size: 0;
ul {
margin: $padding/3;
}
li {
z-index: 10;
position: re
Just to chime in and enforce what others have said. It's a bad practice not necessarily from a performance point of view (It's probable you'll get better paint time increases from removing blurs/shadows and rounded corners than optimising selectors) but from a maintainability point of view.
The more heavily nested a selector, the more specific the resultant CSS rule (which you know already). Therefore, when you want to 'trump' that rule at some point you'll have to write a rule of equal (or greater) specificity further down the cascade to overrule the first. If you have an ID in there, that's going to make it FAR more specific too (so avoid unless you need them and know you won't need to override down the line).
To follow this to its logical conclusion, don't nest unless you need to. Don't have a rule like this:
.selector .another .yeah-another {}
When this would do the same job:
.yeah-another {}
It just makes life easier for everyone (including you) down the line.
It depends on how much dynamic manipulation of the DOM and styles will go on after page load. It's not page loads (mostly) or slow selectors on initial layout that are at issue, it's repaints/reflows.
Now, Steve Souders says that on the average site it's simply not a real concern. However, on a web app or highly interactive site, poorly performing CSS rules can make your repaints slower than they have to be. If you have a lot of repaints...
Experts such as Nicole Sullivan, Paul Irish, and Steve Souders have covered the way CSS interacts with with JavaScript and how to write highly performant CSS selectors. It's more than depth (different selectors have different performance), but a good rule of thumb is to limit both depth and complexity to keep yourself out of trouble--but not so much performance trouble, read on.
However, as jankfree.org notes, it's not so much descendant or specific selectors as it is certain properties in certain contexts (html5rocks.com) that make paints expensive. I see long or complicated selectors more as a maintainability issue (Nicolas Gallagher) than a performance issue--keeping in mind that maintainability interacts with performance. Highly maintainable code can iterate faster and is easier to debug (helping you find and fix performance issues).
Now, as to Sass optimization. Yes, Sass can optimize your CSS. But it cannot optimize your selectors. A 4 level nested block will be output as a 4 level nested selector. Sass cannot change it without possibly making your CSS not work. You, as the author, have to optimize the way you write Sass to optimize your output. I, personally, use nesting only in a limited way (a killer feature in Sass for me is composing styles with @extend
and placeholders). However, if you really love nesting you might be able to tweak your output to some degree using the Sass parent selector reference (or the newer @at-root).
So far as I know, neither Sass nor Compass has a built-in tool to analyze selectors and warn about them. It's probably possible to create a tool to do that (set a max depth and have your pre-processor warn you) utilizing an AST. More directly, Google Page Speed does have an existing feature that provides some information. SCSS Lint has a nesting option. There's also CSS Lint. (These can theoretically be added to run in your Compass config's on_stylesheet_saved
if you're not already using something like Grunt or Gulp).
My opinion:
You tell me which is worse on your eyes
from the op
nav li ul li a {color: $textColor;}
or as has been suggested
.nav-menuitem-menu-menuitem-link {color: $textColor;}
So...
The question is "Is it bad practice to hypernest in SCSS?" (or is it SASS?) I say no. But it's an ancillary argument.
The WORSE practice lies in leaving the SASS (or is it SCSS?) output, in it's machine-driven state, for production.
S*SS is a only a tool in your bag of tricks, no different than Notepad++ or Git or Chrome. It's role is to make your life a little easier by bringing some very general programming concepts to the point of building some css. It's role is NOT building your css. You can't expect it to do your job for you and create completely usable, readable, performing output.
...which would be going thru your css afterwards and hand tweaking. Test, build, etc with your hypernested output. And when S*SS creates my first example above, give that anchor a class and call it with nav .class
.
Just think about how you would want to write the actual css selector. Don't nest everything just because it is a child of the element.
nav li ul li a {
/* over specific, confusing */
}
.sub-menu a {
/* add a class to nested menus */
}
Once you start chaining that many selectors, it becomes a pain to override and can lead to specificity issues.
Although not directly an answer to your question, you can keep highly nested sass for your own purposes but still use @at-root
. Check it out here.
.parent {
@at-root {
.child1 { ... }
.child2 { ... }
}
}
// compiles to ...
.child1 { ... }
.child2 { ... }
Don't nest CSS. We feel comfortable nesting css because that closely mirrors what we do in HTML. Nesting gives us context that .some-child
is inside .some-parent
. It gives us some control over the cascading. But not much else.
As SMACSS suggests, I would nest in class names instead. i.e, use .child-of-parent
instead of .parent .child
or .parent > .child
Nesting badly in practice can lead to extremely slow pages. See how github speeded up their diff pages.The least you should do is follow the inception rule which states that you shouldn't be nesting beyond 4 levels.
However, I would go one step further and say that we shouldn't nest CSS at all. I wrote a blog post with my opinions. Hope this is useful.