Modern CSS Style Reset Best Practices!

Table of contents

1. Box-sizing model

2. Remove the default margin

3. Percentage based height

4. Adjust row height

5. Smooth Fonts

6. Media Defaults

7. Inherit the font of the form control

8. Word wrap

9. Root cascading context


When starting a new front-end project, the first task is to reset some default styles in CSS. Let's take a look at how to do a style reset in modern CSS. This article takes a deep dive into each rule to understand what it does and why to use it!

Here is the custom CSS reset code:

/*
  1. 使用更直观的 box-sizing 模型
*/
*, *::before, *::after {
  box-sizing: border-box;
}
/*
  2. 移除默认 margin
*/
* {
  margin: 0;
}
/*
  3. 在应用中允许基于百分比的高度
*/
html, body {
  height: 100%;
}
/*
  排版调整
  4. 添加无障碍行高
  5. 改进文本渲染
*/
body {
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
/*
  6. 改进媒体默认设置
*/
img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
}
/*
  7. 删除内置表单排版样式
*/
input, button, textarea, select {
  font: inherit;
}
/*
  8. 避免文字溢出
*/
p, h1, h2, h3, h4, h5, h6 {
  overflow-wrap: break-word;
}
/*
  9. 创建根层叠上下文
*/
#root, #__next {
  isolation: isolate;
}

There's not a lot of code here, but there's a lot going on in this little stylesheet. The following will introduce one by one!

Historically, the main goal of CSS resets has been to ensure consistency across browsers and to undo all default styles. This CSS reset code doesn't really do any of these things.

These days, browsers don't have much of a difference in layout or spacing. In general, browsers implement the CSS specification exactly, and everything works as you'd expect, so it's no longer necessary.

The CSS reset here may not fit the classic definition of "CSS reset", but it's more creative!

1. Box-sizing model

.box Let's look at a piece of code first. Assuming no other CSS is applied, how wide is the element in the following scenario  ?

<style>
  .parent {
    width: 200px;
  }
  .box {
    width: 100%;
    border: 2px solid hotpink;
    padding: 20px;
  }
</style>

<div class="parent">
  <div class="box"></div>
</div>

Here  .box the width of the element is: 100%. Since its parent has a width of 200px, 100% will resolve to 200px. But where does it apply the 200px width? By default, it applies that size to the content area, which is the white area in the image below:

width: 100% The declaration will  .box set the content box to 200px. Instead,  padding an additional 40 px will be added (20 px on each side). The border will add an extra 4px (2px on each side). When doing calculations, the width of the pink rectangle will be 244 px.

The overflow occurs when trying to fit a 244px box into a parent with a width of 200px:

We can change this strange behavior by setting the following rules:

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

After applying this rule, percentages will be parsed according to the border-box. In the example above, the pink box has a width of 200 px, and the width of the inner content box will shrink to 156 px (200 px - 40 px - 4 px).

This is a must-have rule that makes CSS work better. Here the wildcard selector (*) is used to apply it to all elements and pseudo-elements. Contrary to popular belief, this isn't bad for performance.

Some people on the web suggest doing the following instead:

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

This might be a useful strategy if i'm trying to migrate a large pre-existing project to use border-box. This is not necessary if starting a brand new project from scratch. It was omitted from the CSS reset above for simplicity.

So when is this useful? Let's look at an example that might be useful. This can be a useful strategy if you are trying to migrate a large pre-existing project to use border-box. If you're starting a whole new project from scratch, it's not necessary. For simplicity, I've omitted it from the CSS reset.

Expand to see examples of when it might be useful. First,   set the property  legacy of  , which is   the default value of the property:box-sizingcontent-boxbox-sizing

.legacy {
  box-sizing: content-box;
}

Then, when a part of the application has not been migrated to use border-box, the class can be placed like this:

<body>
  <header class="legacy">
    <nav>
      <!-- 遗留的内容在这里 -->
    </nav>
  </header>
  <main>
    <section>
      <!-- 现代的内容在这里 -->
    </section>
    <aside class="legacy">
      <!-- 遗留的内容在这里 -->
    </aside>
  </main>
</body>

Here, class <header> is given  legacy , so it uses  box-sizing: content-box. Its child elements  <nav> have  box-sizing: inherit. Since its parent is set to  content-box, nav will be set to as well  content-box.

<main> A label has no  legacy class, so it inherits from its parent  <body>. <body> Inherited from  <html>. <html> is set to  border-box.

Essentially, each element will now find its box-sizing behavior from its parent. If it has an  legacy ancestor of the settings class, it will be  content-box. Otherwise, you end up inheriting the html tag, ie using  border-box.

2. Remove the default margin

* {
  margin: 0;
}

Typically, browsers make common-sense assumptions around margins. For example, h1 will contain more margin than p by default. These assumptions are reasonable in the context of processing document literals, but may not be accurate for modern web applications.

We may usually want elements to have no margins by default, so we delete all the default margins. When you really want to add some margin to a specific label, you can add it in a custom style. The wildcard selector (*) has very low specificity, so it is easy to override this rule.

3. Percentage based height

html, body {
  height: 100%;
}

Have you ever tried using percentage-based heights in CSS, only to find that it didn't seem to work? Let's look at an example:

Here the main element has 100% height, but the element doesn't grow at all. This doesn't work because in fluid layout (the main layout pattern in CSS), height and width operate on a completely different principle. An element's width is calculated from its parent element, while an element's height is calculated from its child elements.

main Elements can grow when this rule is applied :

If you're using a JavaScript framework like React, you might also want to add a third selector to this rule: the root-level element used by the framework .

