CSS Best Practices and a Return to the Basics

by keif on October 26, 2009

This article is not about learning CSS. It’s about having a set architecture in a project when moving forward. One of the first things in beginning development is setting in place a best practice procedure when moving forward – it’s not saying “there is only one way”, it’s saying “for this project, this is how we are moving forward.”

Rule: Choose a Browser Reset Style Sheet

Choose one, or don’t use one.

This helps you on your cross-browser journey. If we reset all browsers to zero, it allows you to spend less time figuring out why margins are inconsistent amongst your unordered list elements (<ul>). This also sets you up to have a default font-family and consistent font-sizes, line-heights, etc. This is most important when cross-browser similarity is a high-concern.

CSS Resets are Bad, M’Kay?

Jonathan Snook stated that he “…okay if the various browsers show things slightly differently.” Jens Meiert also states CSS Resets are bad because they essentially add up to a defined style being overwritten repeatedly, adding to network latency due to the multiple requests for CSS. Then follows up with the comment of using * { margin: 0; padding: 0; } which itself is a bit of a hack and causes performance issues.

To be honest, the argument that CSS Resets/the * hack are a bit of a red-herring. For the majority of clients/sites I’ve worked on, this has been an incredibly minor concern. We’re talking milliseconds. Not even on the radar type performance hits. If you want to squeeze every millisecond (and I do) this is kind of an extreme (even for me) case.

Unfortunately, not all of us are as lucky as Snook and we work with clients/creatives that are not okay with things being a few pixels off sometimes. Personally, I’m with Snook.

Should You Choose To Reset

You have several to choose from:

Rule: Link States

This is referred to as the “LoVe HaTe” rule. :link :visited :hover :active
This relates to CSS specificity, below.

Rule: CSS Specificity

Eric Meyer has a great article on CSS specificity in general that I find lame when sites try to duplicate his article with their own “twist.”
I fully admit, I suffer from over specificity. For good measure, you can read Google’s article about CSS specifity and the increase in performance by using effective CSS selectors.

To reiterate certain aspects, DON’T put a class and ID on everything.

div.imageHolder img#imageHolderImage /* this is BAD */
div.imageHolder img /* this is BETTER */
.imageholder img /* ding ding ding! we have a winner! */

As well, don’t code things inappropriately, i.e. use nested divs/p to generate what is essentially an unordered list.

  • Target the first item
  • General list item
  • Target the last item

Rule: Naming Convention

We won’t dwell on this. BE GENERIC. It’s better to have “.active” or “.select” and NOT “.greenActiveText” – what happens when green active text becomes orange? Now you have a poorly named class.
Also, pick a naming structure and STICK TO IT. camelCase? Dashes-instead? Hell_underscores_are_okay, AS LONG AS YOU ARE CONSISTENT. Do not change it up. This is extremely important walking on to a project. If you walk in and the prior developer is doing it different than you are used to, ADOPT THEIR STYLE, DO NOT REWRITE IT, ADD TO IT, OR MAKE IT MORE COMPLEX THAN NEED BE.

Rule: Shorthand

Use it. Know it. Love it.

