Skip to the navigation

Defensive coding and CSS: Preventing the most common bugs

This is the first installment in the Defensive coding and CSS series. I’ll be dealing with the most common CSS bugs and showing you how to avoid them by slightly changing your coding style.

In this first installment I’ll be covering these issues: CSS resets, clearing floats, double-margin, hasLayout, and #id.class bug. These are the bugs that, in my experience, happen the most often and sometimes cause other, more serious bugs.

Defensive coding is about preventing these bugs before they happen. If you don’t prevent them, they will be like an avalanche — there will be a lot of them interacting with each other, making it difficult to figure out what’s what.

CSS Resets

When I began coding with CSS many years ago, I didn’t know any good CSS resets; in fact, there were none back then. The difference in default styling of elements between browsers can cause margins, paddings, line-heights, and even some alignments to be completely different. That’s why I started using the * {margin: 0; padding: 0;} declaration to battle those bugs.

About three years ago I discovered that this approach was inefficient; not only that, it was also messing up my forms and causing all kinds of havoc. Since then, I’ve been using the popular CSS reset by Eric Meyer.

Eventually I decided to modify it and extend the reset to serve my purpose better. I created the aardvark.legs CSS framework which unifies the styling amongst all the popular browsers. This has proved to be a real time saver, because now I don’t have to spend as much time dealing with inconsistencies between browsers.

Clearing floats

I think everyone will agree that uncleared floats are often the cause of major bugs, especially in IE6. However, it’s a bug that is easy to fix. My favorite method is setting overflow: hidden; for the parent element containing the floats and then using conditional comments or hacks for IE6 to declare overflow: visible; height: 1%;. This ensures reliable cross-browser rendering and prevents any possible bugs associated with overflow: hidden; in IE6.

Dealing with double-margins in IE6

IE6 has another annoying bug when it comes to floats, called double-margin. It occurs when you float any element in IE6 and add a margin to it. Under these circumstances, IE6 decides to double the margin set and puts your element somewhere it shouldn’t be. This is easy to fix, and I’m always surprised that people don’t prevent this one before it happens.

The easiest way to avoid the double-margin bug is to set display: inline; on any element that you float. This way you will never have to see or worry about the bug again.

Dealing with hasLayout and its consequences

If you haven’t heard of the hasLayout term before, I recommend you read this useful article on it. If you have, read on.

The problem with hasLayout comes up quite often in coding. One of the most annoying variations of the bug is trying to use position: absolute; bottom: 0; and having the element appear somewhere completely different in IE6. The issue is, fortunately, easy to solve — you need to trigger hasLayout. This can be done in many different ways. My favorite is using conditional comments or IE6 hacks to set height: 1%. While there are other ways to give something a layout, this is by far the least problematic one, in my experience.

Again, it doesn’t hurt to think of it ahead of time. Whenever you add bottom: x; to your CSS, think of whether the container hasLayout or not. This way you will prevent the bug before it happens and won’t have to spend the extra time debugging.

The ID + multi-class bug

This is a bug that never got a name, or at least none that I can remember. It’s a peculiar beast and happens only in IE6 when you have this kind of code: #id, #id.class2, #id.class3. The first definition will be applied, but the other two won’t. The simplest way to avoid it is to not use the #id at all. Sometimes you need to take advantage of the cascade; in these situations, I recommend using #id, #wrapper .class2, #wrapper .class3. The two rules are more specific than just #id and at the same time don’t suffer from any bugs in IE6.

Don’t fix, prevent

Ultimately, this is not about the techniques; it’s about preventing the bugs rather than fixing them. If I was a proficient mathematician, I could probably give you some formula that would determine how much more time is spent on fixing a bug vs. preventing it. Since I’m not, you’ll just have to trust me…

