深入解析自訂的CSS重置樣式

青灯夜游
發布: 2022-01-26 11:04:20
轉載
3060 人瀏覽過

本篇文章帶大家深入解析下自訂的CSS重置樣式,研究下其中的每一條規則,並分析下使用該規則的原因,希望對大家有所幫助!

深入解析自訂的CSS重置樣式

每當我開始一個新專案時,首要的任務就是處理 CSS 語言中的那些邊邊角角的問題。為了解決這些問題,通常會使用自訂的一組基礎樣式。

過去很長一段時間,我使用的是來自 Eric Meyer 那份著名的 CSS 重置樣式(CSS Reset)。作為一個古老且實用的 CSS 程式碼,在過去十多年裡它從未被更新過,而這段期間很多東西都已經發生了巨大的變化!

最近,我開始使用我自己定義的 CSS 重設樣式。它包含了我總結的許多小技巧,既可以改善使用者體驗又能提升 CSS 開發體驗。在本文中,我們將介紹這個自訂的 CSS 重設樣式。並深入研究其中的每一條規則,除了討論每條規則的作用之外,還將深入淺出的解析使用該規則的原因!

背景介紹

從歷史上看,CSS 重置樣式主要作用是清除了瀏覽器的預設樣式,以此來確保瀏覽器之間樣式的一致性。而我的這份 CSS 重置樣式並不是為了解決這個問題。

如今,不同瀏覽器之間在佈局或間距方面的差異已經微乎其微。總的來說,現代的瀏覽器,正如我們所期望的那樣,已經忠實地實現了 CSS 規範。所以,對樣式一致性問題的處理已經不是那麼重要了。

而且,我從不認為去掉瀏覽器所有的預設樣式是必要的。例如,我會用 標籤將字體樣式設定為斜體!雖然在不同的專案中可能要遵守不同的設計規範,但我認為去除常識性的預設設定是毫無意義的。

我的這份 CSS 重置樣式可能不符合 “CSS重置樣式” 的經典定義,但從另一個角度來說,這份 CSS 重置樣式也擁有了更多的創造力。

我的CSS Reset

閒話少敘,直接上程式碼:

