Starting a Refactor with CSS Dig

Avatar of Tom Genoni
Tom Genoni on (Updated on )

The following is a guest post by Tom Genoni. Tom built an open source Chrome Extension for analyzing CSS. I’ll let him introduce it.

It’s a new web project. You’re starting from scratch. The front end is going to be clean and orderly. You’ve set your defaults. Your CSS files are organized. You’ve got a system! This time will be different. What could possibly go wrong?

If this sounds familiar then you know how it usually ends: slowly, inevitably, the code starts to balloon and you feel the control slipping away. It becomes complex and intertwined. You’re overriding styles, naming is inconsistent, magic numbers and hacks abound. Older code is hard to parse, poorly documented, and good luck getting new coworkers to understand it. Bugs start to appear. Damn. Better just throw more CSS at it.

Determined to avoid this fate, I researched refactoring techniques, emerging best practices, and eventually built CSS Dig. In this post, I’ll highlight three areas where CSS Dig can help and provide some refactoring tips.

Start The Audit

In Nicolle Sullivan’s presentation about her refactor of Trulia she recommends taking screenshots of every nook and cranny of your site and grouping the design elements together to see the universe of font sizes, buttons, backgrounds, borders, etc. This exercise alone often surfaces a lot inconsistencies (and a fair amount of groaning) and provides a starting point for standardization.

After realizing that, yeah, we have too many button variations, the next step is to “grep your styles”: scrutinize your CSS the same way and you’ll often find a wide range of properties and values that are candidates for consolidation. This is where CSS Dig can help.

After installing the Chrome Extension you’ll see its icon in the upper-right corner of your browser. Navigate to a site you’d like to inspect and click the icon. A few caveats:

  • On sites with lots of CSS, and depending on your connection speed, it can take a few seconds for CSS Dig to complete.
  • Sites with strict “Content Security Policies” can cause CSS Dig to fail. For example, facebook.com and github.com.
  • CSS referenced by @import is ignored. It’s considered a bad practice and it seems most sites now avoid it.

Speed Things Up

The first thing you’ll see is a dialog listing all the CSS files and style blocks found on that page. Note that some remote files, like font providers, are not accessible and will be listed as “Undiggable”. You can disable items, like third-party libraries, you don’t want included in the analysis but before you “Start Digging” take a good look at the list. Reducing http requests is the number one performance rule so combining CSS into fewer files is a good place to start.

There are 10 http requests for CSS files on washingtonpost.com home page. Can some of these be combined?

Once you’ve picked the CSS you’d like to examine click “Start Digging” and you’ll be presented with the main CSS Dig screen. On the left you’ll see the properties and their counts. Clicking on these reveals the actual declarations used in the CSS. And clicking on the individual declarations isolates the rule sets in the right column.

Too Many Colors

One of the first things I like to examine are the colors. High numbers here are often the harbinger of problems in other areas. A while back I ran CSS Dig on huffingtonpost.com. They’ve since cleaned things up a bit but at the time this is what they were working with:

It’s pretty in its own way. But do they really need all of those reds?

Different websites have different needs and constraints — but contrast that with the colors from apple.com:

This shows a bit more discipline.

Because CSS Dig shows you the number of times a color was used, you can pretty quickly identify which ones to consolidate around. Pick a dominant blue (or red or green) and make it the default. If you’re using a preprocessor create variables and stick to them. Your users will get a more consistent experience and it’ll be easier for you to maintain. Sass maps are great for this.

$ui-color: (
  brand         : #0081BA,
  brand-light   : #9ACCE2,
  brand-dark    : #036,
  bad-news      : #C60C0C,
  good-news     : #97C70A
);

And then referenced a color using:

.foo {
  color: map-get($ui-color, brand);
}

Spacing

Other areas for standardization are paddings and margins. It’s not uncommon to have a wide spread of values, sometimes in different units, especially when different teams are working on separate parts of a site. But when components have to mix and match, inconsistencies can quickly become apparent.

One way to address this is by setting a global spacing grid that applies to all elements (with the occasional exception). In the UI library at Optimizely we use a spacing unit, currently at 10px, and all component spacing is based on that. This helps to exclude “magic numbers” yet gives some discretion to the CSS author.

For example, the following code:

.foo {
  padding: spacer(1);
  margin: spacer(1.5) 0;
}

compiles to:

.foo {
  padding: 10px;
  margin: 15px 0;
}

using:

@function spacer($value) {
  @if ($value * 2) % 1 != 0 {
    @warn 'Spacer value must be a multiple of 0.5';
    @return 'Spacer value must be a multiple of 0.5';
  } @else {
    @return $spacer-unit * $value;
  }
}

If our spacer function sees a value that’s not an increment of 0.5, it returns an error. There’s nothing preventing the author from using a hard-coded number, but exceptions can be discussed in a code review. I’ve found this frequently creates serendipitous harmony across components.

Specificity Wars

When Sass was gaining popularity it was not uncommon to see developers attempt to match the nested structure of the HTML they were styling. It does seem like a good idea. I tried it. But it turns out that creates all sorts of complications and it’s now frowned upon.

Among the pains it exacerbates is the long-standing struggle with CSS specificity. Overriding long selectors in an effort to reuse a highly-specific component is a confusing and annoying experience, often resulting in more selectors and (gasp) !important rules and code you hope you never have to explain to anyone.

Long selectors from nytimes.com.

In the Selectors tab of a CSS Dig report, you’ll see all the selectors listed with options to sort by length and specificity. These are calculated using Keegan Street’s Specificity Calculator. This will help identify potential selector time bombs and, hopefully, begin the process of making the styles less nested, more resuable, and easier to maintain. I also recommend using CSS Specificity Graph Generator to get a bird’s eye view of your code.

Keep Going

If after taking a look at your own code you find you want to do a deeper refactor, here are a few more steps to consider.

  1. Pick a short code name for the refactor. This helps gives the project significance and, more importantly, provides a way to namespace new classes. At Optimizely we’re using lego- as a prefix for all classes (yes, I know, super original name) but it’s been invaluable in providing clear a separation between new and old classes.
  2. Adopt a modular, object-oriented approach, like BassCSS, SMACSS, or Harry Roberts‘ upcoming refresh of his Inuitcss. This has greatly reduced the amount of new code we write and has speed up development time considerably.
  3. Use a linter (like CSS lint or SCSS-lint). This will automatically enforce a long list of common code standardizations, keeping your code clean and consistent.

Contribute

The CSS Dig source code is available on GitHub. Your suggestions, requests, and bug reports are welcomed.

Also, I work at Optimizely — check us out. We’re working on some interesting things.