Writing Clean CSS3 Code [updated]

One of the main problems with writing CSS3 code are the vendor prefixes. These are the -moz- or -webkit- you see before properties such as border-radius or text-shadow. They’re a necessary evil at worst and you’ll have to use them to get the most out of what CSS3 currently has to offer.

So what’s the problem? I’m very much a fan of the single line approach to writing CSS as seen below. It allows elements to sit under each other nicely, making them easier to find. Good commenting also helps.

The downside of vendor prefixes is declaring the same value more than once. Combine this with the single line approach above and you can see it starts to get messy with every CSS3 declaration on the same line. This will only get more difficult to read, with more CSS3 properties used.

I’m a designer so I can’t have my code looking messy and ugly, especially when you’re working on sites you know your workmates will be working on some point too. My solution is to keep the regular old CSS on a single line but split CSS3 onto separate lines defined by vendor prefixes. Not exactly earth-shattering but now it’s cleaner and much easier to read and edit all those declarations of the same property. They all sit under each other making them easier to compare to one another. I also start with the shortest at the top working my way to the longest, again just keeping everything consistent, neater and easier to read.

It even works well with extra CSS3 properties.

I take the same approach if I’m using rgba for the background colour of an element. The first declaration is for older browsers such as IE which ignore the rgba line.

Over to You

How do you deal with keeping your code beautiful and using multiple CSS3 vendor prefixes?

Update: As a few people have pointed out in the comments as well as a tweet from @nathansmith, you should be putting the vendor prefixes first and the final spec version last. See CSS-Tricks‘ comprehensive explanation.

Author

I'm the creater of Inspect Element and currently work as a senior web designer and developer for Factory Media. You can read my personal blog and follow me on Google+ and Twitter.