Comments

  1. A very resourceful list, bookmarked :)

    #1Jarryd wrote this on February 2, 2009 at 4:25 pm

  2. Nice tips. You can also validate your XHTML document to ensure that you didn’t leave any tags unclosed. Thank you.

    #2Raymond Selda wrote this on February 2, 2009 at 7:05 pm

  3. Just from a hip: overflow: visible; height: 1%; is something I really don’t like. I hate messing with overflow and there is even better solution for most of the bugs: set a width (be it a 100% or px size) to it’s parent container.

    #3Ollie wrote this on February 2, 2009 at 11:48 pm

  4. CSS bugs? Surely you mean browser bugs? CSS does exactly as it should, it’s how browsers render it that’s the problem.

    #4Jem wrote this on February 3, 2009 at 12:54 am

  5. This is an excellent article. Simple and to the point, and hits on some of the most frustrating x-browser compatibility issues. Tricks/techniques like these should really be more prominent in training resources. Teach for the real world, not the “ideal” world.

    #5Jeremy Martin wrote this on February 3, 2009 at 5:13 am

  6. Great first installment, looking forward to more down the road! CSS resets have especially proved helpful since I stumbled across them a couple weeks ago.

    #6Stuart Thursby wrote this on February 3, 2009 at 7:46 am

  7. Just from a hip: overflow: visible; height: 1%; is something I really don’t like. I hate messing with overflow and there is even better solution for most of the bugs: set a width (be it a 100% or px size) to it’s parent container.

    Width doesn’t always solve it. More importantly, often times you can’t afford to set the width because you need the parent to be flexible. The reason I like my solution is because it doesn’t influence the layout in any way, except clearing the floats. Besides, setting width doesn’t clear floats, unlike setting height.

    CSS bugs? Surely you mean browser bugs? CSS does exactly as it should, it’s how browsers render it that’s the problem.

    Browser bugs is a very general term. There could be JS, CSS, HTML, etc. browser bugs. It’s obvious I’m talking about CSS browser bugs.

    Thanks to everyone else!

    #7Anatoli Papirovski wrote this on February 3, 2009 at 8:15 am

  8. For turning on hasLayout, I prefer zoom:1. As far as I can tell, it has no side effects and has no meaning at all to any other browser, so it’s safe to use anywhere as a hasLayout trigger. And it’s great for communicating to yourself months later–you’d never use the property otherwise, so whenever you see it you know that it’s there to turn on Layout for IE. I haven’t figured out why many people still seem to go for height:1%–any insight?

    #8Joshua Paine wrote this on February 3, 2009 at 10:36 am

  9. Joshua, that’s a good point. I’m, personally, simply used to using height: 1%; and I see no advantage to zoom. A couple of reservations I do have are minor: 1) it’s not valid, 2) it does not have an -ms- prefix, as such if somebody decides to one day implement zoom it could break something. The first is a boring excuse, the second could be a big problem but highly unlikely to happen.

    Therefore, if someone prefers to use zoom: 1; then that’s great. (The article I link to, in relation to hasLayout, mentions it, btw.)

    #9Anatoli Papirovski wrote this on February 3, 2009 at 3:37 pm

  10. Great write up! Thank you
    Though I have always wondered if some of these (or any other) bugs also affects IE7 since most bugs related articles are referring to IE6 only.

    #10AthenaEmily wrote this on February 4, 2009 at 8:41 am

  11. Though I have always wondered if some of these (or any other) bugs also affects IE7 since most bugs related articles are referring to IE6 only.

    The hasLayout issue sometimes comes up with IE7, but not too often. It can be solved by setting width or by setting zoom: 1; as mentioned above. But usually it can be worked around in other ways too.

    Other than that, none of these bugs really affect IE7.

    #11Anatoli Papirovski wrote this on February 4, 2009 at 8:45 am

  12. There are some rare cases where height:1% causes problems in IE6. If you want to use a height declaration to trigger hasLayout then use height:0. You should be serving these styles targeting IE in conditional stylesheets - no issues with invalid code served to modern browsers or risks of future css properties being introduced.

    To self-clear a container with floated children you should use min-height:0 for IE7.

    You will find that setting a width does trigger hasLayout in IE6, and hence, will clear floats. Therefore, there is no need for triggering hasLayout with an additional declaration if the element already has properties declared that trigger it.

    #12 • gareth hunt wrote this on February 5, 2009 at 2:52 am

  13. Great post, and I like that you are concentrating on preventing issues before they crop up rather than reacting to issues once they are on screen. I love the new blog and your posts so far have been very thoughtful. I’m looking forward to more advanced css practices from you in the future, added you to my rss feeds.

    #13Joel S wrote this on February 5, 2009 at 7:23 am

  14. There are some rare cases where height:1% causes problems in IE6. If you want to use a height declaration to trigger hasLayout then use height:0.

    I will disagree with this. height: 0; will cause exactly the same problems, in my experience.

    To self-clear a container with floated children you should use min-height:0 for IE7.

    Or instead of adding further code, you could just keep the overflow: hidden; that you already used for other browsers.

    You will find that setting a width does trigger hasLayout in IE6, and hence, will clear floats. Therefore, there is no need for triggering hasLayout with an additional declaration if the element already has properties declared that trigger it.

    However, I still need to set overflow: hidden; for other browsers and therefore if I decide to position something outside of the width of the box, it will be hidden. That’s not at all what I want to happen.

    With the solutions presented in this article I’m attempting to avoid nasty surprises, not just fix the bugs. I’m also attempting to do it with as little code as possible. And I do mention conditional comments.

    #14Anatoli Papirovski wrote this on February 5, 2009 at 7:34 am

Sorry, the comments are closed at this time.