Mark Daggett's Blog

Innovator & Bricoleur

CSS Anti-patterns

Over the last month of two I have been working on a large enterprise Rails site. The backend has been implemented by a core group of developers but the frontend CSS and HTML have been handed off several times. As I worked to refactor some of the views I noticed several anti-patterns reoccurring in the code that I thought I would highlight and propose work arounds. While all of the examples I present in this file are extracted directly from the site in question I have seen them occur over and over again on other projects.

1. Unclear Naming Conventions

If a tag in an HTML page performs a task then a good CSS name should describe what the job is. It should have semantic value and should not where possible describe only visual attributes.

Anti-pattern Example
1
2
3
4
.teal {
color: #1EC5E9;
font-style: italic
}

This class name gives very little semantic value to tag it is applied to. The class “teal” only describes the visualness of the tag. Furthermore this name is only relevant while the visual design of the page stays the same. If the design changes then every instance of the “teal” class will need to be removed throughout the codebase if the color changes. What is worse is if the CSS attributes within the class are updated without changing the name then the name becomes meaningless. A better approach would be to understand what the teal color is for. If it is meant to draw emphasis to a bit of text then choose a name like “highlight” so that it is more clear what job it is to perform.

2. Invalid Declarations

When writing CSS periodically run your classes through a CSS validator to ensure its syntax is correct. The problem with invalid declarations is that they may not break the tag in question but may corrupt the rest of the cascade causing classes defined later in the file from working. Whenever I am hunting down a CSS error the first thing I do is ensure I am working off a valid document. I can’t tell you how many times just fixing the code in one part of the file fixed mystery bugs that appeared lower in the document.

3. Unnecessary verboseness

Where possible try to compact your CSS attributes into one line:

Anti-pattern Example
1
2
3
4
  background: #2175BE;
  background-image: url(../images/bottomshadownav.png);
  background-position: bottom;
  background-repeat: repeat-x;
Improved Version
1
  background: #2175BE url(../images/bottomshadownav.png) repeat-x bottom;

4. Overly Specific Classes

I strive to make CSS classes do only one thing. That does not mean that my classes only have only one attribute declaration, but it means that I try to assign them only one job to perform. This allows me to build up complex behaviors and visuals to html tags by combining several simple CSS classes. Resist the urge to add properties to your class that doesn’t describe the job it does. This will also make your HTML more clear to read, and easier to extend. Consider the two examples below:

Anti-pattern Example
1
2
3
4
  .slider {
    height: 27px;
    float: left;
  }
Improved Version
1
2
3
4
5
6
  .slider {
    height: 27px;
  }
  .left {
    float: left;
  }

5. Browser Specific Overrides

Where possible resist the urge to place browser specific hacks in the master CSS file. The proper approach is to peel these classes off into an override stylesheet that will be loaded only when the user is using that particular browser. The reason we put override classes in their own file is for two reasons. It simplifies the master CSS file, and gives the developer an easy way to eliminate CSS from the site when the site no longer needs to support a deprecated browser.

Anti-pattern Example
1
2
3
  .decile img {
  _margin: 0px /* IE 6 Hack */
  }

6. Needless Duplication

Part of writing good CSS is to generalize common tasks where possible. In the example below you’ll notice that both classes are essentially the same.

Anti-pattern Example
1
2
3
4
5
6
7
8
  .comparator a {
  margin-right: 3px;
  padding: 3px 13px 3px 13px;
  }
  .ambition a {
  padding: 3px 13px 3px 13px;
  margin-right: 3px
  }
Improved Version
1
2
3
4
  a.link {
    padding: 3px 10px 3px 10px;
    margin-right: 3px
  }

7. Overuse of exclamation point

The “!” override is a brute force method to ensure an attribute of your class cannot be overwritten. This should be used as a last resort and not to mask poor design or abstraction of classes. Overuse of the exclamation point is like a shouting match between all your CSS classes, almost never ends well.

8. “Cargo Culting” through Copy + Paste

Copying CSS en masse and pasting it into the document without making fundamental changes to the class can be a sign of disconnect between the designer and developer or a signal that the developer / designer doesn’t know (or care) about how the copied CSS works. Bulk copying CSS creates deadweight in the CSS file and makes it harder to maintain and extend.

In the first case where a developer is implementing a design given to them by a front-end developer it is entirely possible the developer won’t know how the CSS works. Later, they may find themselves needing to replicate a style elsewhere in the site. Often this means they bulk copy several classes and paste them elsewhere in the document. Typically, they make a trivial changes needed e.g. change the font-size and then rename the class. The proper approach would be to abstract the first class so that it is more generalized and can service both instances of how it needs to be implemented.

However, I found several examples where entire blocks of code appeared three and four times in the same file with absolutely no difference! This is absolutely unacceptable in a professional product.

9. Unused Classes

With any site under constant development it is easy for classes to become unused within the html. Developers and designers must make it part of their development process to remove unused classes from the CSS otherwise the site can become bogged down with all the deadweight inside the CSS file. There are projects like “deadweight” which are specifically dedicated to helping you prune your CSS of unused code.

10. Needless Namespacing

Namespacing is used to change the way a child class works when its parent class changes. This is a great way to keep your HTML and CSS flexible because it means that a single change to the parent element can change the look and feel of all the containing children. However, if you over namespace your CSS by binding it to specific html tags where not absolutely needed you make the CSS brittle and hard to maintain.

Anti-pattern Example
1
2
3
4
5
  .qipp-inputs table tr.metric td.metric_name {
  border-bottom: 1px dotted #B6CBD2;
  padding-left: 20px;
  text-align: left !important;
  }
Improved Example
1
2
3
4
5
  .qipp-inputs .metric td.metric_name {
  border-bottom: 1px dotted #B6CBD2;
  padding-left: 20px;
  text-align: left !important;
  }

I welcome any discussion or feedback on these patterns and would love to improve this document where possible. What anti-patterns have you seen in CSS files you’ve worked on?

Like this post, then you'll love my book on JavaScript.

Expert JavaScript is your definitive guide to understanding how and why JavaScript behaves the way it does. Master the inner workings of JavaScript by learning in detail how modern applications are made. In covering lesser-understood aspects of this powerful language and truly understanding how it works, your JavaScript code and programming skills will improve.

Comments