/* 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; }
登入後複製

雖然程式碼較短,但在這個小樣式表中包含了很多乾貨。讓我們開始吧!

1. Box-sizing 盒子模型

在開始之前,先回答一個問題!在沒有其他 CSS 樣式的情況下,下面程式碼中的.box元素(粉紅色邊框的矩形區域)的寬度是多少?是 200px、240px、244px 還是 0px 呢?

 
登入後複製

.box元素的樣式中設定了width: 100%,由於它的父元素.parent的寬度是200px ,所以這裡的100% 會被解析為200px。

那麼這 200px 的寬度會作用在哪裡呢?預設情況下,瀏覽器會將這個寬度套用在內容框上 (content box)。正如我們所熟知的那樣,這裡所說的「內容框」 是盒子模型裡的盒子實際包含的內容,它在border 和padding 內部:

深入解析自訂的CSS重置樣式

width: 100%.box盒子模型的content 部分設定為200px;內邊距padding 會額外增加40px 寬度(每邊各20px);邊框border 會增加4px(每邊各2px)。透過加法計算不難得出粉紅色邊框矩形的寬度為 244px。因此,上面提到的問題的答案是 244px。

當我們試圖將一個244px 的盒子塞進一個200px 寬的父容器時,它會發生溢出:

深入解析自訂的CSS重置樣式

##這種行為看起來很奇怪,我們可以透過以下設定來更改它:

*, *::before, *::after { box-sizing: border-box; }
登入後複製

應用此規則後,寬度的百分比將基於border-box 進行解析。在上面的例子中,我們的粉紅色框是 200px,而內部的 content-box 將縮小到 156px (200px - 40px - 4px)。

在我看來,這是一條必不可少的樣式的規則,因為它會使 CSS 更易於使用。我們用通配符選擇器(

*)將其應用於所有元素和偽元素。與大眾認知完全相左的是,這個樣式設定並不會導致效能變壞,具體可參考文章* { Box-sizing: Border-box } FTW

Inheriting box-sizing

我在網路上看到了另外一種樣式設定:

html { box-sizing: border-box; } *, *:before, *:after { box-sizing: inherit; }
登入後複製

如果您想在一个已存在的大型项目中迁移使用 border-box,那么这将是一个有用的策略。如果你从零开始一个全新的项目,这是没有必要的。为了简单起见,我在 CSS 重置样式中省略了它。

首先,我们可以创建一个 “legacy” 选择器,将 box-sizing 的值继续保留为content-box,这也是 box-sizing 属性的默认值:

.legacy { box-sizing: content-box; }
登入後複製

然后,当应用程序中存在尚未迁移使用 border-box 时,我们就可以将该类添加到对应的位置,以保持原有样式不被影响:

 
登入後複製

为什么要这样做呢?现在,让我们思考一下这个代码段中的元素是如何计算的。

  • 被赋予了legacy,因此它使用了box-sizing: content-box

  • 其子元素

  • 标签没有legacy,因此它从其父级继承;而继承自已经被设置为border-box

从本质上讲,每个元素都可以从其父元素获得 box-sizing 属性。如果它有一个设置了legacy的祖先,那么它的属性值是content-box。否则,它将最终从标签中继承,其属性值为border-box

2. 移除 margin 的默认值

* { margin: 0; }
登入後複製

浏览器会对外边距 (margin) 做出很多常识性假设。例如,h1在默认情况下要比段落的边距更大。这些假设在那些做文字处理的文档中是合理的,但对于现代 web 应用程序来说可能并不准确。

另外,外边距会在你稍不留神的时候遭遇外边距塌陷的问题,它可真是一个令人讨厌的小机灵鬼呢。而且,我发现自己经常希望元素在默认情况下没有任何外边距。所以我决定把它全部去掉。

当我确实希望向特定的标签添加外边距时,我可以在项目中用自定义样式中来实现。通配符选择器(*)的优先级极低,这条规则很容易被覆盖。

3. 基于百分比的 height

html, body { height: 100%; }复制代码
登入後複製

我们在 CSS 中经常会使用百分比来设置高度,很多时候却发现它似乎并没有效果。请看下面的示例:

深入解析自訂的CSS重置樣式

虽然将main元素设置为height: 100%,但元素的高度根本没有变化!

这里不起作用的原因是,在 CSS 流式布局(CSS 中的主要布局模式)中,heightwidth的工作原理完全不同。元素的宽度是基于父元素计算的,元素的高度是根据其子元素计算的。这个话题说起来比较复杂,远远超出了本文的范围,本文中不再展开讨论。

在下面的代码示例中,我们将上面的规则应用到代码中,会发现main元素的高度变为了 100%:

深入解析自訂的CSS重置樣式

如果您使用的是像 React 这样的 JavaScript 框架,那么您可能还需要在此规则中添加第三个选择器:框架使用的根元素。

例如,在我的 Next.js 项目中,会将规则做如下更新:

html, body, #__next { height: 100%; }
登入後複製

为什么不使用 vh?

你可能会想:为什么非得使用百分比来设置高度呢?为什么不用vh替代呢?

问题是vh不能在移动设备上正常工作;在移动设备上浏览器 UI 在上下滑动的时候,视口的可见部分会进行调整,这就导致100vh在浏览器中是不固定的,可能会超过屏幕实际的使用面积。

在未来,新的 CSS 单位将解决这个问题。在此之前,我继续使用基于百分比的高度。

4. 更改 line-height

body { line-height: 1.5; }
登入後複製

行高line-height控制段落中每行文本之间的垂直间距。它的默认值因浏览器而异,但通常在 1.2 左右。这个没有单位的数字是基于字体大小的比值。它的功能就像em一样。line-height为 1.2 时,每行的行高将比元素的字体大 20%。

这里带来一个问题,对于那些有阅读障碍的人来说,这些句子排得太近,使阅读变得更困难。WCAG 标准规定,行高应至少为 1.5

现在,1.5 这个数字会影响标题 (如 h1、h2 等标签) 和其他大字体元素,使它们产生了相当大的行间距:

深入解析自訂的CSS重置樣式

您可能直观的想到,在标题上重新设置行高。我的理解是,WCAG 标准是针对 “body” 文本,这里只对 body 设置了 1.5 倍行高。

使用 “calc” 灵活的设置 line-heights

我一直在尝试着另一种设置行高的方法,如下所示:

* { line-height: calc(1em + 0.5rem); }
登入後複製

这是一个相当高级的代码片段,虽然它又超出了本文的范围,这里还是会简单做一下介绍。

这个方法并没有用字体的大小值乘以 1.5 这样的数字来计算行高,而是以字体大小作为基数,并为每行添加固定的空间。对于 body 里面的文字段落((paragraphs),每行都将解析为 24px(假设使用的是浏览器的默认字体大小)。

不过,在较大的文本上,此声明会产生更紧的行。下面的示例可以做出验证:

深入解析自訂的CSS重置樣式

这个在使用时需谨慎,目前我还在试验中。

其中的一个缺点是,我们必须用*将其设置在所有元素上,而不是将其应用于body。这是因为em单位不能被子元素很好地继承;它不能使每个元素重新计>算1em所对应的值。例如,在这个博客上,因为第三方代码假设行高是可继承的,导致我的代码被它破坏了。

有关这项技术的更多信息,请查看 Kitty Giraudel 的这篇很棒的博文:使用 calc 计算最佳行高

5. 设置 font-smoothing

body { -webkit-font-smoothing: antialiased; }
登入後複製

这个 CSS 设置存在一点争议。

在 MacOS 计算机上,默认情况下浏览器会使用 “亚像素抗锯齿(subpixel antialiasing)”。这种技术可以利用每个像素内的 R/G/B 灯光使文本更易于阅读。

在过去,这个技术被认为提高了可访问性,因为它改善了文本对比度。你可能读过一篇流行的博文,停止 “修复” 字体平滑,这篇文章并不提倡切换到 “抗锯齿(antialiased)”。

问题是,这篇文章写于 2012 年,那时高 DPI “视网膜(retina)” 显示时代还未来临。今天的像素更小,肉眼根本看不见。LED 像素的物理布局也发生了变化。如果你在显微镜下观察现代显示器,你已经不会看到有序的 R/G/B 线网格了。

在 2018 年发布的 MacOS Mojave 中,苹果公司在操作系统中禁用了亚像素抗锯齿。我猜他们意识到,对现代硬件来说,这个技术的弊大于利。

令人困惑的是,像 Chrome 和 Safari 这样的 MacOS 浏览器,在默认情况下仍然使用亚像素抗锯齿。因此,我们需要将-webkit-font-smoothing设置为antialiased来显式关闭亚像素抗锯齿。

这两者的区别在于:

深入解析自訂的CSS重置樣式

MacOS 是唯一使用亚像素抗锯齿的操作系统,因此这个 CSS 规则对 Windows、Linux 或移动设备没有影响。如果您使用的是 MacOS 计算机,则可以尝试运行一下下面的代码示例:

深入解析自訂的CSS重置樣式

6. 更改媒体元素的默认值

img, picture, video, canvas, svg { display: block; max-width: 100%; }
登入後複製

在 CSS 中图像被认为是 “inline” 内联元素,也就意味着它们应该像那样在段落中间使用。这与我们经常使用图像的方式是不符的。通常,我们使用图片的方式与对待段落、标题或边栏的方式相同,这些都是布局元素。

但是,如果我们布局中试图使用内联元素,就会碰到奇奇怪怪的事情。比如内联元素的 4px 空白间距问题,这个神奇的空白与line-height有关系。通过在所有图像上设置display:block,我们避开了这一类问题。

我还设置了max-width: 100%,这样做是为了防止大型图像溢出,特别是它们被放在一个不够宽的容器中。

大多数块级元素将自动伸长/收缩以适应其父元素,但像深入解析自訂的CSS重置樣式这样的媒体元素是特殊的:它们被称为替换元素,并且它们也不遵循相同的规则。

如果图像的 “自身的” 大小为 800 × 600,那么深入解析自訂的CSS重置樣式元素的宽度也将为 800px,即使我们将其放入一个 500px 宽的父元素中。

这个规则将防止图像超出其容器,我认为这是一个比较明智的做法。

7. 表单控件的字体继承

input, button, textarea, select { font: inherit; }
登入後複製
登入後複製

在默认情况下,按钮和输入框不会从它们的父项继承排版样式。相反,他们有自己怪异的风格。例如,