每当我开始一个新项目时,首要任务就是磨平CSS语言中的一些粗糙边缘。我通过一套功能性的自定义基线样式来做到这一点。
很长一段时间,我使用的是Eric Meyer著名的CSS重置。这是一段结实的CSS代码,但现在有点过时了;它已经十多年没有更新了,而且自那时以来发生了很多变化!
最近,我一直在使用自己的定制CSS重置。它包括我发现的所有小技巧,以改善用户体验和CSS编写体验。
像其他CSS重置一样,在设计/美学方面它是没有偏见的。无论您的美学目标是什么,您都可以为任何项目使用此重置。
在本教程中,我们将深入了解我的自定义CSS重置。我们将深入探讨每个规则,您将了解它的作用以及为什么要使用它!
CSS重置
废话不多说,这就是它:
/*
1. 使用更直观的盒模型。
*/
*, *::before, *::after {
box-sizing: border-box;
}
/*
2. 移除默认的边距
*/
* {
margin: 0;
}
/*
字体排版调整!
3. 添加可访问的行高
4. 改善文字渲染
*/
body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
/*
5. 改善媒体默认值
*/
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
}
/*
6. 移除内置表单排版样式
*/
input, button, textarea, select {
font: inherit;
}
/*
7. 避免文本溢出
*/
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word;
}
/*
8. 创建根堆叠上下文
*/
#root, #__next {
isolation: isolate;
}
它相对较短,但在这个小样式表中包含了很多内容。让我们深入了解一下!
一些琐碎的注释
历史上,CSS重置的主要目标是确保浏览器之间的一致性,并撤消所有默认样式,创建空白状态。我的CSS重置实际上没有做到这两点。
如今,浏览器在布局或间距方面没有太大的差异。总的来说,浏览器忠实地实现了CSS规范,一切都表现得如您所期望的那样。因此,这并不是那么必要了。
我也不认为有必要去除所有浏览器默认值。例如,我可能确实希望
<em>
标签设置font-style: italic
!我可以在各个项目样式中做出不同的设计决策,但我认为剥夺常识默认值没有意义。我的CSS重置可能不符合“CSS重置”的古典定义,但我做了这种创造性的自由。
1. 盒模型
快来做个小测验!根据可见的粉色边框,假设没有应用其他CSS,以下情况下.box
元素有多宽?
<style>
.parent {
width: 200px;
}
.box {
width: 100%;
border: 2px solid hotpink;
padding: 20px;
}
</style>
<div class="parent">
<div class="box"></div>
</div>
我们的.box
元素具有width: 100%
。因为其父元素宽度为200px,这个100%将解析为200px。
但是它将这个200px宽度应用在哪里呢?默认情况下,它将这个大小应用在内容框上。
如果您不熟悉,"内容框"是实际包含内容的框模型中的矩形,位于边框和填充内部:
width: 100%
声明将.box
的内容框设置为200px。填充会额外添加40px(每边20px)。边框会额外添加4px(每边2px)。当我们进行计算时,可见的粉色矩形将是244px宽。
当我们试图将244px的框塞入宽度为200px的父元素时,它会溢出:
<style>
.parent {
width: 200px;
border: 2px solid black;
}
.box {
width: 100%;
border: 2px solid hotpink;
padding: 20px;
}
</style>
<div class="parent">
<div class="box"></div>
</div>
* {
/* 这是典型的默认值。 */
/* 我在这里撤消了我的CSS重置。 */
box-sizing: content-box;
}
这种行为很奇怪,对吧?幸运的是,我们可以通过设置以下规则来更改
它:
*, *::before, *::after {
box-sizing: border-box;
}
应用此规则后,百分比将根据边框框解析。在上面的示例中,我们的粉色框将是200px,而内部的内容框将缩小到156px(200px - 40px - 4px)。
在我看来,这是一个必须的规则。它让CSS的工作变得显著更加愉快。
我们使用通配选择器(*
)将其应用于所有元素和伪元素。与流行观念相反,这对性能并不会有影响。
2. 移除默认边距
* {
margin: 0;
}
浏览器对边距进行了常识假设。例如,默认情况下,h1
的边距会比段落多。
在文字处理文档的背景下,这些假设是合理的,但对于现代网络应用程序可能不准确。
边距是一个棘手的东西,而且我经常发现自己希望元素默认情况下没有任何边距。因此,我决定将其全部移除。🔥
如果/当我想要为特定标签添加一些边距,我可以在自定义项目样式中这样做。通配选择器(*
)的特异性极低,因此很容易覆盖此规则。
3. 调整行高
body {
line-height: 1.5;
}
line-height
控制段落中每行文本之间的垂直间距。默认值在不同浏览器之间有所不同,但通常在1.2左右。
这个无单位的数字是基于字体大小的比例。它的功能就像em
单位一样。使用line-height
为1.2,每行将比元素的字体大小大20%。
问题在于:对于那些患有阅读障碍的人来说,这些行之间的距离过于紧密,使阅读变得更加困难。 WCAG标准规定line-height至少应为1.5。
现在,这个数字确实会在标题和其他具有大字体的元素上产生非常大的行间距:
<style>
* {
line-height: 1.5;
}
</style>
<p>
这段文字的行高比例为1.5倍,感觉
很不错,对吧?我认为
这段文字易读且愉快。
</p>
<h1>
但标题上有点太多了!
</h1>
h1 {
font-size: 4rem;
margin-top: 0.5em;
}
您可能希望在标题上覆盖此值。我理解WCAG标准是针对“body”文本而言的,而不是标题。
使用“calc”更智能的行高
我一直在尝试另一种管理行高的替代方法。这是它的样子:
* {
line-height: calc(1em + 0.5rem);
}
这是一个相当高级的小片段,超出了本文的范围,但这里是一个简短的解释。
4. 字体平滑
body {
-webkit-font-smoothing: antialiased;
}
好了,这个有点有争议。
在MacOS计算机上,默认情况下,浏览器会使用“子像素抗锯齿”。这是一种旨在通过利用每个像素中的R/G/B光线使文本更易于阅读的技术。
过去,这被视为一种可访问性的胜利,因为它提高了文本对比度。您可能已经阅读过一篇流行的博客文章停止“修复”字体平滑,该文章主张不要切换到“抗锯齿”。
问题在于:该文章是在2012年编写的,在高DPI“视网膜”显示器出现之前。今天的像素要小得多,肉眼看不见。
像素LED的物理排列也发生了变化。如果您用显微镜观察现代显示器,您不会再看到有序的R/G/B线网格。
在2018年发布的MacOS Mojave中,苹果在整个操作系统中禁用了子像素抗锯齿。我猜他们意识到在现代硬件上这样做带来的危害更大。
令人困惑的是,像Chrome和Safari这样的MacOS浏览器仍然默认使用子像素抗锯齿。我们需要显式关闭它,将-webkit-font-smoothing
设置为antialiased
。
看看区别:
MacOS是唯一使用子像素抗锯齿的操作系统,因此此规则对Windows、Linux或移
动设备没有影响。如果您使用的是MacOS计算机,您可以尝试使用实时渲染:
<p>
这个段落使用默认的子像素抗锯齿。
</p>
<p class="antialiased">
这个段落没有使用子像素抗锯齿。
</p>
p {
/* 撤消CSS重置 */
-webkit-font-smoothing: subpixel-antialiased;
font-family: sans-serif;
}
.antialiased {
-webkit-font-smoothing: antialiased;
}
5. 合理的媒体默认值
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
}
这里有一个奇怪的问题:图像被视为“内联”元素。这意味着它们应该像<em>
或<strong>
一样在段落中间使用。
这与我使用图像的方式不符。通常情况下,我将图像视为与段落、标题或侧边栏相同的布局元素。
但是,如果我们尝试在我们的布局中使用内联元素,则会发生奇怪的事情。如果您曾经遇到过一个神秘的4px间隙,而它既不是边距、也不是填充、也不是边框,那么它可能是浏览器使用的“内联神奇空间”。
通过默认情况下将所有图像设置为display: block
,我们就可以绕过整个一类奇怪的问题。
我还设置了max-width: 100%
。如果将大图像放置在不足以容纳它们的容器中,这样做可以防止图像溢出。
大多数块级元素都会自动调整大小以适应其父级,但像<img>
这样的媒体元素是特殊的:它们被称为替换元素,它们不遵循相同的规则。
如果图像的“原生”大小为800×600,则<img>
元素也将为800px宽,即使我们将其放置在500px宽的父级中。
此规则将阻止该图像超出其容器,对我来说,这种行为更加合理。
6. 继承表单的字体
input, button, textarea, select {
font: inherit;
}
这里还有另一个奇怪的事情:默认情况下,按钮和输入框不会从其父级继承字体样式。相反,它们有自己奇怪的样式。
例如,<textarea>
将使用系统默认的等宽字体。文本输入将使用系统默认的无衬线字体。两者都将选择微小的字体大小(Chrome中为13.333px)。
您可能想象不出在移动设备上阅读13px文字是多么困难。当我们聚焦具有小字体大小的输入时,浏览器将自动放大,以使文本更容易阅读。
不幸的是,这不是一个很好的体验:
如果我们想要避免这种自动缩放行为,那么输入需要至少具有1rem / 16px的字体大小。以下是解决此问题的一种方法:
input, button, textarea, select {
font-size: 1rem;
}
这解决了自动缩放问题,但这只是一个权宜之计。我们应该解决根本原因:表单输入不应该有自己的字体样式!
input, button, textarea, select {
font: inherit;
}
font
是一个很少使用的快捷方式,它设置了一堆与字体相关的属性,如font-size
、font-weight
和font-family
。通过将其设置为inherit
,我们指示这些元素匹配其周围环境中的字体。
只要我们不为我们的主体文本选择一个过于小的字体大小,这就解决了所有问题。🎉
7. 文字换行
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word;
}
在CSS中,如果没有足够的空间来容纳所有字符在同一行中,文本将自动换行。
默认情况下,算法将寻找“软换行”机会;这些是算法可以在其上拆分的字符。在英语中,唯一的软换行机会是空格和连字符,但这在语言之间会有所不同。
如果一行没有任何软换行机会,并且不适合,则会导致文本溢出:
代码播放区
<div class="wrapper">
<p>
这是一个窄列文本,有一个非常长的单词:antidisestablishmentarianism。
</p>
<p>
使用URL时会出现相同的问题:https://www.somewebsite.com/articles/a1b2c3
</p>
</div>
.wrapper {
border: 2px solid;
padding: 16px;
}
p:not(:last-of-type) {
margin-bottom: 1em;
}
这可能会导致一些恼人的布局问题。在这里,它添加了一个水平滚动条。在其他情况下,它可能导致文本重叠其他元素,或滑到图像/视频后面。
overflow-wrap
属性让我们调整换行算法
。它接受一个值,normal
(默认)或break-word
。
在break-word
模式下,如果一行没有任何软换行机会,浏览器将找到第一个软换行机会并在那里断开。
在上面的示例中,单词“antidisestablishmentarianism”将被拆分为“antidisestablishmentari”和“anism”。同样,URL将被拆分为两个短段,每个段落适合其容器。
8. 创建根堆叠上下文
#root, #__next {
isolation: isolate;
}
这是一种相对较新的CSS功能,用于创建堆叠上下文。
这并不是一种独立于Flexbox或网格布局的布局工具,而是一种用于管理元素如何在Z轴上堆叠的工具。
通过创建一个根堆叠上下文,我们可以控制子元素如何堆叠,而不受外部元素的影响。这对于web组件、小部件和其他可能在不受信任的上下文中使用的代码来说尤其有用。
在React应用程序中,#root
和#__next
元素通常是应用程序的最高级别元素。通过在这些元素上应用isolation: isolate
,我们可以确保我们的组件在任何上下文中的行为都是一致的。
这是一个非常强大的属性,我尝试在大多数项目中都将其使用!
结束语
这是我的自定义CSS重置!它可能不是标准的CSS重置,但它是我目前正在使用的。我喜欢它的简洁性和功能性,我希望您也喜欢。
我特别喜欢它的简洁性。相比之下,Eric Meyer的重置有很多额外的规则。例如,他还会移除input[type="checkbox"]
的appearance
,以及更多其他奇怪的东西。这些是我从未遇到过的问题,因此我认为在我的项目中添加它们没有意义。
除此之外,我认为这个重置非常适合React和其他组件库。它只涉及全局样式,不会破坏组件封装性。我发现自己将它与Emotion或Styled Components一起使用,这样我就可以确保每个项目都有一致的外观。
如果您对我自定义CSS重置有任何想法或建议,请随时在GitHub存储库中打开一个问题!