Watch more video from the Top Picks channel on Frequency

Another day, another melodramatic blog post title. ;)

I was prepping to speak at Webstock this year when I realized I didn’t want to give the talk I had proposed. I didn’t want to talk about the Mistakes of Massive CSS, because I realized it went deeper than that. In fact, in most cases, the things we considered best practices were leading to the bad outcomes we sought to avoid. I realized (unpopular though it might be), that we couldn’t make it work out well by trying harder. Each time we start a new project, we think “this time, I’m going to keep the code clean. This time the project will be a shining example of what can be done with CSS.” And without fail, over time, as more content and features are added to the site, the code becomes a spaghetti tangle of duplication and unpredictability.

It is time to let ourselves off the hook. There is nothing we could have done by trying harder. There is no magic juju that some other developer has that we don’t. Following our beloved best practices leads to bad outcomes every. single. time.

What are those flawed best practices?

Classitis!

Never add an non-semantic element

Or, a non-semantic class

Use descendant selectors exclusively

Sites need to look exactly the same in every browser

Classitis!

How in the world did we even get the idea that some aspects of CSS were good and others evil? Who decided and what data did they use to judge? Did their goals fit our goals? There is nothing wrong with using classes. In almost every case, classes work well and have fewer unintended consequences than either IDs or element selectors.

You should style almost everything with classes. The goal is to find a balance between classes that are too broad and include everything and the kitchen sink and classes that are too narrow. Generally speaking, you don’t want your classes to be so narrow that each one applies a single property value pair. It becomes extremely hard to evolve your design if every item is composed of mini-mixins.

On the other hand, if classes are too broad, you will have duplication. Try to find the middle ground where all the repeating visual patterns can be abstracted. This is hard, but very worthwhile. If you do it, your code will stay clean. You will finally see results from trying harder.

Classes are our friends. Seeing a lot of IDs is actually very bad. Run from this kind of code:

#sidebar #accounts #accountDetails h3{}

Never add non semantic elements

We don’t want to have unnecessarily heavy HTML with a lot of extra elements. On the other hand, adding an extra element can often provide a buffer between two sets of classes that weren’t necessarily coded to interact with one another. For example, I prefer to have the decorative elements of a container completely separated from its content.

Using a paragraph that happens to be inside a rounded corner box to make a corner decoration means that the container can never hold content other than a paragraph. If you want to include a UL you will need to duplicate all those styles. This doesn’t work.

You want your content to be marked up in beautiful HTML that uses a diverse set of tags like P, UL, OL, LI, H1-6, strong, em . Add a few extra wrapper elements to keep your content nicely cordoned off from your containers or separate out decorative flourishes! Your HTML will be clean and your CSS predictable.

Never add non-semantic classes

We absolutely don’t ever want to use classes like “bigRedHeading”, not because it is non-semantic, but because it isn’t future proof. As the design evolves, the CSS needs to keep pace. On the other hand, CSS needs abstractions. We need to be able to solve a particular problem really well, and then allow people to go on using that solution long afterward. Grids for example solve the layout problem. Once they have been implemented on a site, developers can spend time on more important features and stop re-implementing a layout solution over and over. Abstract solutions are necessarily disconnected from the content they happen to contain. This is something we should look for in a solution, not condemn.

The semantics debate has really gone too far. It is useful as a general principal, but often I see standards aware developers trying to stuff in semantics that never existed in the design. If the design didn’t make a distinction between two things visually, why add additional complexity? Classes work much better when we use them to represent visual semantics, rather than keeping them tied to content.

One more point on the topic. Screen readers don’t read class names. It is not an accessibility issue. (Thanks to John Foliot for confirming)

Use descendant selectors exclusively

Never has more terrible advice been given (ok, ok, I exaggerate, but for CSS, this is as bad as it gets). The descendent selector is *only* appropriate between multiple nodes of the same object (say, a tab container and its’ tabs), and even then, only when you are absolutely certain that there will never be any markup changes. Very hard to guarantee, no?

I have had a designer give me a tab container that had one group of tabs to the left and another grouping (usually more simply styled) to the right. In which case, if you had styled the UL using the descendant selector, you would be stuck overriding a bunch of styles you no longer needed. Classes are much much better and can be used in combination with the descendant selector when the nodes belong to the same object.

I guess the only time I use the descendant selector with elements is to style LI, and even then, I often get bitten when someone wants to nest those lists. Better support for the child selector will make that issue easier to fix. Ideally, we don’t want any styles flowing from container to content.

Even with the media block, you might consider putting a class on the media block which sets the styles of the image. It sounds reasonable until you realize that the image is actually its own object. You might have multiple nested media blocks and you will get very weird interactions unless you apply the image style class directly to the image itself.

In the middle layer, you might decide to create one display objects for each of the different types, and that would probably make the objects easier to use, but in the CSS layer, you don’t want to tie it all together like that.

Sites need to look exactly the same in every browser

Forking your design is bad, it makes testing even more complicated, but that doesn’t mean that pixel for pixel a site needs to be exactly the same in every browser. If you try to force the complexities of a modern design onto users of IE6, their user experience will suffer. The site will load slower and reflows and repaints will make the javascript sluggish. IE6 users need a reasonably fast user experience, they do not *need* rounded corners.

Anyway, enough ranting. Please do checkout the slides for Our Best Practices are Killing Us. I hope you find them useful.

Photo by Trey Ratcliff