A look at CSS Resets in 2018

All browsers ship with a set of default styles that are applied to every web page in what is called the “user agent stylesheet”. Most of these stylesheets are open source so you can have a look through them:

A lot of styles are consistent across all user agent stylesheets. For example, I used to think that the <head> element was not visible due to some special feature, but it is actually hidden like any other element on a page, with display: none! You can see this same style in WebKit, Chromium, and Mozilla.

A lot of styles, however, are inconsistent between the user agent stylesheets. For example, see how a search input is styled across the browsers.

Search input across browsers

The case for CSS resets

In order to deal with the inconsistencies between user agent stylesheets, CSS resets were born. A CSS reset is a set of styles applied to a page before any other custom styles, with the purpose of creating a more standardised base between browsers.

Eric Meyer wrote an article on the reasoning behind CSS resets in 2007, which I think still holds true:

The basic reason is that all browsers have presentation defaults, but no browsers have the same defaults… We think of our CSS as modifying the default look of a document but with a “reset” style sheet, we can make that default look more consistent across browsers, and thus spend less time fighting with browser defaults.

Although things are different than they were in 2007, I think resets can still be useful.

Aren’t user agent stylesheets less inconsistent nowadays?

Yes, a lot of default styles between user agent stylesheets are now very similar. For example, most browsers apply the same 0.67em horizontal margin and 2em font size to the <h1> element. However, this consistency is relatively new and we still need to consider support for the older browsers that have less consistent default styling.

Additionally, depending on the type of reset we want to apply (as we will see below), we may still want a reset even if only the modern, more consistent, browsers were in use.

Don’t we apply our own styles to override reset anyway?

One of the major arguments against using CSS resets is that a lot of the styles are eventually overridden by our main stylesheet, which means that the reset styles unnecessarily add to page load time. Although this is definitely true, it isn’t a good enough argument for me to stop using them for two reasons.

The first is that I think resets allow us to write cleaner styles. We can separate my styles that are targeted to specific browsers and my styles for the actual design of the website. Instead of having browser-specific corrections in the same place as my design-specific styles, we can separate them.

Second, resets are (typically) very small and should have a negligible effect on load times. We frequently use the cascade to override and modify element styling, and although there may be some performance gains to never doing this, it may not be worth the time.

Types of CSS resets

There are many, many different CSS resets. Since the first in 2004, undohtml, there has been a plethora of resets ranging in complexity and specificity.

Broadly, there are three goals that a CSS reset tries to achieve. Some reset stylesheets combine these three goals, whereas others only try to solve one.

  1. Correct user agent styling errors
  2. Undo any "opinionated" user agent styling
  3. Create a consistent, largely opinionated, style base

Corrective resets

One goal of CSS resets is to correct errors in user agent stylesheets. As you would imagine, this is more for older browsers. A good example of this is when HTML5 was introduced and browsers such as Internet Explorer 9 didn’t apply the correct display type to the new elements.

In resets like normalize.css, these errors are specifically targeted and fixed:

/**
 * Add the correct display in IE.
 */

main {
  display: block;
}

Since these styles only apply to older browsers, we can also use a PostCSS processor such as PostCSS Normalize, along with browserlist. This allows us to conditionally add these types of styles only if we are supporting that particular browser.

Another example, which applies to some modern browsers, is correcting the display on elements with the hidden attribute.

[hidden] {
    display: none !important; // One of the good use cases of !important
}

Undoing opinionated user agent styling

Another goal of CSS resets was to undo any opinionated styles from user agents.

There are many opinions for what an opinionated style is. My definition of an opinionated style is anything that isn’t the, for lack of a better word, “bare” version. For example, I would consider adding a 2em margin on headings, as most user agent stylesheets do, an opinionated style because why 2em? Why not 3em? Or 4em? An “unopinionated” style in my opinion would just be a margin of 0 instead. Okay, back to the resets.

A simple version of this is the “Universal Reset”, which removes all margin and padding from all elements:

* {
    margin: 0;
    padding: 0;
}

This reset is probably too heavy-handed, as it removes padding from elements you may not expect, such as <input> elements. An alternative, more commonly used reset is Eric Meyer’s CSS Reset. It returns margin, padding, borders, and font size on specific elements to 0 or none. And, it doesn't include elements where you would expect a padding.

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, 
figure, figcaption, footer, header, hgroup, 
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
	margin: 0;
	padding: 0;
	border: 0;
	font-size: 100%;
	font: inherit;
	vertical-align: baseline;
}

Resets for consistent, opinionated, styles

Where the previous category of resets attempted to correct opinionated user agent styles by undoing them entirely, this category of resets does this by setting its own opinionated styles.

For example, instead of setting all font sizes to 1em or margins to 0, this type of reset will set an opinionated style.

/**
 * Correct the font size and margin on `h1` elements within `section` and
 * `article` contexts in Chrome, Firefox, and Safari.
 */

h1 {
  font-size: 2em;
  margin: 0.67em 0;
}

Bootstrap’s Reboot is another example of this. They take things a bit further, even declaring font families and background colours for the <body> element.

// Body
//
// 1. Remove the margin in all browsers.
// 2. As a best practice, apply a default `background-color`.
// 3. Set an explicit initial text-align value so that we can later use the
//    the `inherit` value on things like `<th>` elements.

body {
  margin: 0; // 1
  font-family: $font-family-base;
  font-size: $font-size-base;
  font-weight: $font-weight-base;
  line-height: $line-height-base;
  color: $body-color;
  text-align: left; // 3
  background-color: $body-bg; // 2
}

How are we using CSS resets today?

I recently ran a poll on Twitter asking people what CSS resets they currently use.

Most people use resets like Normalize.css, which is a combination of correcting browser errors and setting consistent, opinionated, styles. A good amount of people reported their own customised resets, which generally fell into the third category as well.

My opinion

I have always used a slightly-modified version of Eric Meyer’s CSS reset for two reasons.

The first is that I generally prefer to work with as blank a slate as possible, adding styles as I see fit. This is just a personal preference for the way I work.

The second is that I’m a strong believer in only applying margins in one direction (usually down) and most opinionated resets, like most user agent stylesheets, don’t follow this rule. Therefore, I would rather start with zero margin and padding anywhere, and add it as I go.

Nowadays, I’ve been tweaking my reset file a lot more, even adding utilities that I want in every project I work on, such as a .sr-only class. This has made me think that it isn’t really a reset anymore and is more of a “base”. With new resets coming out like Reboot, it seems like this is the general theme of where things are going.

 

I'm really interested to hear what everyone uses. Do leave a comment with what you think about resets today!

blog comments powered by Disqus