My Custom CSS Reset by Josh W. Comeau was translated from My Custom CSS Reset by Josh W. Comeau and translated by KooFE Front-end Team
Whenever I start a new project, one of my first tasks is to deal with the edges of the CSS language. To address these issues, a custom set of base styles is often used.
For a long time, I used the famous CSS Reset from Eric Meyer. As an old and useful piece of CSS code, it hasn’t been updated in over a decade, and a lot has changed in that time!
Recently, I started using my own CSS resets. It contains a number of tips I’ve compiled to improve both the user experience and the CSS development experience. In this article, we’ll cover this custom CSS resetting style. And delve into each of these rules, in addition to discussing the role of each rule, will also be a simple explanation of why the use of the rule!
background
Historically, CSS restyles have mostly been used to clear the browser’s default styles to ensure consistency across browsers. My CSS restyling is not intended to solve this problem.
Today, there is little difference in layout or spacing between browsers. By and large, modern browsers, as one might expect, have faithfully implemented the CSS specification. As a result, dealing with style consistency issues is not that important.
Also, I never thought it was necessary to remove all of the browser’s default styles. For example, I use the <em> tag to set the font style to italic! While it’s possible to follow different design specifications in different projects, I don’t think it makes sense to remove common-sense defaults.
My CSS resets may not fit the classic definition of “CSS resets,” but in another way, they are more creative.
My CSS Reset
Without further ado, go directly to the code:
/* 1. Use a more-intuitive box-sizing model. */
*, *::before, *::after {
box-sizing: border-box;
}
/* 2. Remove default margin */
* {
margin: 0;
}
/* 3. Allow percentage-based heights in the application */
html.body {
height: 100%;
}
/* Typographic tweaks! 4. Add accessible line-height 5. Improve text rendering */
body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
/* 6. Improve media defaults */
img, picture, video.canvas, svg {
display: block;
max-width: 100%;
}
/* 7. Remove built-in form typography styles */
input.button.textarea, select {
font: inherit;
}
/* 8. Avoid text overflows */
p.h1.h2.h3.h4.h5.h6 {
overflow-wrap: break-word;
}
/* 9. Create a root stacking context */
#root.#__next {
isolation: isolate;
}
Copy the code
Although the code is short, there is a lot of dry work in this small stylesheet. Let’s get started!
1. Box-sizing
Before we begin, answer one question! In the absence of other CSS styles, what is the width of the.box element (the rectangular area with the pink border) in the following code? Is it 200px, 240px, 244px or 0px?
<style>
.parent {
width: 200px;
}
.box {
width: 100%;
border: 2px solid hotpink;
padding: 20px;
}
</style>
<div class="parent">
<div class="box"></div>
</div>
Copy the code
Set width: 100% in the.box element style. Since its parent element is 200px wide, 100% will be interpreted as 200px.
So what does this 200px width do? By default, browsers apply this width to the content box. As we all know, the “content box” is the actual contents of the box in the box model, inside the border and padding:
Set the content part of the.box model to 200px; The padding adds an additional 40px width (20px on each side); The border border will be increased by 4px (2px on each side). By adding, the width of the pink rectangle is 244px. Therefore, the answer to the above question is 244px.
Overflow occurs when we try to fit a 244px box into a 200px wide parent container:
This behavior seems strange, and we can change it with the following Settings:
*, *::before, *::after {
box-sizing: border-box;
}
Copy the code
When this rule is applied, the percentage of the width is resolved based on the border-box. In the example above, our pink box is 200px, and the inner Content-box will shrink to 156px (200px-40px-4px).
In my opinion, this is an essential style rule because it makes CSS easier to use. We use the wildcard selector (*) to apply it to all elements and pseudo-elements. Contrary to popular belief, this style setting does not lead to performance degradation. See article * {box-sizing: border-box} FTW for details.
Inheriting box-sizing
I saw another style set online:
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
Copy the code
This can be a useful strategy if you want to migrate using border-box in an existing large project. This is not necessary if you are starting a brand new project from scratch. For simplicity, I’ve omitted it from the CSS Reset style.
First, we can create a “Legacy” selector that keeps the value of box-sizing as content-box, which is the default for the box-sizing property:
.legacy {
box-sizing: content-box;
}
Copy the code
Then, when there is a border-box in the application that has not been migrated, we can add the class to the corresponding location to keep the original style intact:
<body>
<header class="legacy">
<nav>
<! -- Legacy stuff here -->
</nav>
</header>
<main>
<section>
<! -- Modern stuff here -->
</section>
<aside class="legacy">
<! -- Legacy stuff here -->
</aside>
</main>
</body>
Copy the code
Why do you do that? Now, let’s think about how the elements in this code snippet are evaluated.
-
is given legacy, so it uses box-sizing: content-box.
-
The
-
The
tag has no legacy, so it inherits from its parent ; While inherits from < HTML >; < HTML > is already set to border-box.
Essentially, each element gets a box-sizing attribute from its parent. If it has an ancestor set to Legacy, its property value is Content-Box. Otherwise, it will end up inheriting from the < HTML > tag with an attribute value of border-box.
2. Remove the margin default
* {
margin: 0;
}
Copy the code
Browsers make a lot of common sense assumptions about margins. For example, h1 is larger than paragraph margins by default. These assumptions are reasonable for documents that do word processing, but may not be accurate for modern Web applications.
In addition, the margin will be in your slightly careless time to encounter the problem of the margin collapse, it is really a nasty little clever. Also, I often find myself wanting elements to have no margins by default. So I decided to get rid of it all. 🔥
When I do want to add margins to a particular tag, I can do so in a custom style in my project. Wildcard selectors (*) have extremely low precedence, and this rule is easily overridden.
3. Height based on percentage
html.body {
height: 100%;
}
Copy the code
We often use percentages to set heights in CSS, only to find that it doesn’t seem to work. Take a look at the following example:
Although I set the main element to height: 100%, the height of the element doesn’t change at all!
The reason this doesn’t work is that in CSS streaming layouts (the main layout mode in CSS), height and width work completely differently. The width of an element is calculated based on the parent element, and the height of an element is calculated based on its children. This is a complicated topic that is well beyond the scope of this article and won’t be discussed in this article.
In the following code example, we apply the above rule to our code and see that the height of the main element is 100% :
If you’re using a JavaScript framework like React, you might also want to add a third selector to this rule: the root element used by the framework.
For example, in my Next. Js project, the rules are updated as follows:
html.body.#__next {
height: 100%;
}
Copy the code
Why not use VH?
You may be wondering: why do you have to use percentages to set heights? Why not use VH instead?
The problem is that VH doesn’t work properly on mobile devices; On mobile devices, the visible portion of the viewport adjusts when the browser UI slides up and down, which results in 100Vh being unfixed in the browser and may exceed the actual screen usage.
In the future, new CSS units will solve this problem. Until then, I continue to use a percentage based height.
4. Change the line – height
body {
line-height: 1.5;
}
Copy the code
Controls the vertical spacing between lines of text in a paragraph. Its default value varies from browser to browser, but is usually around 1.2. The unitless number is based on the ratio of font sizes. It functions just like EM. When line-height is 1.2, the line height of each line is 20% larger than the font of the element.
Here’s a problem. For those with dyslexia, the sentences are too close together, making reading more difficult. The WCAG standard states that the row height should be at least 1.5.
Now, the number 1.5 affects headings (such as tags h1, H2, etc.) and other large type elements, causing them to have considerable line spacing:
You might intuitively want to reset the row height on the title. As I understand it, the WCAG standard is for “body” text, and only 1.5 line heights are set for body.
Use calc to flexibly set line-heights
I’ve been trying another way to set the line height, as follows:
* {
line-height: calc(1em + 0.5 rem);
}
Copy the code
This is a fairly advanced code snippet, and although it is beyond the scope of this article, it will be covered briefly here.
Instead of multiplying the font size by a number like 1.5, this method uses the font size as the base and adds a fixed amount of space to each line. For the body paragraphs, each line will be parsed to 24px (assuming the browser’s default font size is used).
However, on larger text, this declaration produces tighter lines. This can be verified by the following example:
This should be used with caution, and I’m still experimenting with it.
One drawback is that we have to set it with * on all elements instead of applying it to the body. This is because EM units do not inherit well from quilt elements; It does not recalculate > 1em for each element. For example, on this blog, my code is broken by third-party code that assumes line heights are inheritable.
For more information on this technique, check out Kitty Giraudel’s great post on Calculating optimal row Heights using CALC.
5. Set the font smoothing
body {
-webkit-font-smoothing: antialiased;
}
Copy the code
This CSS setting is a bit controversial.
On MacOS computers, browsers use “subpixel antialiasing” by default. This technique uses R/G/B lighting within each pixel to make text easier to read.
In the past, this technique has been credited with improving accessibility because it improves text contrast. You may have read a popular blog post about stopping “fixing” font smoothing, which doesn’t advocate switching to “antialiased.”
The problem is, this article was written in 2012, before the era of high-DPI “Retina” displays. Today’s pixels are even smaller and invisible to the naked eye. The physical layout of LED pixels has also changed. If you look at a modern display under a microscope, you no longer see the ordered grid of R/G/B lines.
In the 2018 release of MacOS Mojave, Apple disabled subpixel anti-aliasing in the operating system. I guess they realize that for modern hardware, this technology does more harm than good.
Confusingly, MacOS browsers like Chrome and Safari still use subpixel anti-aliasing by default. So, you need to explicitly turn off subpixel anti-aliasing by setting -webkit-Font-Smoothing to Antialiased.
The difference between the two is:
MacOS is the only operating system that uses subpixel anti-aliasing, so this CSS rule has no effect on Windows, Linux, or mobile devices. If you are using a MacOS computer, try running the following code example:
6. Change the default values of media elements
img, picture, video.canvas, svg {
display: block;
max-width: 100%;
}
Copy the code
Images are considered “inline” in CSS, which means they should be used in the middle of a paragraph like or . This is at odds with the way we often use images. In general, we use images the same way we treat paragraphs, headings, or sidebars, which are layout elements.
However, if we try to use inline elements in a layout, we run into strange things. Take the 4px space problem with inline elements. The magic space is related to line-height. We get around this problem by setting display:block on all images.
I also set max-width to 100% to prevent large images from spilling out, especially if they are placed in a container that is not wide enough.
Most block-level elements will automatically elongate/contract to fit their parent, but media elements like are special: they’re called replacement elements, and they don’t follow the same rules either.
If the image’s “own” size is 800 × 600, the width of the element will also be 800px, even if we put it into a parent element 500px wide.
This rule will prevent images from growing out of their container, which I think is a sensible approach.
7. Font inheritance for form controls
input.button.textarea, select {
font: inherit;
}
Copy the code
By default, buttons and input fields do not inherit typesetting styles from their parent. Instead, they have their own weird style. For example,
As you can imagine, reading 13px text on a mobile device is very difficult. When we focus on an input field with a smaller font, the browser automatically zooms in, making the text easier to read.
Unfortunately, this is not a good user experience:
To avoid this automatic scaling, the font size must be at least 1rem/16px. There is one way to solve this problem:
input.button.textarea, select {
font-size: 1rem;
}
Copy the code
This fixes the auto scaling problem, but it’s only a stopgap. Let’s solve this problem at its root: form input should not have its own typography!
input.button.textarea, select {
font: inherit;
}
Copy the code
Font is a shorthand for CSS font Settings. It sets a series of font related properties, such as font-size, font-weight, and font-family. By setting its value to inherit, you can align these elements with the typesetting in the surrounding environment.
As long as we didn’t use the obnoxious smaller font in the body, this solved all our problems at once. 🎉
8. Set word wrap
p.h1.h2.h3.h4.h5.h6 {
overflow-wrap: break-word;
}
Copy the code
In CSS, text is wrapped if there is not enough space to hold all the characters in a line.
By default, the algorithm looks for “soft newline” opportunities; These are algorithms that can split characters. In English, the only opportunities for soft line feeds are Spaces and hyphens, but this varies from language to language.
If a line does not have any soft newlines and does not fit, text overflow will result:
This can lead to some annoying layout problems. Here, it adds a horizontal scroll bar. In other cases, it can cause text to overlap with other elements, or slide behind the image/video.
The overflow-wrap property allows us to tweak the line wrap algorithm and allow it to use hard line breaks if soft line breaks are not found:
While hot, neither of these solutions is perfect, at least hard line breaks won’t break the layout!
Thanks to Sophie Alpert for coming up with a similar rule! She suggests applying it to all elements, which is probably a good idea, but not something I’ve personally tested.
You can also try adding the 登 录 property:
p {
overflow-wrap: break-word;
hyphens: auto;
}
Copy the code
登 记 : aut: Automatic use of a hyphen (in languages that support them) to indicate hard linefeed. This also makes hard line breaks more common. If you have a very narrow text column, use it. In my personal CSS reset styles and for including it, but it’s worth trying!
Root stack context
#root.#__next {
isolation: isolate;
}
Copy the code
The last one is optional. It is usually only needed when using JavaScript frameworks like React.
As we saw in Fuck off, Z-Index, the Isolation property allows us to create a new stack context without setting z-Index.
This is beneficial because it allows us to ensure that certain high-priority elements (modes, drop-down lists, tooltips) are always displayed above other elements in the application. No weird stacking background errors, no endless Z-indexes.
To match the framework you use, you need to adjust the selector to your needs. We want to choose the top-level elements to render in the application. For example,
The final usable code
Here is my CSS reset in a compact, replicable, and elegant format:
/* Josh's Custom CSS Reset https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; {} *margin: 0;
}
html.body {
height: 100%;
}
body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
img, picture, video.canvas, svg {
display: block;
max-width: 100%;
}
input.button.textarea, select {
font: inherit;
}
p.h1.h2.h3.h4.h5.h6 {
overflow-wrap: break-word;
}
#root.#__next {
isolation: isolate;
}
Copy the code
Feel free to copy/paste into your own project! It can be published without any restrictions (though if you want to keep a link to this blog post, I’d appreciate it!). .
I didn’t release this CSS reset as an NPM package because I think you should have your own. Bring it into your projects and adjust it over time as you learn new things or discover new techniques. If necessary, you can always make your own NPM packages for reuse in your projects. Remember: code lasts forever. You have this code, and it should grow with you.
Thanks to Andy Bell for sharing his modern CSS style reset. It sparked some inspiration for me and inspired this blog post!
Learn more about CSS
My CSS reset style is very short (only 11 times declared!) But I spent an entire blog post talking about them anyway. To be honest, I have a lot more to say! We only briefly mentioned some knowledge points, not in depth.
CSS looks complex, but it isn’t. Language can always feel a bit unpredictable and inconsistent unless you break out of the casserole and ask what’s really going on inside. When your mental model is incomplete, you are bound to encounter some problems.
However, if you take the time to learn how the language actually works, everything becomes much more intuitive and predictable. In those sunny days, I like to write CSS freely!
Search ikoofe on wechat, and the public account “KooFE Front-end team” releases front-end technology articles from time to time.