For example, in a Next.js project, update the rules as follows:

html, body, #__next {
  height: 100%;
}

So why set a percentage-based height instead of using vh units? The problem is that the vh unit doesn't work properly on mobile; 100vh will take up more than 100% of the screen real estate, because mobile browsers do this where the browser UI appears and disappears. In the future, new CSS units will solve this problem. Until then, percentage-based heights can be used.

4. Adjust row height

body {
  line-height: 1.5;
}

line-height controls the vertical spacing between each line of text in a paragraph. The default varies by browser, usually around 1.2. This unitless number is based on the font size, just like em units. With a line height of 1.2, each line height will be 20% larger than the element's font size.

Here's the problem: For people with dyslexia, the lines are packed so tightly together that it's hard to read. The WCAG standard states that the line height should be at least 1.5. This figure does tend to produce rather large lines on headings and other large font elements:

You may wish to override this value on headers. My understanding is that the WCAG standard applies to "body" text, not headings.

5. Smooth Fonts

body {
  -webkit-font-smoothing: antialiased;
}

On MacOS computers, the browser uses Subpixel Antialiasing by default. This is a technology designed to make text easier to read by utilizing R/G/B light within each pixel. In the past, this was seen as an accessibility win, as it improved text contrast.

In MacOS Mojave, released in 2018, Apple disabled subpixel antialiasing across the operating system. However, MacOS browsers like Chrome and Safari still use subpixel antialiasing by default. We need to turn it off by  -webkit-font-smoothing setting  antialiased to .

In the figure below, the left side is the effect after closing:

MacOS is the only OS that uses subpixel antialiasing, so this rule has no effect on Windows, Linux, or mobile devices. If you're using a MacOS computer, you can compare the real-time rendering of the two (without CSS reset):

p {
  -webkit-font-smoothing: subpixel-antialiased;
  font-family: sans-serif;
}

.antialiased {
  -webkit-font-smoothing: antialiased;
}

The effect is as follows:

6. Media Defaults

img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
}

In HTML, images are considered inline elements. This means it should be used in the middle of a paragraph, like <em> or  <strong>. This is inconsistent with how images are used most of the time. In general, images are treated the same way as paragraphs, headings, which are layout elements.

However, if you try to use inline elements in your layout, weird things happen. If you've ever had a mysterious 4px gap, it wasn't padding, marginor border, it was probably inline space added by the browser with the line-height.

This problem is avoided by setting display: block to the image. In addition to that, it is also set max-width: 100%. This is done to prevent large images from overflowing if they are placed in a container that is not wide enough. Most block-level elements automatically grow/shrink to fit their parent, but  <img> media elements like this are special: they're called replaced elements, and they don't follow these rules.

If the original size of the image is 800x600, even if you put it in a parent element with a width of 500px, it will be 800px wide. This rule will prevent the image from growing out of its container, which is probably a more sensible default behavior.

7. Inherit the font of the form control

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

By default, buttons and input fields do not inherit typography styles from their parent elements. Instead, they have their own weird style. For example, <textarea> the system default monospaced font will be used. input Input will use the system default sans serif font. Both will choose a very small font size (13.333px in Chrome). Reading 13px text on a mobile device can be difficult. When focusing on an input with small fonts, the browser will automatically zoom in, making the text easier to read.

Here's a not-so-good experience:

If you want to avoid this autoscaling behavior, the input font size needs to be at least 1rem / 16px. Here is one way to solve this problem:

input, button, textarea, select {
  font-size: 1rem;
}

This does solve the autoscaling problem, but that's cosmetic. The root cause of this problem is: form input should not have its own typography style .

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

font is a seldom-used shorthand that sets some font-related properties like  font-size, font-weight, font-family. By setting it to  inherit, you specify that these elements match the typography in their surroundings. Doing this will fix these issues as long as you don't set a very small font for the body text.

8. Word wrap

p, h1, h2, h3, h4, h5, h6 {
  overflow-wrap: break-word;
}

In CSS, text wraps automatically if there is not enough space for all characters on a line. By default, the algorithm looks for opportunities for "soft line breaks", which are characters that the algorithm can split on. In English, the only soft-wrapping opportunities are spaces and hyphens, but this varies from language to language.

If a line doesn't have any chance of soft-wrapping, and it doesn't fit in a newline, it will cause text to overflow:

This can cause horizontal scrollbars to appear, text to overlap other elements, or slide behind images/videos.

overflow-wrap Attributes can tune the newline algorithm and allow it to use hard-wrap if no soft-wrap opportunities are found:

In addition, you can also try adding the hyphens attribute:

p {
  overflow-wrap: break-word;
  hyphens: auto;
}

hyphens: auto uses hyphens (in languages ​​that support it) to specify hard line breaks, which makes hard line breaks more common. This may be worthwhile if the text column is very narrow, but it can also be a bit distracting. So didn't include it in the reset, but worth a shot!

9. Root cascading context

#root, #__next {
  isolation: isolate;
}

This item is optional. It's usually only needed when using a JavaScript framework like React. The isolation property allows us to create a new stacking context without setting z-index. This ensures that certain high-priority elements (such as modals, dropdowns, tooltips) will always be displayed on top of other elements in the app.

We need to adjust the selector, which selects the top-level element rendered in the application, according to the framework used. For example, create-react-app is used  <div id="root">, so selectors should be used #root.

Finally, take a look at the full code for these reset styles, which you can copy/paste into your own projects:

*, *::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;
}

Reference article: https://www.joshwcomeau.com/css/custom-css-reset/

Guess you like

Origin blog.csdn.net/maxue20161025/article/details/128075088
Recommended