Discussion

  1. I use less (http://lesscss.org/). I set up a mixin for vendor prefix properties like so:

    .rounded (@radius) {
    -moz-border-radius: @radius;
    -webkit-border-radius: @radius;
    border-radius: @radius;
    }

    Then call it like this whenever I need rounded corners:

    div.roundedbox {
    .rounded (5px);
    }

    There’s a mac app that compiles .less files into .css on each save so that’s really all you need!

  2. origiNell says:

    I’m usually more the one-property-per-line css writer, so I keep my css3 properties in the following order:
    selector {
    css1 – 2.1 properties;
    css properties enhanced with css3 standard (layered backgrounds etc.);
    css3 properties (non vendor specific);
    vendor specific css3 properties ordered alphabetically;
    }

    If there are any keyframe animations I define them above the element they are going to happen. However I think it would keep stuff more readable when I’d define them below, have to try that out ;-)
    Nice thing is that the rendering engines are really tolerant, so when some old browser encounters f.e. a layered background..

    #bla {
    background: fuchsia url(‘whatever.gif’) 0 0 no-repeat;
    /* Layered background, getting some dirt on top */
    background: fuchsia url(‘whatever.gif’) 0 0 no-repeat, url(‘somedirt_ontop.gif’) 0 0 repeat-x;
    }

    .. it will ignore the unknown combination (background: bg1, bg2,..) and use the above defined as a fallback.

    Perfect for progressive enhancement *thumbs up* :-)

    Perfect for sticking to progressive enhancement :-)

  3. Great useful info, thank you!

  4. Steven Ringo says:

    The solution is dead-simple. Use SASS. http://sass-lang.com/

    With SASS mixins you define all the vendor-prefix variations once. And its a breeze to get it working. Yes, there is some post-processing involved but the benefits far outweigh the tiny bit of hassle. And if you’re using a framework like Rails, it just happens automatically anyway. Plus no need to learn any new syntax. SASS (the newer SCSS-flavour) is just a superset of CSS.

  5. imran khan says:

    i also follow the same hierarchy… but sometimes you have to write inline css… what you suggest for that. for bigger products sometimes i have to access of php pages, and i have to write inline css on that. thats a big mess

  6. Michael says:

    I’ve read a few articles discussing css code layout and came up with my own system. I found that any polarized idea (all on one line, all on separate lines) doesn’t work.

    The first thing I do is tab out from the selector. This addresses the “find where I’m going” problem. To keep my tabs as close as possible, I adjust then for each group of related rules. For example:
    a { blah }
    a:hover { blah
    blah }

    The second thing I do is group attributes on a line based on (in this order) Styling, Font, Layout, CSS3. Styling is borders, backgrounds, etc. The rest are self explanatory. For CSS3 styles, I put each group on it’s own line and I start with the non-vendor specific version.

    Here’s an example:

    .box { background-color: #f5f5f1; border: 9px solid #575753;
    margin: 10px 0;
    box-shadow: 0px 0px 30px rgba(219,219,216,.4); -webkit-box-shadow: 0px 0px 30px rgba(219,219,216,.4); -moz-box-shadow: 0px 0px 30px rgba(219,219,216,.4); }
    .box a { color: #535353; }

    I don’t wrap my lines when I code so you don’t get anything blocking the selectors like you see here.

    What do you think?

  7. Michael says:

    Opps, my examples don’t work because the comment doesn’t show tabs…

    Example 1:
    a { blah }
    a:hover { blah
    blah }

    Example 2:
    .box { background-color: #f5f5f1; border: 9px solid #575753;
    margin: 10px 0;
    box-shadow: 0px 0px 30px rgba(219,219,216,.4); -webkit-box-shadow: 0px 0px 30px rgba(219,219,216,.4); -moz-box-shadow: 0px 0px 30px rgba(219,219,216,.4); }
    .box a { color: #535353; }

    This still probably won’t look right but it’s better.

  8. dom says:

    nice article, thanks

  9. James says:

    I like it!

    I’ve been wondering how to work with separating out CSS3 properties from the rest. This could be the best way so far.

    This separates them and also removes the need for any CSS3 specific classes or a separate CSS file just for CSS3 enhancements.

    Cheers!

  10. Peter De Berdt says:

    A great way to manage the whole horror that CSS can quickly become is using Compass (http://compass-style.org/).

    I’m saying Compass here instead of SCSS or SASS (http://sass-lang.com/) because Compass already uses those, but in addition provides mixins that allow you to write things like:

    @include border-radius(4px, 4px);

    and this will generate

    -webkit-border-radius: 4px 4px;
    -moz-border-radius: 4px / 4px;
    -o-border-radius: 4px / 4px;
    -ms-border-radius: 4px / 4px;
    -khtml-border-radius: 4px / 4px;
    border-radius: 4px / 4px;

    One line, compile to CSS, instant gratification. You can set up compass to monitor your SCSS files and compile them to CSS each time the file changes.

    Definitely worth a look at!

  11. Edson says:

    Great article. In some cases (depending the project) I use the CSS3 at the bottom lower of the CSS file.
    It looks like this:

    .title { background:url(../img/bg_title.png) repeat-x; color:#fff; display:block; font-size:16px; font-weight:bold; height:25px; padding:6px 0 0 8px; }

    some other CSS

    /* FX/CSS3 */
    .title { -moz-border-radius:5px; -webkit-border-radius:5px; border-radius:5px; }

    So when some other element of the entire project needs border radius, I’ll append it right after.

  12. I asually create a second css file especially for CSS3 declarations, so my main stylesheet isn’t filled with ugly code. Also, when CSS3 is finally standarized; all I have to do is rewrite the CSS3-only file, instead of searching for possible hacks/fixes.

  13. Sam says:

    I keep each area/element clean by the below example.

    Sometimes to debug I’ll strip the attributes onto their own lines like your example but I always end up putting them back into one single line. By default my editor wraps my text. I guess putting the code into one line when I’m done with it is my little pet habit of “collapsing” the CSS.

    /**
    * Header
    */
    #header h1 { display:block; width:100%; height:100%; }

  14. Great read! I’ve been wondering about how other designers have solved this one.

    I usually have the “real” declaration in the main selector, then group vendor forks by them selves. When the vendor-forks become obsolete, I can easily remove the forks without harming the selector. e.g:

    /* ### Something ### */
    .something { background: #fff; border-radius: 5px; box-shadow: 0 1px 2px rgba(0,0,0,.5); }
    /* Forks */
    .something {
    -moz-border-radius: 5px; -webkit-border-radius: 5px;
    -moz-box-shadow: 0 1px 2px rgba(0,0,0,.5); -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.5);
    }

    Btw, I like your commenting-style… I might just adopt them. :-)

    • I really like the sound of this idea… easy to maintain in the future and allows you to write CSS as it should be written. Good styles! ;)

      @Tom – Great article, thanks.

    • If you choose to separate out the vendor prefixes into their own rules (not wise, IMO, as putting the styles for a single widget in two places is just asking for mistakes, but anyway), make sure you put the prefixed rule FIRST, not second, or at the end of your sheet. You should always make sure the non-prefixed, standard property comes last so that when a browser supports it, it will use it.

      For instance, in your example, Safari 5, which now uses plain border-radius, will override the border-radius property with your -webkit-border-radius property. This is not good, because Safari’s -webkit-border-radius property had a lot of bugs, whereas their implementation of border-radius is much more standards-compliant.

  15. Theo says:

    Nice and useful article. Will try some of the examples in the comments too. Thanks all !

  16. ?????? says:

    css3 is great but what to do with this beast IE :( :( :(

  17. Great read, thanks and these multiple prefix properties in CSS3 was something that irritated me quite a bit too; code became unnecessarily longer and indeed, messy. My approach to trying to keep it as clean as possible is the same, to use the multi-line approach. Even then, it sometimes gets a bit daft.

    .mystyle {css properties,
    -moz-properties,
    -webkit-properties}

    I do hope there’s an action to collate these into the one standard property in the not too distant future but for now, this is it…

  18. Alex Hall says:

    I have always used a multi-line syntax for writing my CSS, and indeed, for any language I like to keep things spaced out because I find it so much easier to read and debug. I’m not worried about the impact this has on loading speed because all files are compression when published anyways.

    This means that anyone can work a fully bloated, easy-to-read version of the files and then when they are published live they are automatically compressed (and obfuscated where possible).

    When it comes to CSS3 I like to make that stand out even more, simply because I tend to make more changes to that than anything else because it is in a constant state of flux. I just add an extra line between the last CSS rule and the first CSS3 rule of any selector. That way you always know to look at the bottom of a selector rule to find any CSS3.

  19. Dragan Eror says:

    It’s nice to read all this different experience of code practice :)
    While I working with Drupal, I’m using one simple rule

    1. CSS properties are alphabetical ordered

    Always!!!

    .someclass {
    -moz-border-radius: 5px;
    -moz-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.5);
    -webkit-border-radius: 5px;
    -webkit-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.5);
    background: #CCC;
    border: solid 1px #000;
    border-radius: 5px;
    box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.5);
    display: block;
    text-shadow: 0 1px 0 #fff;
    }

  20. Thnx so much for this post!! I found hard to get my css clean, is taking me time to get use to it, but with info like this one, makes me feel like i can see the light at the end of the tunnel!

  21. Steve says:

    Putting multiple CSS items on one line is terrible advice and you shouldn’t be persuading people to do it.

  22. Jeffri says:

    Well, I use separated file for CSS 3 property. This way, it will become easier to manage, as I did for IE specific CSS too. It adds one more http request, but for the sake of this, it’s not a big sacrifice. :)

    Also, I thought the standard CSS 3 property should placed at the bottom of vendor prefixes? This way we can ensure it will always use the standard property when it is available. I’m not sure about how vendor prefixes will work when they finally go to standard one, but I think it will be safer that way. (for example when the browser update to standard property, will they also update their vendor prefixes property? or they will leave the bug -if any- in vendor prefixes untouched? or maybe drop it?)

  23. Eugene says:

    I just came across this problem yesterday as I was starting to work with CSS3 and was debating a solution. I like this method. Thanks.

  24. Jeffrey says:

    Shouldn’t standard CSS3 property put after vendor specific properties? Like so:

    .box {
    -moz-border-radius:10px;
    -webkit-border-radius:10px;
    border-radius:10px;
    }

    Source:
    http://www.456bereastreet.com/archive/201009/remember_non-vendor-prefixed_css_3_properties_and_put_them_last/

  25. James Godwin says:

    Always great finding CSS tips, thanks

  26. Evan Mullins says:

    I prefer the single line as well for my css. The vendor prefixes has thrown a monkey wrench into keeping the code simple and neat. I usually do everything on single line and then include each property which requires vendor prefixes on it’s own new line. Very similar to yours, but I combine all the border properties on one line and so on. Then I hope once css3 is the new standard cleaning the css up will be simple, I’ll know that each line is for a new property. Thanks for the article!

  27. Splitting it over multiple lines makes sense. This is how its mostly done now. I dont like seeing it all on one line as its hard on the eyes.

  28. good explanation to write css

  29. Tom Kenny says:

    Thanks for the huge response! Seems like more people care about clean code than I thought.

    I can understand why people want to use a ‘solution’ such as LESS and SASS but honestly I don’t think they’re necessary at all. I like to feel in control when writing my CSS and the only way to do that is to write pure CSS from scratch. These intermediate tools get between myself and what I love. CSS.

    As always, use/do whatever works for you.

  30. @Tom I agree. You should never need to use IE hacks ever…..even though I use CSS3, I always have a clean fallback for it, and I refuse to use HTML5 until we no longer need to support IE7/8. IMO the mark of a good developer is one who doesn’t need .htc and .js hacks for their code ;)

  31. If no one has noted yet you should make sure to declare the unprefixed CSS3 property last so that when browsers drop their tags when a standard is decided on your sites will no longer be getting the old vendor prefixed way without really having to update.

  32. Dave says:

    This post is a coding style guide. Nice. Visual cues on code help development more than some developers imagine.

    I need to be true, I also prefer to create my own CSS manually, and don’t make use of any library. Even the best rated by the most known developers.

    Every single library proclame itself as “simple” and “lightweight”. But there are obvious and unescapable downsides. Band width usage and performance are the main.

    My approach with some CSS3 properties is the same as before. I use many different classes.

    .round {/*border-radius declarations*/}
    .boxShadow {/*box-shadow declarations*/}
    .gradient {/*gradient declarations*/}
    .white70 {/*rgba(255,255,255,.7)…*/}

    This is my preferred way to write CSS.

    For dealing wih IE, I use conditional comments, and make use of specific rules, keeping CSS and Javascript, when needed, in tiny separate files.

    Easy to maintain, valid, functional.

  33. Paul Irish says:

    single line ftw!

    but for css3 i typically break it out. I also enjoy the indentation pattern that is on http://css3please.com :

    -moz-box-shadow: 0px 0px 4px #ffffff;
    -webkit-box-shadow: 0px 0px 4px #ffffff;
    box-shadow: 0px 0px 4px #ffffff;

    (Hopefully that pre tag works, otherwise just go to css3please.. :)

    Once you have to tweak a value its much easier on the cursor than when they arent all vertically aligned.

  34. Reza says:

    Very informative and helpful. Thaks very much.

  35. CSS is like a new language to me. Took a while to get head around it, but eventually it all started to make sense. Thanks for the useful tips guys!! :)

  36. MyFreeWeb says:

    Check this out: http://cssprefixer.appspot.com

    If you use Python on the server side, you’ll love it very much :)

  37. Babu says:

    Really useful info…!!

  38. steff says:

    thanks for clearing things for us tom… these vendor prefixes really give me headaches sometimes

Become Part of the Discussion

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.