An Interview With Elad Shechter on “The New CSS Reset”

Hey folks! Elad reached out to me to show me his new CSS reset project called the-new-css-reset. It’s quite interesting! I thought a neat way to share it with you is not only to point you toward it, but to ask Elad some questions about it for your reading pleasure.

Here’s the entire code for the reset up front:
/*** The new CSS Reset – version 1.2.0 (last updated 23.7.2021) ***/

/* Remove all the styles of the “User-Agent-Stylesheet”, except for the ‘display’ property */
*:where(:not(iframe, canvas, img, svg, video):not(svg *)) {
all: unset;
display: revert;
}

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

/*
Remove list styles (bullets/numbers)
in case you use it with normalize.css
*/
ol, ul {
list-style: none;
}

/* For images to not be able to exceed their container */
img {
max-width: 100%;
}

/* Removes spacing between cells in tables */
table {
border-collapse: collapse;
}

/* Revert the ‘white-space’ property for textarea elements on Safari */
textarea {
white-space: revert;
}
Hey Elad! I want to get to the code bits really quick here, but first, I’d love to hear the why about this project. CSS resets have been popular for ages because they wipe out the differences that exist between different browsers default styles and then you build up your styles from there. There are some widely-used resets out there already — why a new one?
First, when talking about “CSS resets” we have two approaches:
Nicolas Gallagher’s Normalize.css is the gentle approach. Normalize.css is fixing differences between the implementation in different browsers.Eric Meyer’s CSS Reset is the hard approach, saying that in most cases we don’t want basic styles from the browsers, like the font-size value we get from elements like

through

, or the default styles for the

    and

      list elements. For example, we use the list only for the semantic meaning, and because it helps in other ways for accessibility and SEO.I love Normalize.css. I think it’s a must-have in any project, even if you prefer the CSS Reset idea.
      And why is Normalize.css so important? Normalize.css touches shadow DOM elements that the CSS Reset doesn’t. When looking at Normalize.css, you will find special pseudo-classes like ::-moz-focus-inner, ::-webkit-file-upload-button, and more. It covers so many bases and that’s why I believe Normalize.css is a must-have in any project.
      I love the hard CSS Reset as well. I think in most cases we don’t want the basic styles of the browser, and if we need it in a specific place, we will define it according to our need. This brings me to the point that I’m using both Normalize.css and CSS Reset combined. So, Normalize.css is first to load, followed by the hard CSS Reset.
      So, why we need a new CSS reset? The CSS resets we have are built on old CSS features. But in the last several years, we’ve gotten new features built specifically for resetting things in CSS, and this got me thinking that now we can create a much more valid CSS reset using these new cutting-edge CSS features.
      It seems to me the juiciest bit here is that very first ruleset. Let’s start with that first CSS property and value: all: unset;. That’s what is doing the heavy lifting in this CSS reset yes? How does that work?
      all is the most exceptional CSS property because it allows us to reset all the properties that exist in the CSS all at once.
      The property accepts several keywords. The two basics are initial and inherit; there are two smarter ones, which are unset and revert. To understand what all: unset does, we need to jump to the fundamental behavior of our CSS properties.
      In CSS, we have two groups of properties:
      Inherited properties group: These are properties that have inheritance by default — mainly typography properties.Non-inherited properties group: These are all other properties that don’t inherit by default, for example, the Box Model properties that include padding, border, and margin.Like typography properties, we want to keep the inherit behavior when we try to reset them. So, that’s where we’re able to use the inherit keyword value.
      /* Will get values from the parent element value */
      font-size: inherit;
      line-height: inherit;
      color: inherit;
      For the other properties in the non-inherited properties group, we want to get their initial value in most cases. It is worth mentioning that the initial keyword computes differently for different properties.
      max-width: initial; /* = none */
      width: initial; /* auto */
      position: initial; /* = static */
      After we understand the fundamentals as well as the inherit and initial keyword values, we understand that if we want to reset all of properties together, we can’t use them directly with the all property. That’s because, if we reset all of the properties to the initial value, i.e. all: initial, we lose the inherent behavior on the inherited properties group. And suppose we reset all properties with the inherit value. In that case, all the properties get an inheritance — even Box Model properties, which we want to avoid.
      That’s why we have the unset value. unset resets the property according to its type. If we use it on an inherited property, it’s equal to inherit; if we use it on a natural non-inherited, it equals initial.
      max-width: unset; /* = initial = none */
      font-size: unset; /* = inherit = get parent element value */
      This brings us back to the main feature of my CSS reset. What all: unset does is reset all the inherited properties to the inherit value, and all the other properties in the non-inherited properties group to their initial value.
      This operation removes all the default user-agent-stylesheet styles that the browser is adding. To understand these substantial new CSS powers, all of this happened while I was doing only one operation to all HTML elements.
      /*
      Reset all:
      – Inherited properties to inherit value
      – Non-inherited properties to initial value
      */
      * {
      all: unset;
      }
      And then you follow it up with display: revert; — does all: unset; do things to the display property that would be undesirable?
      Short answer: yes. The display property represents the basic structure which we do want to get from our user-agent stylesheet. As we saw in most of our properties, the unset value is doing an excellent job for us, and we reset all properties in one operation.
      Now, to understand what the unique revert keyword value is doing for the display property, let’s talk about the two types of styles that we are getting from our browsers. The styles we are getting from our browsers are built from two layers:
      Layer 1, the CSS initial value: As we already saw, the first layer is the initial values of all our properties in CSS, including the inherit behavior on some of the properties.Layer 2, the user-agent stylesheet: These are the styles that the browser defines for specific HTML elements.In most cases, when we want to reset things, we want to remove the basics styles of Layer 2. And when we do reset with all: unset, we remove all the styles of the user-agent stylesheet.
      But the display property is exceptional. As we already saw, every property in CSS has only one initial value. This means that if we reset the display property to its initial, like on a

      element or any other HTML element, it always returns the inline value.
      Continuing with this logic, we connect the

      element to the default display: block declaration, which we get from browsers. But we only get this behavior because of Layer 2, the user-agent stylesheet, which defines them. It’s built on the same idea that the font-size is bigger on heading elements,

      to

      , than any other HTML elements.
      div {
      display: unset; /* = inline */
      }
      span {
      display: unset; /* = inline */
      }
      table {
      display: unset; /* = inline */
      }
      /* or any other HTML element will get inline value */
      This is, of course, unwanted behavior. The display property is the only exception we want to get from our browser. Because of that, I’m using the unique keyword value revert to bring back the default display value from the user-agent stylesheet..
      The revert value is unique. First, it checks if there is a default style for the specific property in the user-agent stylesheet for the specific HTML element it is sitting on, and if it finds it, it takes it. If it doesn’t find it, revert works like the unset value, which means that if the property is an inherited property by default, it uses the inherit value; if not, it uses the initial value.
      A diagram of all the CSS reset keywordsThen those two rules are within a ruleset with a selector where you select almost everything. It looks like you’re selecting everything on the page via the universal tag selector (*), but then removing a handful of things. Is that right? Why target those specific things?
      When I started to imagine “The New CSS Reset” I didn’t think I would need exceptions. It was a lot more straightforward in my imagination.
      But when I started to create experiences, I was replacing my old CSS reset with my new CSS reset (without all the exceptions), and I saw some things that broke my old projects, which I tested.
      The main things that broke were elements that can get sizes via width and height attributes — elements like