by Trey Ratcliff

Our (CSS) Best Practices Are Killing US

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

37 thoughts on “Our (CSS) Best Practices Are Killing US”

  1. “How in the world did we even get the idea that some aspects of CSS were good and others evil? ”

    You mean, like the ideas that IDs and descendant selectors are evil?

    (We kid because we love.)

  2. IDs and descendant selectors were probably great when sites were documents and mostly uniform throughout. I think that was only the case as long as w3c specs and technical papers converted from LaTeX made up the vast majority of the web. ;)

    Actually, they are still useful now. IDs are great for JavaScript hooks into the DOM, but not for styling, and descendent selectors are fine within the nodes of any one component, as long as they don’t leak to the content area.

  3. “Sites need to look exactly the same in every browser” never was a best practice.

    Also, semantic grids are possible.

    And, there’s an interesting approach to that stuff, Yandex guys made a presentation, but I guess it’s only available in Russian… BTW, just search something on http://yandex.com and open the web inspector :-)

  4. Nicole,

    A bit of a clarrification.

    While it’s true that screen readers don’t read class names, this may still be a problem if you are using your class to visually express structural semantics. For example if you create a class of ‘important’ that is/was applied to content that is styled to visualize “important content” (bolder, different color,etc.) then you *do* have a problem, as that significance is not conveyed in a non-visual way – its just ‘decorated’ that way, so tread carefully.

    Also, while most CSS is pretty much ignored by screen readers, there is one important caveat: display:none;, which takes the content out of the page flow for screen readers as well. I have seen old-school ‘skipnav’ links wrapped in divs with display:none; often, and this effectively removes their exposure to their intended audience as well.

    Finally, speaking of hidden content and ignored CSS, you should also be aware that using something like this:

    .tip:before {content: ‘Tip: ‘;}

    …places that text (“Tip:”) out of the page flow as well – screen readers will NOT read aloud that text, so please don’t do this either .

    So while using classes usually doesn’t have an accessibility impact, what you do with those classes may.

    I am but a CSS grasshopper however, so thanks for teaching me so much with your articles.

    Cheers,
    JF

  5. The only question is the naming of CSS after applying this approach. I mean we’re currently elimination the cascading in CSS, and leave the SS only, but that sound bad.

    When I used ID’s in CSS, I often noticed that I group the similar parts of ID’s together, like

    #header,
    #footer {
    }

    and defined the differences only in

    #header {
    }

    while it would be a lot easier with classes. Classes are good, but ID’s are very very useful in JavaScript, just as you mentioned.

  6. Awesome article Nicole, I wish more folks would get especially the last point. I always try to avoid Classitis but heck, sometimes a class just is the best solution for the task at hand.

  7. I get what you’re saying is that we should only use IDs and descendant selectors in a very few selected cases, and classes for absolute everything else?

    You know, drinking too much water can be deadly. What about when an element has too many classes that you have trouble finding where it inherits a certain property from without resorting to Firebug. Or when you have to look at five different code blocks just to make sure you don’t declare a property twice; or to make sure you’re not inadvertently styling another element in a different page. This may easily happen when too many classes are used on a large enough site, and either without proper documents or with proper docs but no one reads them carefully enough.

  8. Hrm… the slides don’t seem to match the talk… I think you skipped the “Yummy data from Salesforce” slide in the presentation, I got lost for a second.

    Those stats are not too surprising really based on what I have worked on. A lot of the time I think it ends up being this:

    I need it to work now! Ahhhh! *hacking, inline css declarations, random stuff that doesn’t have any effect* It works! I will go back and fix it later.

  9. Nicole – thanks for clarifying that ID’s aren’t a total waste. They are excellent hooks into JavaScript and I’d be wary of doing it any other way (except by building up the site from JavaScript, which negates the need to have ID hooks… and then I’d be committing at least three varieties of web crimes punishable by shunning). They’re also not awful if you’ve got a static column layout that’s supposed to remain relatively inflexible… but that’s really the only use case for id styling I’ve ever used.

  10. A lot of it is also probably because of a lack of understanding of how css works.

    Case in point:

    a{}
    a:link,a:visited{}
    a:focus{}
    a:hover,a:active,li a.active{}

    All have the exact same style on a site I have had the opportunity to work on because the initial developer was just throwing stuff at the wall and when it stuck it was left alone.

  11. Nicole,
    I have been working on implementing OOCSS on our existing site for almost a year now. And I can understand a developers concerns with too many classes, and non-semantic elements. I think it takes more of a change of mind set to use OOCSS. You have to start looking at you pages in a different way, need to actually visualize the “Objects”. It was when I finally started to see this that things started to click. I now have these wonderful, reusable assets. Once the structures are in place, I have found that I can create new pages or modify existing once much easier. My pages have more flexibility and consistency.

  12. @John Foliot

    “”
    While it’s true that screen readers don’t read class names, this may still be a problem if you are using your class to visually express structural semantics. For example if you create a class of ‘important’ that is/was applied to content that is styled to visualize “important content” (bolder, different color,etc.) then you *do* have a problem, as that significance is not conveyed in a non-visual way – its just ‘decorated’ that way, so tread carefully.
    “”

    Actually, you can specify the audio style of the “important” to use a different voice, or to speak louder, or to speak slower. There is a whole (probably little used) subset of css that you can use to target screen readers:

    http://www.w3.org/TR/CSS2/aural.html

  13. I would like to propose that a practice that exists in other software development fields helps keep some of the chaos at bay: refactoring. You should make CSS changes that come with thought and therefore you still have to do things not by trying harder, but by principle and practice. It doesn’t make every project invincible, but it does make them less quickly corrupted.

  14. It should be noted, your point about classitis completely ignores the not insignificant performance loss of using classes instead of id’s. there is much lower overhead in looking for an id on a page. Your css example is also unnecessarily verbose. ID’s are by definition unique and are a perfect fit for unique page elements. Only got 1 login box? ID=”login” is perfect and faster for the browser to find and style. Your example above should only read #accountDetails h3 {} the other two ID’s aren’t needed.

  15. @SeanJA
    “Actually, you can specify the audio style of the “important” to use a different voice, or to speak louder, or to speak slower. There is a whole (probably little used) subset of css that you can use to target screen readers:”

    Really? I’ve never seen that work. Anywhere. Which is probably a good thing, because I notice I can listen to some voices at a comfortable speed and other voices, frankly, are garbage. So I’m glad you can’t change them on me :)

    @MikeBaxter agreed, that example is just bad code and not a good reason to switch to a class.

    .sidebar .accounts .accountDetails h3{}

    And when did “classitis” == “using a class”?? Classitis is what Drupal has: 500 classes on 15 wrapping divs around a single line of content. Classitis *is* a bad thing. Using a class to target something isn’t.

  16. The CSS are for the not high performance website. If for the high scale website we must do away with the CSS and to use higher performance system. The CSS is not the efficient, and has problem with the Asian languages.

  17. I’m a bit confused about CSS flexibility vs performance:

    I can see why .media-block is more flexible than div.media-block, there’s a clear advantage there.

    But doesn’t div.media-block win performance-wise, since in this case, only div-tags will be evaluated? Or is this a negligible performance difference? Or does it come down to ‘use both where they make most sense’?

  18. The number 1 feature CSS needs: class multi-inheritance. I want to be able to build style definitions from other style definitions.

    I think your talk infers this need throughout. CSS appears not to be designed by programmers using basic patterns but instead is an organic mess. It was never made for scale and the CSS powers that be have been lousey about advancing the standard forward.

  19. @brunodbo no, actually other way around: div.someclass is slower. The parser reads it “backwards”: it’ll first look for the class, and then check that the owner of that class is a div. The reason some devs say div.someclass is usually more to tell the humans what kind of tag they were targetting, for a small performance price.

    Also there were some situations you could get yourself in where other browsers were fine with .someclass overriding something but IE6 wanted a bit more “heaviness” and adding the tag name was enough (without needing to list an ancestor).

    Similarly, #someContainer #someInnerElement ul.someclass is much worse: first the class is found, then it’s checked if it’s on a ul, then the ul is checked if a descendant of #someInnerElement who is then checked to be a descendant of #someContainer. Instead, I’ll throw an id on that ul (if it’s important and special, like the main menu) and target it so: #mainMenu… if it’s a lesser ul who’s sharing styles with other uls, like all the uls who have actual bullets (ul.bullets) then I’ll still see if I can get away with either ul.bullets or just .bullets… and only mention an ancestor if I *must*.

    Or you can trade a slight CSS penalty for leaner code: if your #mainMenu is already in a special container (like #header) and it’s the only ul who’ll ever be in #header, you could leave off setting a token on that ul and call it with #header ul, #header li and #header ul a (unless no other anchors, then #header a). But those are indeed parsed just a hair slower than if you had targeted the ul directly (with an id, it may be found a hair faster than with a class, even if no other element has that class).

  20. Not meant for publication.

    Hi,

    Great article, thanks for sharing.

    I noticed that you consistently misspell the neuter possessive pronoun, “its”. It *never* takes an apostrophe–just like their gendered counterparts “his” and “hers” never do.

    The only legitimate use of “it’s” is as the contraction of “it is”. Thus, if you find yourself wondering whether to use “it’s” or “its”, simply expand “it’s” to “it is” and see if the sentence still makes sense.
    “its’” (apostrophe at the end of the word) has no legitimate uses at all.

    It may be too late to correct this very widespread error in the culture at large, but you can do your part by getting it right.

    Regards,

    Michael

  21. @Joshua K,

    Less (http://lesscss.org/) is your friend here. Unfortunately its not native to the CSS spec, so you will need a JS file for client side, or there is the server side option to actually take your “less” syntax and transform it into usable CSS.

  22. “I can see why .media-block is more flexible than div.media-block, there’s a clear advantage there.

    But doesn’t div.media-block win performance-wise, since in this case, only div-tags will be evaluated?”

    No. Browsers match against CSS selectors by reading right-to-left.

    To match against .media-block, the browser just has to check whether the element has a class of “media-block”.

    To match against div.media-block, the browser first checks whether the element has a class of “media-block”. If there is a match, it then checks whether the element is a div.

    Keeping your selector chains short actually speeds up the matching process. However, the performance difference from selector-matching is usually negligible. The real performance hit comes from massive, unmaintainable CSS — as Nicole has explained.

  23. Imagine if CSS had the kind of power over HTML elements that XAML Resource Dictionary ControlTemplates have over WPF controls. Maybe in CSS5/HTML7? That should be the goal.

  24. From what I understand about an id – it is used once per page, so would it not make sense to use id’s as the building blocks of your site? ex. id=”header” or id=”page-wrapper”

    Watching your video, I question a lot of the ways I have done css in the past, how things have evolved etc. I recently started using LESS (server side, no js) and quickly found that you really have to plan and analyze your sites much more than just creating with more standard css. Which in my mind is a good thing. I have found myself using a combination of head.js (without a lot of the garbage) as a hook for specific pages. So, I will create my classes that are most broad in scope, then target specific pages for differences.

    I can see where this can become very complicated as far as specificity for sure. However, I feel that by creating a bunch of classes to accomplish certain ‘global” styles – ex. class=”float-left clear sidebar grid6″ And maybe I sort of missed some of your point in the video, but I feel when you get a element with 5-6 classes attached, you should just be using inline styles. At that point, any change you make you have to go in and fool with the html instead of just dealing with the css.

    My ultimate goal in any project, rather it’s an online app or a website is to have the ability to completely change a layout without having to spend all my time in the html and do it mostly in the css. What are your thoughts? Am I completely missing the point?

    1. @Ryan You make a good point. It is definitely possible to be *too granular* with your classes.
      float-left clear sidebar grid6 is an example of being too granular.

  25. @Joshua Kincaid I concur!

    This would have been infinitely more useful and less error prone than the cascade, which is automatic. I find it ironic that what was touted as a major feature of CSS( the cascade ) is advised against by such luminaries as Ms. Nicole.

    What I really, really wish for is an end to the dogmatic adherence to the way the web is built. Its now 20 years later, more or less, since the creation of HTTP, HTML, a little later CSS and javascript. Being shackled to old ideas that, while great for the day, are now so archaic and plain crappy for developing complex applications just sucks. I mean, really, a *document* format as an application platform? Really? Sure we have things like gmail, but would you really want to write something like that in HTML? Hats off the the Google devs who suffered through creating that.

    Anyway, I digress… CSS is just not cut out for the job, and with the long, long life of Microsoft browsers, we’ll be suffering the sins of the past for decades to come. Wheeeee…..

  26. I come from the SGML and XML worlds, so my background is almost 100% semantic. Warnings against “classitis” sound like silly noob fussing to me — I’m glad you called it out. Why not keep things simple, as they were intended?

    an id identifies a specific instance of something (this paragraph, not that one).
    a class identifies a general type of something (an overview kind-of paragraph, not a warning kind-of paragraph.

    Lots of other SGML and XML document types allow both ids and some kind of class/type/category attribute, and people don’t seem to have a problem understanding how to use them — I’m not sure why the HTML id and class atts have caused so much gratuitous hair-pulling in the CSS world.

  27. Hello Nicole, I just discovered your blog and OOCSS idea and find them both absolutely great. Being a front-end developer myself I invented/ing my own philosophy, which is in may ways simular to yours (well, we all have to fight the same problems, at last).
    In my version, there are 3 main levels in document: a general template (some general blocks like header-body-footer), a structure (a set of positions / sizes that differentiates layouts of different pages) and elements, which are much like OOCSS modules and which can nest other elements as well. I also use namespaces, which are just a chain of classes in the body tag (simular to the breadcrumb) that allow me to speak the same elements differently, depending of their location: so I can have a generalized style for .headline and give it some variations on some specific sections of the site or single page. (Namespaces are created in .sass as variables). Where I go really differently is: all my “fresh” elements are isolated and can’t be reused. For a good reason: many of them are existing only because designer wanted something “special” on some special page. So, all elements from the beginning are selected with namespace – this assures me, that it’s styles would not appear on an other page a year later, when someone else creates an element with the same name or that it won’t be re-written because of the same problem. If designer adds later another page, I usually just add it’s namespace to list of the pages, where this styling must happen. If I see, that an element is being intensively used, I can delete namespace to “open” it’s styling for the whole site, or just modify namespace by deleting one segment of the chain to “open” it for some part of the site (chain is = breadcrumb). I also use .sass partials and a composing file to have all elements styled with their own file, which lay in their folders tree (named after the class of the elements top-parent), which also represents layout structure – so it’s supereasy to find place, where each element is styled. There are also a mix of naming / structuring conventions I use to be able to find elements easily.

  28. Is there another post where you explain why using IDs and descendant selectors is so bad? It’s mentioned a few times here as if everyone already agrees that’s the case.

Comments are closed.