Feb 11 '08
A Better CSS Reset
There’s a laundry list of issues to address when trying to make your sites behave across browsers. And there are things that aren’t even really browser dependent so much as platform dependent, like a certain someone who shall remain nameless (cough, Windows) who has a penchant for displaying text without anti-aliasing. But of all the issues (or at least those that don’t pertain to Internet Exploder making its own rules), the one most frustrating is the fact that you can write perfect code, and valid CSS, and somehow still end up with browsers not playing nice-nice. So what gives? Browser defaults, that’s what.
This has all been written about many times, but it boils down to the fact that each browser has not only its own rules for displaying CSS styled content (yup, even the standards compliant ones), but also its own default settings for font sizes, line heights, and the like. I could spend the time to explain them all and how they work, but I prefer to cut to the chase. The solution is a CSS reset of which there are a plethora floating around — there’s one unbelievably bloated one from Yahoo, and another more popular and reasonable one from the ubiquitous Eric Meyer.
But of course this is my blog, here is the revised reset I have come up with and put into use recently, taking what I believe is the best of what’s out there and mixing in some of my personal experience (and a few simple predefined classes that will make your workflow easier and more efficient).
If you don’t care about my explanation you can download the bn reset right here.
/* —[ THE bn RESET ]— */
html, body {
font-size: 10px;
margin: 0;
padding: 0;
line-height: 1;
}
* {
font-size: 1em;
margin: 0;
padding: 0;
outline: 0;
vertical-align: baseline;
}
img { border: none; }
ul, ol, li { list-style: none; }
:focus { outline: none; }
table, td, form, fieldset {
border: none;
border-collapse:
collapse; border-spacing: 0;
}
/* —[ REUSABLE CLASSES ]— */
.hide { display: none; }
.right { float: right; }
.left { float: left; }
.current { cursor: default; }
.clear {
clear: both;
height: 0;
margin: 0;
padding: 0;
line-height: 0;
font-size: 1px;
overflow: hidden;
}
Yup, that’s it! So let’s explain this in chunks. First, the two statements at the top: redefining the body and html tags, and then using the universal selector (*) to reset a whole mess of crap all at once. The idea here is pretty simple — I want to clear out all margins, padding, line-heights, and other predefined characteristics of HTML and CSS elements. Doing this in the body and html tags does a fair job, but I want to get rid of all the formatting associated with lists and things like that as well. This is where the universal selector comes in. This zeros out almost all the styling, formatting, and browser defaults all in one shot. It also serves the dual purpose of forcing me to explicitly define everything that’s happening on the page. Things like lists, which are indented by default, are now snapped to the margin like everything else and I can command them as I see fit.
The main question I always get at this point is why did I set the font size of the body and html tags to 10px, and then switch over to 1em for the universal selector. Well, two reasons: first, because different browsers have different default font sizes and while there are varying ways to handle this, for me the simplest is to reset the font size of my page down to 10px. Then I can use em settings — which is my measurement tool of choice for reasons I’ll not go into here — throughout my code, and I know that my starting numbers are always multiples of 10. So, for instance, if I want the font size of my h1 tags to be 18px, I just set them at 1.8em. Easy peasy. It should be noted here that there are some times this gets a bit confusing, since font sizes are inherited by child elements. For example, if I set the font size of the p tag to be 1.2em, and then the font size of the span tag to be 2em, and I put that span inside a p tag, what I end up with is a span with a font size of 24px (1.2em x 10px = 12px for the p, and 12px x 2em = 24px for the span). So keep that in mind.
The second reason why I do this is for scalability. If for some reason I need to adjust the font sizes of my project in any kind of universal way, these preset values of 10px and 1em can be adjusted and the changes will cascade down to the child elements. CSS is all about saving you from massive cut and paste jobs, so this is yet another great example.
Now, the next bit of code here covers a bunch of minor resets that are important but not things we want to apply universally. The easy one is removing borders from your images, but the others are often overlooked and very useful. The list (ul, ol, and li) elements are cleared out so I can use them however I like. I find it’s pretty rare that I show a real “bulleted list” anymore, or at least one without custom bullets or formatting, so why bother clearing it out each time. I clear that bitch out once and then put it back if I need it. The :focus pseudo-class is cleared out so you can steer clear of those stupid dotted outlines on links you click, and then comes the big daddy for me: table and form.
Tables and forms are the bane of most designers’ / coders’ existence to some degree because they just don’t behave dependably across browsers. Enter the border-collapse property. If you’re anything like me and you want your layouts to do what they’re told, even to the pixel, this is your best friend. Forms and tables (and their child elements like td and fieldset tags) have borders, even when you tell them not to. Even if you set a table’s property as border: 0, some browsers will still add in that damned extra pixel — albeit without any visually representation, just a space you can’t get rid of. This magical and wildly underused property clears out the problem and forces all browsers to hide the borders on these elements unless you explicitly tell them otherwise. That’s right… do as your told.
Finally, my reset includes a couple of fairly obvious but very handy classes that I use constantly. They’re pretty straightforward, so I’ll spare you the explanation, but keeping in mind that an element can be assigned multiple classes at once (like, for instance, <a class="right current">), these five preset classes will allow you to make your code dance without writing custom classes or added superfluous attributes to stuff you’ll only use once or twice.
CSS is all about extensibility… so use it the way it’s supposed to be used. Zero things out, ask them to do what you want, and set up classes that you can reuse constantly. Don’t reinvent the wheel, just borrow from us kind and generous souls who are happy to share the love and help bn reset your browser.
6 comments
Very good stuff here, thanks! Your article underscores a gripe I have with CSS - it’s designed to save time and be flexible, but unless you get really serious about mastering it, it’ll just annoy the hell out of you and eat up all your time. I suppose every bit of technology has a learning curve, but the learning curve for CSS is very high for a technology that is (or should be) so commonly adopted.
Excellent information in this article, Clint. I’m glad that the rest of us get to benefit from your experience here.
Thanks guys - glad it helped!
@Mark, Snooth actually uses a very nascent version of this I was tinkering with a while back. If you want to see how off base I was at the time, put this reset in the global style sheet right after the one that’s there now and watch how the site practically shits itself. Good for a goof anyway…
[...] but suffice it to say it evens the playing field across browsers (as best as possible). I know a pretty good one you can use to get started (wink wink), which is of course based partly off the work of Eric Meyer, the [...]
I have started looking at CSS frameworks and reset style sheets lately, and I have come to a basic conclusion.
Why reset? Set instead. Simply put, replace your reset style sheet with one that SETs all the basic styles to the defaults you would like to start from instead. You still get a good baseline across browsers by setting all your styles to a standard format. I just don’t see the point of doing something to force me to specifically undo it later. I would much rather start with a style sheet that has a reasonable starting point that overrides the differences between browsers while at the same time making elements appear as I would expect them to everywhere.
So how about we see the death of the reset style sheet and the birth of frameworks with set style sheets. I think I will work on creating my own set.css in the near future.
It’s actually the same thing John, simply semantics. The only difference between “reset” and “set” is that “set” actually takes the extra step of creating a baseline set of presentational styles which you can use as a foundation.
But in order to accurately predict browser behavior, you still need to reset before you do this. So the only difference between your method and mine is that I choose to “set” my baseline presentational styles outside of the reset process. This way, each project can have a different foundation without ever editing the reset.css file.
Keeping your steps modular really saves time and energy as you work on larger and multiple projects.