The New CSS Reset
CSS has acquired a number of new features in recent years, allowing us to reset the CSS more succinctly than before. What’s more, now in 2021 all
those CSS features have broad support in all the evergreen browsers. This
urged me to create a new CSS Reset, called “The new CSS Reset”.
Before we jump into how I created my new CSS reset, which is
simpler and more sophisticated than before, I’ll first address some frequently asked questions.
Why Do We Need A CSS Reset?
Every browser loads a style file called the User-Agent-Stylesheet, which defines default styles for HTML elements.
The problem is that different browsers might define different default styles. CSS resets were invented to solve this problem.
Normalize CSS Vs. CSS Reset Approach
When it comes to how to reset the styles, there are two main approaches:
- The Gentle approach — Normalize CSS.
- The Aggressive approach — CSS Reset.
Let’s take a quick look at these two approaches.
Normalize CSS (the gentle approach)
The Normalize CSS's main goal is to resolve browsers’ differences and create consistent basic styles across all of them.
The Normalize CSS works by searching for the most common definition for each element. It then defines the common styles for those browsers that style that element differently and thus override the styles in the User-Agent-Stylesheets that aren’t using in the common “correct” way.
The Normalize CSS project has excellent documentation, and I recommend you go over it and see what it fixes.
Part of a Normalize CSS file:
/**
* Correct the inability to style clickable types in iOS and Safari.
*/ button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
CSS Reset (the aggressive approach)
Unlike Normalize CSS, CSS Reset’s main idea is very different — it assumes that most of the browsers’ default styles do not fit our projects’ needs, and therefore its main goal is to remove most of them.
For example, if we take a look at the HTML section heading elements, <h1>
to <h6>
, we’ll realize that in most cases we don’t want the default styles coming from the User-Agent-Stylesheet, such as the specialfont-size
, margin
, and even the font-weight
. The styles that we do want to apply, we will define based on our project’s needs.
There are many types of CSS Resets, but Eric Meyer’s CSS Reset is the most well-known one.
A portion of Eric Meyer CSS Reset:
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain) */ 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;
}
Which is Better to Use?
This section is, of course, my personal opinion. But you will be surprised by my answer.
First, I think that the Normalize CSS is a must-have in any project.
Why is Normalize CSS a must-have?
Normalize CSS addresses issues that the CSS Reset doesn’t address, such as shadow DOM elements.
Shadow DOM elements are inner scoped elements that exist inside certain HTML elements. One example is the inner buttons on some input elements, such as <input type=”search”>
, <input type=”file”>
, <input type=”number”>
, and others.
An example from Normalize CSS:
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/ [type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
But what about CSS Reset ?!
I also like the idea of CSS resets, which remove most of the default styles that we will want to define differently in most cases.
However, there is a major caveat: Eric Meyer’s CSS Reset is built as a long CSS selector list. The problem with this big chain of selectors is that it’s unreadable when debugging CSS code.
Since the Reset CSS and the Normalize CSS focus on different concerns, and due to the caveat in the common CSS Resets, I’ve worked with both Normalize CSS and a custom CSS Reset that I developed over time.
The Normalize CSS addresses Shadow DOM elements' differences, and the custom CSS Reset removes unneeded browsers' default styles.
@import "resets/normalize.scss";
@import "resets/reset.local.scss";
The custom CSS Reset only resets those elements that require reset, such as lists, headings, and other elements.
This is My Old Custom CSS Reset:
/****** Elad Shechter's RESET *******//* box sizing border-box for all elements */*,
*::before,
*::after { box-sizing:border-box; }a { text-decoration:none; color:inherit; cursor:pointer; }
button { background-color:transparent; color:inherit; border-width:0; padding:0; cursor:pointer; }
figure{ margin:0; }
ul, ol, dd { margin:0; padding:0; list-style:none; }
h1, h2, h3, h4, h5, h6 { margin:0; font-size:inherit; font-weight:inherit; }
p { margin:0; }
cite { font-style:normal; }
fieldset { border-width:0; padding:0; margin:0; }
The New Way to Reset CSS in 2021
New reset keywords have been added to CSS in recent years: initial
, inherit
, unset
, revert
. Besides these, CSS now also provides the special all
property, which allows us to reset all of the properties at once.
Before we get into those features and how we can utilize them to make a new CSS reset, let’s go over a few basics in CSS.
Two Types of Properties
There are two groups of properties in CSS:
- The Inherited properties group - consists of properties that inherit
definitions from parent elements by default; they are mostly typographic properties (font-size
,color
, etc.). - The Non-inherited properties group - consists of the rest of the properties, and they aren’t affected by parent elements’ definitions.
MDN has information on what the default type of every property is:
Every Property Has an Initial Value
Another basic of CSS I want to talk about is CSS properties’ initial
values.
Before we define any style in CSS, and even before the browser loads its styles (“User-agent-stylesheet”), every property has an initial
value (default value).
This is important to know since in most cases we will want to reset the property's value to its initial
one.
An example of the max-width
property’s initial value:
Now that we’ve gone over initial
values and how styles affect each of the types of properties that we discussed before, let’s look into the process through which I arrived at my new CSS Reset.
The Basics of Resetting in CSS
Our first challenge is that we have two groups of properties, and they have to be reset differently.
Non-inherited properties
When we reset non-inherited properties, we want to get the property's initial value. We’ll use the initial
keyword value to do this.
Examples:
max-width: initial; /* = none */
width: initial; /* auto */
position: initial; /* = static */
Inherited properties
When we reset inherited properties, such as font-size
, we want to keep the default inherited behavior. We’ll use the inherit
keyword value to do this.
Examples:
/* will get parent element value */font-size: inherit;
line-height: inherit;
color: inherit;
Auto Reset
To reset these two categories of properties, inherited and non-inherited, we will use another special reset keyword: the unset
keyword.
Using the unset
value on any property will apply its proper reset keyword. For example, font-size: unset;
will be equal to inherit
, and position: unset;
it will be equal to initial
.
Examples:
max-width: unset; /* = initial = none */font-size: unset; /* = inherit = get parent element's value */
Reset All Properties Together
CSS has many properties, and we want to make sure that they’re all reset without having to go through them one by one.
Therefore, we will use the exceptional all
property. This property enables us to reset all properties at once!
Now, we can effortlessly reset all properties with their respective types.
Example:
/*
Reset all:
- Inherited properties to inherit value
- Non-inherited properties to initial value
*/* {
all: unset;
}
CSS’s Default Values Aren’t Always Desirable!
However, in some circumstances, restoring CSS to its default values is
insufficient. For example, if we reset a <div>
‘s display
property to unset
, the initial
value that we get will be inline
rather than block
. Examples:
div {
display: unset; /* = inline */
}span {
display: unset; /* = inline */
}table {
display: unset; /* = inline */
}/* The inline value will be applied to every HTML element */
The reason for this is that the initial
value doesn’t use the default styles from the browser’s User-agent-stylesheet.
Reverting to the Browser’s Default User-Agent-Stylesheet
The default styles in our browser are derived from two sources:
CSS properties' basic behavior — the initial values and the inherited styles on some of the properties, as we already discussed.
User-agent-stylesheet — the default CSS file that the browser loads to create special styles for specific HTML elements.
This is why you’ll see the display: block;
definition when you run Inspect Element on a <div>
HTML element, but nothing when you run it on a <span>
HTML element.
The browser shows you only those styles that differ from the basic CSS behavior.
How to reset to the User-agent-stylesheet values
To reset to the default values in the User-agent-stylesheet, we have the last special CSS reset keyword: the revert
keyword.
The revert
keyword first determines whether the browser’s User-agent-stylesheet contains special styles for the HTML element in question. If so, it will reset to those default styles.
Examples:
div {
display: revert; /* = block */
}
span {
display: revert; /* = inline */
}
table {
display: revert; /* = table */
}
If there are no styles defined for that element in the User-agent-stylesheet, the revert
keyword will behave like the unset
value. If the property is from the inherited group, it will be reset to the inherit
value; otherwise, it will be reset to the initial
value.
The CSS Reset Keywords Diagram (inherit
, initial
, unset
, and revert
):
Creating “The New CSS Reset”
Now that CSS has all these new reset features, creating a CSS Reset is much simpler than up till now.
In most cases, we want to reset the majority of properties to their default initial values or their inherent behavior of CSS, using the unset
value. But as we saw above, we also want to keep the display
property declarations from the User-agent-stylesheet.
Basic Idea
With all of this knowledge, I began working on my new CSS reset:
/*
Reset all the "User-Agent-Stylesheet" styles,
except for the 'display' property
*/* {
all: unset;
display: revert;
}
Not Everything is Perfect
Having said that, there are a few more details to take care of.
When the height
and width
properties on some special HTML elements such as <img>
, <video>
, <svg>
, <canvas>
and <iframe>
—are reset with all: unset;
the effect of the height
and width
attributes on those elements is reset. As a result, those size attributes will no longer have any effect, due to the CSS reset.
To solve this problem, I used some CSS pseudo-classes.
The :not() pseudo-class
I added the :not()
pseudo-class, which nowadays accepts multiple arguments.
In the arguments, I added all the “content HTML elements” to which width
and height
attributes can be applied. In this way, I’m not affecting those elements.
/* works on every element except for content elements */*:not(iframe, canvas, img, svg, video):not(svg *) {
all: unset;
display: revert;
}
But using the :not()
pseudo-class has an unintended consequence: it creates a stronger CSS specificity and thus might override styles define later in your project. For example:
/* these styles don't affect the element when I use CSS reset with the :not() pseudo-class with multiple arguments */div {
color: red;
}
This style won't work because the arguments list in the :not()
pseudo-class has a stronger specificity than a selector of one HTML element.
To solve this issue, I used the :where()
pseudo-class:
The :where() pseudo-class
I solved this by wrapping the whole :not()
pseudo-class with the :where()
pseudo-class, which is a special selector that removes the specificity inside this selector.
*:where(:not(iframe, canvas, img, svg, video):not(svg *)) {
all: unset;
display: revert;
}
More Special Resets
With our 2021 perspective, we can see that some CSS features have been implemented incorrectly. When I built this new CSS reset, I aimed to solve those common problems.
The Box-sizing property
These days, the most common way to use the box-sizing
property is with the border-box
value, which includes the padding
and the border
in the sizing calculation:
/* Preferred box-sizing value */*,
*::before,
*::after {
box-sizing: border-box;
}
Images overflow
The default size of an <img>
HTML element is its real size. If you place it in a smaller container than the default size of the specific image, the image will overflow from the container. To solve this, I added this style to the CSS reset:
/* For images to not be able to exceed their container */
img {
max-width: 100%;
}
In my new CSS reset project, you’ll discover even more small improvements like this.
Form Elements
In the past, form elements, such as <input type=”checkbox”>
, <input type=”radio”>
, <select>
and others, were difficult to reset. Over the years, I’ve seen many web developers utilize CSS hacks on the <label>
element to style those elements.
With the new CSS reset features, we now can reset even those stubborn elements, and create custom styles for these <form>
elements.
An example of designing radio buttons and checkboxes (using Sass):
input[type="checkbox"],
input[type="radio"] { /* base styles here */ &:checked {}
&:disabled {}
&:focus {}
}input[type="radio"] { border-radius:50%; }
Live CodePen demo of designed form elements:
Or you can create well-designed checkboxes:
However, if you don’t want to reset those form elements, it is easy to restore the default styles with the revert
value and the all
property.
Example:
input,
textarea,
select {
all: revert;
}
To Summarize
In this article, we looked at why CSS resets are useful, what sorts of CSS Resets already exist, and how to combine their resets.
In addition, we saw the CSS reset keywords and met the global reset property, all
, which has expanded the possibilities of CSS resetting.
With all of these possibilities, you can construct a custom CSS reset and design form components that provide a more consistent experience across all browsers.
To try “The new CSS reset”, you can find it on the GitHub page and as an NPM package.
If you find any bugs, please feel free to contact me via the GitHub project.
Browser Support
To create: “the new CSS reset” project, I have used CSS features that while they are cutting-edge, are already implemented in all evergreen browsers:
- Chrome, Edge: version 88+
- Firefox: version 84+
- Safari/iOS: version 14+
- Opera: version 75+
- Samsung Browser: version 15+