Pixel Whip

CSS Confessional

Writing performant stylesheets and how Drupal leads us toward temptation, with its dirty innefficient CSS selectors.

I've had the opportunity to work with some amazing themers at Examiner.com, working on their latest redesign. Examiner.com is a huge site with tons of content and a wide variety of associated page layouts and block layouts. Working on a such a large site got me thinking a lot about what constitutes efficient CSS lately, both from a development and browser rendering perspective.  For now, let's focus on the latter. 

Whether or not the gains, from writing efficient CSS, will have a noticeable impact on the end-user experience will vary. The gains are probably not worth going back and rewriting old CSS, but it's good to have an understanding of these principles as we move forward writing CSS.  

In my mind, there are 3 main variables that will affect rendering performance, device CPU, DOM complexity and CSS selectors. To simplify, let's assume our users are running slow CPUs (read mobile) and we're theming a site with a complex DOM (read Drupal divitis.) How can we write the most efficient CSS?

The main concepts we need to understand are, browsers traverse the DOM outside-in and they evaluate CSS selectors from right to left.  So the browser starts with <html> then <body class="no-sidebar"> then <div class="teaser"> and so on. All the way down until it reaches the inner most element.  For each element, the browser checks the CSS to see if there are any rules where the right-most CSS selector matches. In the above example, when evaluating <div class="teaser">, these rules would match:

  1. div {…}
  2. no-sidebar div.teaser {…}
  3. teaser {…}

In the case of #1, this rule will apply to all divs on our page, which will be way more elements than we probably need. Thus wasted CPU.

For #2, the browser sees a match, then has to traverse all the way back out of the DOM until it finds a match for .no-sidebar.  Not a big deal in this example, because it only has to make one more evaluation before finding a match.  But what if our div was 20 levels deep and .no-sidebar didn't apply to any outer elements? That's 20 more evaluations. When you have 2000 CSS rules full of these descendent selectors, this will add up fast.  This rule is also over-specified, in that there is rarely a need to include both the element and the class on a given selector.  This will make things much harder to override later.

For #3, the browser scans the element, sees a match and is finished.  No more evaluations needed. The rule only applies to elements with the same class and can be overridden or built upon easily.

Popular CSS strategies such as OOCSS and SMACSS are both geared towards writing CSS that can scale with a large complex site.  And both revolve around the core concept of styling by adding layers of classes to get the effect you want.  This should result in tidy CSS-- efficient to scale and maintain.

To find out more about efficient CSS from a browser perspective check out Google's list of selectors to avoid and Chris Coyier's excellent blog post.

Long story short: target classes, not elements.

"Bless me father, for I have sinned, I wrote shitty CSS."

My problem, is the tools I use to create websites tend to steer me down the dark path of inefficient styling by using a ton of descendent selectors.  

The first is CSS preprocessors. Don't get me wrong, I love them long time. However, both SASS and LESS allow you to nest your selectors in order to easily create and manage unnecessary, descendent-heavy styles.  But you're just kicking the unmaintainable can down the road.  Gradually, as the site grows, you'll hit a point where you need to nest more and more in order to override specific styles.  This problem can be solved with a change of mindset and general awareness of what the final compiled CSS will look like.

Writing efficient CSS is easy, provided you have the classes to target. Drupal themes have never been very intuitive when it comes to adding classes.  In most cases, you need to either modify a .tpl file or write a preprocess function.  Both of these can be relatively time consuming to do; depending on the theme you are working with; the element you want to add a class to; and the way the module outputting the markup was originally written.  Most Drupal base themes come with tons of CSS classes which make it very quick and convenient to write some decedent heavy selectors and get the job done.  This might be fine for a small site, but will kill you with a big site. Especially if it  goes through frequent design adjustments.

Thankfully, I've been getting my hands dirty with Drupal 7's render arrays and theme functions. Adding a custom class is getting much easier with practice.  However, there surely must be a way to reduce the learning curve of adding classes to a Drupal theme. Right now I'm drawing a blank, but will definitely be thinking about it.

So as penance, I am writing this post in an effort to raise awareness of writing good CSS. I will also write 10 reusable classes before going to bed tonight.