cssbestpractice

Updated: December 29, 2011

Advanced CSS should be rewarding to both write and view later. Can you open up your most complex CSS file and browse it easily, still able to understand immediately how and why things were done when coming back to it later?

It has been said many times that CSS is easy to learn but difficult to master. Here is a list of tips that my help streamline your process.

Note: This article assumes some familiarity with CSS. However, even if you’re a beginner, the tips in this article are things you should think about! Learning good habits at the start prevents bad habits from getting out of control later. For more basic help with CSS’s structure, syntax, and capabilities, try CSS 101 for tips.

  1. Format rule sets in a readable, logical fashion.

    When you are writing thousands of lines of code, it becomes vital that you organize your CSS. Trust me, code-sifting can be nightmarish when you are under deadlines later (and don’t forget, when you’re searching for that one selector buried deep in the cascade, text editors almost all have a handy ctrl/cmd+F find shortcut).

    • Place selectors that only have one property on the same line.
    • Place selectors with more than one property on separate lines and alphabetize the properties.
    • Always use shorthand when possible.
    • When listing multiple selectors with the same declarations, list each selector (separated by commas) on its own line in a logical order; you may opt for alphabetical, but I prefer to list them in order of their placement in the cascade.
    div { font: normal 1em/1.5 Arial, Helvetica, sans-serif; }
    
    header,
    article section,
    li span {
        background: #fff url(images/img.png) 4px 100% no-repeat;
        margin: 15px 0 0;
        overflow: hidden;
        padding: 5px;
    }
    
  2. Comment your code.

    Commenting is a vital part of programming, but it’s useful for CSS as well. It’s helpful to separate your sections and mark any properties that seem ambiguous in their use. For example, to center an image vertically inside a containing element, you could set the line-height equal to the height of the container. At a glance, something like line-height: 450px seems like a strange value so it would be helpful to add a comment. This also helps when you accomplish difficult CSS tasks and want to reference them later (hint: save snippets).

    • Include a Table of Contents if you’ve got a long stylesheet.
    • Comment hex or RGB values for quick color reference.
    • Use comments as headings to separate sections of your stylesheet.
    • Use box model math comments; when subtracting padding and borders from widths/heights, it’s good to leave the total width/height in a comment.
    /* This is how CSS comments are formatted */
    
    /* Table of Contents:
    1. CSS Reset
    2. Basic body and layout styles
    3. Header
    etc */
    
    /* Colors:
    Gray (background) - #9b9b9b
    Red (requireds) - #9b0c0c
    Blue (link) - #2b899a
    etc */
    
    /*------------------------------------------------------------ Heading --*/
    
    /*---------------------------------------
    This is also a nice way to do headings
    ----------------------------------------*/
    
    div {  /* box model math comments */
        border: 3px solid #fff;
        height: 384px; /* 400px */
        padding: 5px;
        width: 534px; /* 550px */
    }
    
  3. Keep it clean & understand inheritance & cascading.

    To master CSS, you need to fully understand the Cascading part of Cascading Style Sheets as well as how inheritance works. Inexperienced coders may be tempted to use too much specificity or !important declarations (or even inline styles!) to “cheat” the cascade. These techniques should almost never be necessary.

    • Use inheritance properly. Avoid !important declarations unless they are absolutely necessary. To learn more about inheritance and cascading, visit the W3C’s specs.
    • Use efficient selectors. Specificity should be used to resolve issues in the cascade, not as a “general” practice. It increases the weight of your stylesheet and can cause problems with inheritance (or a lack of inheritance) if used when not needed. You especially don’t need to overuse selectors when you’re dealing with IDs: IDs, by definition, are unique, so placing a lot of selectors before them serves no purpose except to make the browser continue fetching when it doesn’t have to.
      body div#wrapper article.first header h3 { padding: 6px 0; }
      body div#wrapper article.first header nav { color: #444; }
      body div#wrapper article.first header nav ul li { color: #0048ff; }
      

      This site can help you understand the lack of need for excess specificity: Go Fetch Yourself.

      article.first h3 { padding: 6px 0; }
      article.first nav { color: #444; }
      article.first nav li { color: #0048ff; }
      

      If you are targeting the children of specific elements but do not need extra selectors for cascading purposes, you can use indenting to help clarify where things are located in the DOM.

      article header { padding: 5px; }
          p.in-article-header-only { color: #ff0000; }
              header span { text-transform: uppercase; }
      
    • Consider using classes to style rather than IDs whenever possible. You can, of course, continue to use IDs in HTML to designate unique elements, but styling with classes makes your code more flexible and easier to manipulate.
    • Avoid using too many classes for abstraction. Good, clean CSS should never use a load of abstracted classes dispersed liberally through your HTML. (This is a common danger in “enterprise” CSS.) It’s easy and quick to implement, and therefore gains potential for abuse. This is a very fast path to unmaintainable code that completely defeats the purpose of CSS: to separate the styles from the content. If you overuse classes in this fashion, you would actually be better off writing inline styles.
      .float-left { float: left !important; }
      .float-right { float: right !important; }
      .text-right { text-align: right !important; }
      .text-left { text-align: left !important; }
      .mt0 { margin-top: 0 !important; }
      .mt5 { margin-top: 5px !important; }
      .mt10 { margin-top: 10px !important; }
      .pb10 { padding-bottom: 10px !important; }
      .pb15 { padding-bottom: 15px !important; }
      .black { color: #000 !important; }
      
  4. Learn & use advanced CSS selectors.

    CSS can do a lot of things natively, including some things that you may have previously thought could only be accomplished with the aid of JavaScript. I won’t go into all the advanced CSS selectors here because Jeffrey Way’s article on NetTuts+ has already done just that.

    I highly recommend you read the linked article and become familiar with the more advanced selectors; they can be extremely valuable, especially when you are ready to move on from too many class names and get back to HTML minus all the clutter. Some of the selectors I especially recommend are the following:

    • Siblings: X ~ Y — selects Y elements that are siblings following X element
      div ~ p { margin: 0; }
      
      /* targets all <p>s that are siblings following the <div> */
      
    • Adjacent siblings: X + Y— selects only the Y element that is preceded by X element
      div + ul { margin: 10px 0; }
      
      /* targets only the first <ul> directly following a <div>
      Will not target any <ul>s after the first <ul> preceded by the <div> */
      
    • Immediate children: X > Y — selects only direct children Y in parent X
      div > p { color: blue; }
      
      /* targets only the <p>s that are immediate children of the <div>
      Will not target <p>s inside another element that is inside the <div> */
      
    • Attribute selectors: X[attr=value], etc. — selects elements that have the specified attribute
      a[rel] { text-decoration: none; }
      /* targets selectors with the specified attribute regardless of value
      IE. <a rel="photobox" href="#"> */
      
      input[type=text] { border: 1px solid #000; }
      /* targets selectors with a specific attribute value
      IE. <input type="text" name="your-name"> */
      
      div[id*=post-] { margin: 20px 0; }
      /* targets element with attribute containing this value
      IE. <div id="post-34">, <div id="new-post-1">, etc */
      
      a[href^=http] { background: url(external-link.gif) 100% 50%; }
      /* targets element with an attribute starting with the specified value
      IE. <a href="http://google.com"> but NOT <a href="extra.htm"> */
      
      a[href$=.jpg] { background: url(jpg-ext.gif) 100% 50%; }
      /* targets element with an attribute ending in the specified value
      IE. <a href="foo.jpg"> but NOT <a href="bar.gif"> */
      

    Support: All of the above-listed selectors are supported by IE7+, Firefox, Chrome, Safari, and Opera.

    Again, these are only a few of the advanced selectors available to practitioners of CSS. I encourage you to research more of them on your own and find ones that will be especially useful to you.

  5. Avoid hacks.

    I’m sure every seasoned CSS developer has seen the notorious IE CSS hacks. You may have done research to find out which ones validate and which don’t; how reliable they are and how they stand up to the test of time. Hacks are one of those things that continue to plague us as CSS itself often utilizes hack-like solutions to fix complex layout issues across browsers.

    Regardless, browser-specific hacks should be avoided whenever possible. There are a few solutions to dealing with the browser-specific CSS that do not require the use of hacks. These include: separate, conditional stylesheets, conditional classes for different browsers, and JavaScript tricks.

    I use conditional comments for browser-specific body classes (additional information on conditional comments). Some people opt to do a class for each individual version of Internet Explorer; however, I’ve found that since IE8 fixes are typically also needed in IE7, I use a more generalized ie class for both IE7 and IE8. Then IE7 gets its own class as well.

    What about IE9? Since it came out of beta, I have found IE9 to render consistently with other modern browsers most of the time.

    <!--[if IE 7]><body class="ie ie7"><![endif]-->
    <!--[if IE 8]><body class="ie"><![endif]-->
    <!--[if gte IE 9|!IE]><!--><body><!-- <![endif]-->
    

    The CSS utilizes the body classes to override modern browser styles via specificity. Just add the necessary rule set and prefix the selector with .ie (etc). The IE-specific selectors will only be called if the specified version of IE is being used.

    div { padding: 5px; } /* targets all browsers */
    .ie div { padding: 4px 3px; } /* targets IE7-8 */
    .ie7 div { padding: 3px; } /* targets IE7 only */
    

    What about IE6? I have stopped support for IE6, as should everyone. Microsoft officially wants to reduce use of IE6 to less than 1% worldwide. They are encouraging users to stop using it and discourage continued support. If you absolutely need to support it for some reason, you can utilize the technique above— but be advised that it is a ten-year-old browser version. Using it should not be encouraged!

  6. Do things right every time, not just the first time.

    It is very easy to take care to do things right the first time a site is implemented. Then, when you have to update later, it can be tempting to slap in quick fixes — like abstractions — that are less than ideal for the longevity of your code quality. If you aren’t careful with your code maintenance, you will end up with bad-practice enterprise CSS.

    So don’t be lazy. If you took the time to do it right at first build, take the time to ensure that it stays maintainable. Your code could be thousands of lines long if it’s a complex site, but it will be worth it to put new selectors in the right place and to alter existing selectors rather than adding abstractions and overriding inheritance.

    And if you’ve done a good job of documenting and organizing clean, solid code in the first place, updates should not be painful!

  7. Don’t be afraid of the future.

    Over the years, the debate over whether or not CSS3 and HTML5 should be put into use has softened as more and more developers get on the future-bandwagon. As long as your code degrades gracefully and fall-backs for unsupported browsers are provided, there is no reason not to take advantage of new features. The W3C already has experimental support for HTML5 and CSS3 validation (though beware of a few bugs).

    Do websites need to look exactly the same in every browser?

    No. Well, mostly no. It’s true that there are clients who will demand that their site look pixel-perfect in Internet Explorer 6 as well as Firefox. When this is the case, it’s a toss-up between arguing for progression and sticking by what you know works and remains consistent. Make your call wisely on a per-site basis, but beware: the web moves fast, and those not willing to embrace the future will find themselves left behind very quickly.