My CSS resets

Every now and then, I see someone post their latest and greatest set of CSS resets. Here’s mine:

@layer reset {
  *,
  *::before,
  *::after {
    box-sizing: border-box;
  }

  body {
    margin: unset;
  }

  button,
  input,
  textarea,
  select {
    font: inherit;
  }

  img,
  picture,
  svg,
  canvas {
    display: block;
    max-inline-size: 100%;
    block-size: auto;
  }

  @media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
      scroll-behavior: auto !important;
    }
  }
}

Some popular resets are a bit more opinionated than this, but this one strikes the right balance for me. My goal is that I can copy this whole thing into any project the moment I start it and be on good footing when I start building out the global styles.

I’ll break it down bit by bit:

Box sizing reset

*,
*::before,
*::after {
  box-sizing: border-box;
}

Make everything use the more predictable border box sizing.

My previous technique involved setting this to inherit and then applying border-box sizing once at the root. The benefit of that was to make it easier to revert a chunk of the page to content-box sizing if needed, specifically when bringing in a 3rd party widget.

However, I found I haven't had to do that in ages. Any plugins or 3rd party components I use these days are modern enough that they too use border box sizing.

In practicality, that was a small piece of complexity I never really need, so I’ve simplified to this current approach.

Remove body margin

body {
  margin: unset;
}

Does anybody ever want that 10px body margin? It’s a holdover from a lost age of the web, so I nuke it.

I like using unset rather than 0 here because it’s just a bit more clear what my intention is. I’m not setting a 0px margin, I’m removing a setting the browser has made.

Form input fonts

button,
input,
textarea,
select {
  font: inherit;
}

The default form fonts are weird, especially for buttons. I’m going to set a font and font size I like on the page. This makes sure my selection carries over to buttons and inputs.

I generally caution against the use of the font shorthand property, because it overrides so many different font-* properties all at once, but in this case, that’s exactly what I want. Inherit everything.

Gary Oldman shouting 'Everyone!'

I’ll almost certainly be adding more opinionated styles to these elements in my global styles layer, but this puts them in a reasonable state even before I get to that.

Images and similar media

img,
picture,
svg,
canvas {
  display: block;
  max-inline-size: 100%;
  block-size: auto;
}

I can’t recall the last time I used an <img> as an inline element. They’re almost always part of the page structure, so I make them block level. This ensures they don’t overflow horizontally out of their container and generally behave more predictably.

Harry Roberts has a rather interesting, highly opinionated take that goes a lot further than this. I like his ideas there, but in practicality, they’re just a bit too much for me. I figure I can layer in his tricks when I really need them, but honestly that doesn’t happen very often.

Reduced motion

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

Remove decorative motion for users who don’t want them. This is pretty standard stuff. The one thing of note here is that these don’t set transitions and animations to none, rather they shorten the durations a super short interval. This way, they’re impossible to perceive, but they still run; browser events like transitionend will fire as normal and any code depending on those events won’t break.

Interestingly, I’m toying with the idea of reworking this bit of code on this site. Some of my posts include tutorials and demos that describe building transitions, and the demos don’t work because I’ve got this sort of code in my stylesheet. At some point, I’ll rejigger what occurs on what layer, but that’s a special case for this particular blog, and not any other projects.

Loading interactions…

Recent Posts

See all posts