div {
	background-image: url("to/some/image");
	background-repeat: repeat-x;
	border-width: unit;
	border-style: (solid dashed dotted double);
	border-color: color || #hex || (rgb / % || 0-255);
	color: #669900;
	margin-top: 10px;
	margin-right: 9px;
	margin-bottom: 8px;
	margin-left: 7px;
	padding-top: 10px;
	padding-right: 5px;
	padding-bottom: 10px;
	padding-left: 0px;
div {
	background: url(to/some/image) repeat-x;
	border:border-width border-style border-color;
	color: #690;
	margin: 10px 9px 8px 7px;
	padding: 10px 5px 10px 0;

Notice the “0” has no identifier. It doesn’t need one. Notice 13 lines became 5. Love that. We also dropped the quotes to prevent any possible browser errors. Get to know your CSS shorthand.

Rule: Browser Targeting

For the love of God, they’re called hacks for a reason. They are hacky. They shouldn’t work, but do. You could fuck another browser down the line. You could introduce errors. DO NOT USE BROWSER HACKS This is a bigger sign that *you* are a hack and a not a proper developer. These are the “once in a lifetime” things that come up.

Except for IE.

Fortunately, IE has a nice, clean targeting system. Conditonal comments. If you target IE, use Conditional Comments.

Rule: CSS Behaviors Require JavaScript

If you’re writing CSS Behaviors, move it into JavaScript. Plain and simple. There is no reason to have CSS behaviors. At all.

Rule: Organize Your CSS

I know this one can be a bitch. The project can change. Your initial strucutre may not make sense. But try to organize it to prevent redundancy.

Alphabetize Yo’ Self

I alphabetize my CSS because I find it easy to read, search, and peruse. I also use a code highlighter in jEdit. Others group it by property (font styling, positioning, dimensions). I prefer my way, but that doesn’t make it right. Just when I’m leading the project.

Rule: Comment, Comment, Comment!

Comment the shit out of anything you are handing off. Eat the bytes. But don’t go crazy. /* this is a comment */ not /*——————– (several lines of this) CODE COMMENT (repeat several lines) ———-*/ Keep it simple. Keep it common sense. Break it up by section (however you organize your CSS).

Rule: The DO NOT Do List:

Don’t do these.

Don’t Use Inline Styles. Period.

Inline styles defeat the whole “separation of content and design.” Maintenance becomes a bitch, frankly. You also add to page weight, and can cause issues when a developer doesn’t realize you’ve done things inline and their properly coded external styles are not working properly.

But Keif, I do this all the time in development… – that’s fine, Timmy, but if you “accidentally” leave one in to production, or check it into SVN/CVS/Git and try to act like it’s not your fault, you’ve proven the point why you shouldn’t do this.

Reuse a “Standard” Set of Specific Styles

I don’t mean reset. I don’t mean element specific/font styling type items. I mean don’t use classes that are specific. #width100 .marginLeft25. This is representative of bad coding in general.

Now, this is a brief overview of many “best practices” I try to run with and improve upon. Google CSS Best Practices and you’ll find a slew of additional resources. Not all of them will agree with me – but that’s not the point. The point is understanding them, and recognizing that someone else’s preference may override your own, and my not be technically wrong. If you fail to recognize this, you need to reconsider your role and what you’re doing – you need to be both a team player that can adapt and evolve, and an innovator should you be charged with leading the effort.

What do you have? Send me your best (or worst you’ve seen!)

  • Braxo

    In your rule CSS Behaviors Require JavaScript, how strict do you go with that?

    I even go as far as to separate the CSS :hover effects to javascript as I view them as behaviors and snazzy extra functionality.

    I am strict with content in db, html for markup, css for styles, js for behavior

  • Pingback: Tweets that mention CSS Best Practices and a Return to the Basics – iKeif – tech and social media geek, mootools fan, and a ton of links — iKeif - tech and social media geek, mootools fan, and a ton of links -- Topsy.com()

  • http://ikeif.net keif

    I go all the way strict – CSS Behaviors (an IE methodology) require JavaScript to be used, therefore they should just be entered in as plain JavaScript.

    The CSS a:hover work, period. Generally, I'll still utilize :hover when I can as CSS is seldom disabled, so most browsers still get a better experience than those that require JavaScript. Which is usually just IE.

  • http://jason.karns.name jasonkarns

    Rule: CSS Specificity
    I admit, I tend to get a little carried away here. In general I do a good job keeping my selectors to a minimum, but I also like to throw in an extra element or two (or class or id) to help show the HTML structure in the CSS.

    Rule: Link States
    You're missing one! :focus. Never leave out focus, else your styles will tend to only be mouse-friendly. Be sure to add :focus to any :hover rule and you've got both the keyboard *and* the mouse covered. The mnemonic I use for the rule order is: Lord Vader's Former Handle, Anakin (:link, :visited, :focus, :hover, :active).

    Rule: CSS Behaviors
    No reason for CSS behaviors at all? Really? Not even as an IE PNG Fix (ala Twin Helix)?

  • http://ikeif.net keif

    CSS Specificity is more of a “destination” – I'm not nearly efficient as I should be, and I agree that sometimes adding in elements can help navigate a CSS file.

    However, it could be argued that CSS commenting could negate the need for the element specificity (but then we're back to debating “how many milliseconds is this costing us?”)

    Totally missed :focus, thanks.

    No reason for CSS Behaviors. At all. Twin Helix's htc file is just JavaScript shoved into an HTC file. There are one hundred (plus one) solutions for PNG's utilizing VML or AlphaImageLoader that don't try to hide behind the HTC that are just as effective (and some could argue that VML is *more* effective).

    I'm looking into the HTC rounded corners fix, but I have a feeling that it too will fall into the “should be JavaScript” – unless someone can generate the benchmarks that say going the HTC route is actually more effective than a pure JavaScript route.

  • http://jason.karns.name jasonkarns

    I agree that the Twin Helix technique is nothing more than a JavaScript solution in HTC clothing. However, when you're throwing in a CSS behavior to fix a browser issue, I don't see anything wrong with it. You've already got your IE-specific stylesheet being included via Conditional Comments. No need to reference another JavaScript file when you can just as easily drop in behavior references. Using IE's proprietary features to patch IE bugs is perfectly fine in my book. CSS expressions (when written properly to avoid the performance hit) can patch in support for position:fixed, and max-height/width. Throw in another HTC for whatever:hover. Although if you need all of these features patched, I would rather drop in Dean Edwards' IE7 script and be done with it.

  • http://ikeif.net keif

    My issue with it, is you're creating additional server requests – to a CSS file, to an HTC file, to fire off JavaScript – why not just request JavaScript? On top of the number of issues that the TwinHelix “fix” can introduct, including the need of a custom htaccess file, it doesn't work with PNG backgrounds and links and needing to possibly set the content expiration (http://support.microsoft.com/default.aspx?scid=…) to fix excessive server requests. A whole slew of issues that can be overlooked until it's in production, or on a client's server that you can't necessarily easily fix on your end.

    Dean Edward's IE7 script is a hack itself – it creates the illusion that CSS will work properly versus actually coding to account for it. You end up writing “advanced” CSS that fails without JavaScript, which can introduce more issues, particularly if you utilize it in addition to other JavaScript frameworks.

    The issue with the IE7 script, is it is Dean Edward's script – there is no community of support. It has 12 accepted defects since January of 2008, and a total of 166 bugs – if there was a strong community behind it, I might say “okay” but it's just a simple “throw it in, hope it works” which can introduce more issues than it fixes, particularly since he considers it a “beta” project. I much prefer to write valid CSS that is cross-browser compliant and progressively enhance the site through the use of CSS3 and a JavaScript library to achieve cross-browser compliance.

    For a majority of clients, a JavaScript solution to make it work is not a valid one if it prevents the site from functioning.

  • http://jason.karns.name jasonkarns

    Ah, I wasn't aware of IE6's issue with caching HTC files. Although I don't generally worry about overhead for IE6 workarounds that only affect IE6 users. Say your IE6 audience is ~24% (current IE usage is about 65% spread evenly over 6,7, and 8). Of those users, I would be willing to wager that over 75% of them are using IE6 due to IT lockdown, which means they are surfing your site on a T1 or T3 line. And if you declare all of your CSS behaviors with one selector, you only have one request.

    As for TwinHelix in particular, yes there are certainly issues with it. But they are not due to the HTC, only the AlphaImageLoader technique in general. A standard JS library using the AlphaImageLoader has the same issues. And I prefer using the VML technique via DD_belatedPNG when the situation calls for it (which it nearly always does). However, this technique has its own problems, namely when the 'fixed' element's position or display properties are modified via JS.

    I generally agree with everything you mentioned regarding the IE7 script. However, from my experience with it, the only fixes the script provides (that I rely on) are for 'nice-to-haves' that don't affect functionality. Things like :hover on non-anchors, :first-child, and :last-child which rarely do anything than change a border or margin property. The lack of these and other layout fixes does not impair the functionality of a site, merely its presentation, which is a perfect case for a JS solution.

    And I'm completely ignoring the fact that IE7.js doesn't work with other libraries. I only use it with jQuery thanks to jQuery's namespacing (which is an entirely different conversation, ala MooTools). If I need MooTools or Prototype, et al. then IE7.js is out of the question.

  • http://ikeif.net keif

    The issue with writing off IE6 as a corporate lock down, is that is your target selling audience – if your client is on IE6, and you try to argue that “most of your users will have a better experience” you won't get a warm reception. As well, one request for one HTC file that is something that could be broken out into multiple JS/CSS files (targeting specific pages, layouts, whatever) brings up the issue again (but this still falls in the “oh gee, it's an extra 30ms”).

    I hate AlphaImageLoader, and the more I've tested against DD_belatedPNG the more I'm liking it. I've only seen one situation it would've needed to be tweaked for past code.

    I still am not sold on using a JS fix for CSS items – it's a pain in the ass, but .first/.last isn't too much to ask to give it the same experience without the JavaScript overhead.

    AAANNND lastly – MooTools is namespace. I think Prototype and Dojo are not, but I'm not going to research the various JS libraries to see which ones still do/do not have this accounted for (maybe a future post?)

  • http://jason.karns.name jasonkarns

    I would like to see a post concerning how the various libraries handle namespacing. And perhaps I boiled the subject down a little too far. The reason I brought it up is that IE7.js works perfectly well with jQuery but not with most other libraries out there. MooTools declares at least 15 global functions. It may be 'namespaced' with its modularity, but that's false advertising when you extend natives the way it does. And extending natives is the reason IE7.js doesn't work with MooTools out of the box. So you can call MooTools namespaced, but it may as well not be.

  • walterg2

    While I would agree that inline styles are, generally, a bad practice, there are still some very valid reasons for using them, hopefully sparingly, within a site. I would say that 99.999% of those reasons are around the use of a CMS, where the user wants to have control of which background images are used for a reusable element. Without the use of inline styles, the user would need to lean on development to update and release the CSS files each and every time a new piece of content is needed using that “template”.

    Again, it's only in extreme circumstances that inline styles should be considered, but they shouldn't be discounted if you can still control the mechanism that the user will be using to add those in (i.e. – CMS).

  • http://ikeif.net keif

    It *can* be argued that inline styles are acceptable in some cases (i.e. CMS systems, or the current design showcase of “make each blog post it's own style”) but I feel it needs to be drilled in to most devs to NOT use inline styles, period, as when they increase their competence they'll see inline styles as valid in extreme circumstances.

  • http://ikeif.net keif

    It *can* be argued that inline styles are acceptable in some cases (i.e. CMS systems, or the current design showcase of “make each blog post it's own style”) but I feel it needs to be drilled in to most devs to NOT use inline styles, period, as when they increase their competence they'll see inline styles as valid in extreme circumstances.

  • Dr Gregg Ramsay

    Nice blog here. One question though, are the CSS rules yours or are they others that you've collected along the way?

  • http://ikeif.net keif

    A combination! Some things I've done because I liked it, and found it reinforced, others are the process of reading, educating, testing and discussion.

Previous post:

Next post: