以下内容是来自 Ahmad Shadeed 的客座文章。Ahmad 提供了大量的示例来展示使用相对单位对我们有何益处。我认为我们许多人认为像 em
这样的单位是用于 font-size
的,它确实可以用于 font-size
,但也可以用于许多其他事物,将字号大小和其他视觉元素联系在一起。
我们生活在一个充满活力的世界中,我们所做的任何事都可能随时发生变化。作为前端开发者,我们应该以一种动态的方式构建我们的布局。
在这篇文章中,我们将探讨一种概念,它允许我们通过使用 CSS 相对单位(%、em 或 rem)来调整组件的大小。不仅是字号,还有该组件中的所有 UI。我们将查看实际示例,该方法的优缺点,甚至是一个以此方式构建的完整网页。
比例字体大小的简单示例

这里有三个元素
- 副标题
- 标题
- 左侧边框
使用类似于这样的 HTML
<article class="post">
<a href="#">
<span class="post-category">Featured</span>
<h2 class="post-title">Building Dynamic Components is Awesome</h2>
</a>
</article>
我希望所有内容都彼此成比例,这样当内容调整大小时,它们可以一起调整。

假设我们从像素开始
.post {
border-left: 4px solid #4a90e2;
}
.post-category {
font-size: 14px;
color: #7d7d7d;
}
.post-title {
font-size: 36px;
font-weight: bold;
color: #4a90de;
}
因此,调整整个组件大小的唯一方法是手动调整每个元素的 font-size
,以使它们在新的尺寸下相互匹配。也许您的客户告诉您,他们希望看到该区域大 1.5 倍,您需要将这些尺寸调整为 21px
和 54px
。
为了使调整变得更容易,我们可以使用百分比字体大小。
.post-category {
font-size: 85%;
}
.post-title {
font-size: 135%;
}
这表示:font-size
应该是其最近的父元素(具有定义的 font-size
)的 85%。
我们可以将该 font-size
设置在父元素上
.post {
font-size: 24px;
/*
Child elements with % font sizes...
85%
0.85 * 24 = 20.4
135%
1.35 * 24 = 32.4
*/
}
当您使用百分比时,浏览器会为您计算这些字体大小,您实际上不需要关心最终的值是什么。它只是一个比例。

如果需要,我们可以使用 em
值执行完全相同的事情。对于字体大小,百分比和 em 基本上是相同的。
.post-category {
font-size: 85%;
/* the same as */
font-size: 0.85em;
}
.post-title {
font-size: 135%;
/* the same as */
font-size: 1.35em;
}
当我们使用 em
来表示除 font-size
以外的值时,它所代表的计算像素值仍然基于 font-size
。这与例如百分比不同,百分比 width
是基于父元素的 width
,而不是 font-size
!
例如,如果我们设置
.post {
font-size: 24px;
border-left: 0.25em solid #4a90e2;
}
border-left-width
将计算为 6px
。
在以下交互式演示中,滑块会更改两个组件的 font-size
。第一个将所有内容都设置为像素:字体大小、边框、边距和填充。第二个将所有这些内容都设置为 em。
所有内容的比例缩放!
比例按钮
有时我们需要按钮的变体。也许一个更大的版本来强调更重要的号召性用语。我们可以通过使用 em
单位来获益,因为它可以用于填充,这样我们就可以轻松地通过 font-size
和 padding
来增加按钮的大小。
<button class="button">Save Settings</button>
<button class="button button--medium">Save Settings</button>
<button class="button button--large">Save Settings</button>
如果我们将所有这些变体都设置为像素,我们将得到类似于以下内容:
.button {
font-size: 16px;
padding: 10px 16px;
border-radius: 3px;
}
.button--medium {
font-size: 24px;
padding: 15px 24px;
border-radius: 4px;
}
.button--large {
font-size: 32px;
padding: 20px 32px;
border-radius: 5px;
}
相反,我们可以结合百分比和 em 值来使所有内容成比例,包括 border-radius
!
.button {
font-size: 1em; /* Let's say this computes to 16px */
padding: 0.625em 1em; /* 0.1875 * 16 = 10px */
border-radius: 0.1875em; /* 0.1875 * 16 = 3px */
}
.button--medium {
font-size: 130%;
}
.button--large {
font-size: 160%;
}
查看所有内容是否按比例缩放
图像的比例宽度/高度
这是一个示例,其中我们需要将头像图像保持比旁注和发布时间更大一些。请注意蓝色高亮显示。当我们缩放 font-size
时,其高度应发生变化。

HTML 可以像这样
<div class="bio">
<img src="author.jpg" alt="Photo of author Ahmad Shadeed">
<div class="bio__meta">
<h3><b>By:</b> Ahmad Shadeed</h3>
<time>Posted on August 5, 2016</time>
</div>
</div>
我们不仅需要设置 em 值的字体大小,还需要设置图像的宽度和高度。确保图像本身足够大,以便在缩放时不会损失太多质量!
.bio h3 {
font-size: 1em;
}
.bio time {
font-size: 0.875em;
}
.bio img {
width: 3.125em;
height: 3.125em;
}
缩放“边框”
另一个可以使用 em 值设置的属性是:box-shadow
。

我们已经知道边框可以使用 em 值进行缩放。在这里,我们将使用 em 值来设置内嵌 box-shadow
的“高度”,这样它就可以随着文本的大小进行缩放。
.headline {
box-shadow: inset 0 -0.25em 0 0 #e7e7e7;
}
注意:我们也可以使用具有硬颜色停止的 CSS 渐变来实现这一点,因为这些停止也可以设置为 em 值!
为图标留出空间
假设我们有一个带有自定义图标的装饰性 <blockquote>
。我们应该考虑字体大小发生变化时的场景。相对单位在这里可以再次提供帮助。

<blockquote class="quote">
<p>
<span>
Building dynamic web components using modular design concepts is awesome.
<em>- Ahmad Shadeed</em>
</span>
</p>
</blockquote>
我们将使用我们已经提到的相对单位来设置所有内容。我们将通过伪元素应用的 SVG 图像来放置装饰性图标。我们将使用相对定位和大小来绝对定位该伪元素,并为它(使用相对填充)在父元素上留出足够的空间。
.quote {
position: relative;
padding: 1.5em 2em;
padding-left: 4.5em;
border-radius: 0.3125em;
}
.quote p {
font-size: 2em;
}
.quote span {
box-shadow: inset 0 -0.25em 0 0 rgba(255, 255, 255, 0.4);
}
.quote:before {
content: "";
position: absolute;
top: 2.125em;
left: 1.875em;
background: url("quotes.svg") no-repeat;
height: 1.875em;
width: 1.875em;
}
有了它,如果我们更改字体大小,所有内容都会很好地缩放

请注意所有内容是如何按比例缩放的,就像我们在设计应用程序中对这些元素进行分组并进行拖动缩放一样!

如果我们使用像素值,那么事物将不会那么好地缩放。特别是图标,它可能会意外地靠近文本,或者意外地离文本很远

交互式示例
带有标题的图片
想象一下这样排列的照片和标题

我们可以基于字体大小来完成大部分设计,例如它向左和向上的偏移量、填充,甚至阴影。
<figure class="figure">
<img src="sunrise.jpg" alt="Sunrise">
<figcaption>The feeling you got from watching the sunrise is amazing.</figcaption>
</figure>
.figure figcaption {
position: absolute;
top: 1.25em;
left: -1.875em;
right: 0;
padding: 1em;
box-shadow: -0.3125em 0.3125em 0 0 rgba(0, 0, 0, 0.15);
font-size: 1.75em;
}
装饰性背景
以这个内容块中标题后面的暗色圆圈为例

让我们确保当字体大小发生变化时,它也会相应地调整大小。但是这里还有更多细微的细节。边框半径应该也是相对的,虚线厚度也应该是相对的。
<section class="block">
<h3 class="block__title">Content outline</h3>
<div class="block__content">
<p>Description to be there....</p>
</div>
</section>
.block__title {
position: relative;
font-size: 1.5em;
padding: 0.5em;
}
.block__title:after {
content: "";
position: absolute;
left: 0.25em;
top: 0;
width: 2.5em;
height: 2.5em;
border-radius: 50%;
background: #000;
opacity: 0.5;
transform: scale(1.75);
}
.block__title:before {
content: "";
margin-left: 0.5em;
border-bottom: 0.0625em dashed rgba(255, 255, 255, 0.5);
}
尽可能多地使用相对单位,所有内容都会缩放
带有图标的搜索输入
在按钮中使用图标很常见,但您也可以在输入框中使用它们。这是一个常见的示例,我们使用放大镜图标来指示搜索输入。

使用 background-image
来放置图标,并添加 padding-left
以防止文本与图标重叠。如果字体大小增加,我们应该相应地增加图标的大小。
<form class="search">
<label for="search">Enter keyword:</label>
<input type="search" id="search" placeholder="What are you searching about?">
</form>
.search input {
width: 25em;
font-size: 1em;
padding: 0.625em;
padding-left: 2.5em;
border-radius: 0.3125em;
border: 0.125em solid #b4b4b4;
background: url("search.svg") left 0.625em center/1.5em 1.5em no-repeat;
}
所有经典内容都使用相对单位设置:填充、边框、边框半径... 但我们还将相对单位用于背景位置和背景大小。现在,所有内容都会很好地缩放!
切换
考虑将自定义复选框设计为来回切换开关

这里没有我们无法缩放的东西!
<form action="" class="switch">
<p>Do you want to subscribe?</p>
<input type="checkbox" name="" id="switch" class="off-screen">
<label for="switch"><span class="off-screen">Do you want to subscribe?</span></label>
</form>
.switch label {
width: 5.625em;
height: 2.5em;
border: 0.125em solid #b4b4b4;
border-radius: 2.5em;
}
.switch label:before {
content: "";
right: 0.25em;
top: 0.21875em;
width: 2em;
height: 2em;
}
随便缩放
限制行长,仅在需要时
像这样的一段内容

我们这里有相当大的水平空间。如果不限制任何内容,这段文字的行长就会过长,让人不舒服。设置max-width
是一个限制行长的绝佳方法。我们可能不会用像素来设置它(因为我们一直在讨论的所有相同原因:它不会缩放),我们可能也不会使用百分比,因为在宽度较窄的情况下,100% 可能没问题。那就用相对单位吧!
<div class="hero">
<h2>This is title for this hero section</h2>
<p>And this paragraph is a sub title, as you know I'm writing an article about using em units to build dynamic components.</p>
<a href="#">Read about hero</a>
</div>
.hero h2 {
margin-bottom: 0.25em;
font-size: 1.75em;
}
.hero p {
margin-bottom: 1em;
max-width: 28.125em; /* limit line length */
font-size: 1.25em;
}
.hero a {
display: inline-block;
background: #4a90e2;
padding: 0.7em 1.5em;
}
现在行长被限制了,但当可用宽度较小时,它会愉快地全宽显示。
按钮中的 SVG 图标
人们喜欢使用图标字体的原因之一是,字体会随着文本的大小自动调整。但这也可以用<img>
(正如我们所见),也可以用内联<svg>
图标来实现!

我们将使用 em 值来设置width
和height
,然后图标将随着字体的缩放而按比例缩放。
<ul class="social">
<li class="social__item">
<a href="#">
<svg width="32" height="32" viewBox="0 0 32 32">
<!-- SVG Data -->
</svg>
Like on Facebook
</a>
</li>
<li class="social__item">
<a href="#">
<svg width="32" height="32" viewBox="0 0 32 32">
<!-- SVG Data -->
</svg>
Follow on Twitter
</a>
</li>
<li class="social__item">
<a href="#">
<svg width="32" height="32" viewBox="0 0 32 32">
<!-- SVG Data -->
</svg>
Follow on Dribbble
</a>
</li>
</ul>
.social__item svg {
display: inline-block;
vertical-align: middle;
width: 2.1875em;
height: 2.1875em;
}
列表计数器
假设我们用自定义设计的计数器创建了一个列表。用这种方式将文本设置到容器中,我们最好确保所有内容都按比例缩放,否则就会出现这样的问题

<ul class="list">
<li>Go to example.com and click on Register</li>
<li>Enter your email address</li>
<li>Pick a strong password</li>
<li>Congrats! You now have an account</li>
</ul>
.list li {
position: relative;
padding-left: 3.125em;
margin-bottom: 1em;
min-height: 2.5em;
}
.list li:before {
font-size: 1em;
width: 2.5em;
height: 2.5em;
text-align: center;
line-height: 2.5em;
border-radius: 50%;
}
快乐地缩放
定位图标 - 列表/警报/模态
我想你已经明白了,所以我们再举几个例子,用一个演示让你自己看看相对缩放是如何有帮助的。
汉堡菜单图标
也许你用元素和伪元素“伪造”了一个图标。这也应该是可缩放的。
渐变
我们已经了解了如何使用相对单位来设置 background-size。我们还暗示了渐变中的颜色停靠点可以使用相对单位来设置。让我们试试吧!
.box-1 {
background:
linear-gradient(
to right,
#4a90e2 0,
#4a90e2 0.625em,
#1b5dab 0.625em,
#1b5dab 1.875em,
#4a90e2 0,
#4a90e2 3.125em
);
background-size: 1.25em 100%;
}
图像精灵
有些东西有固定的尺寸,用像素来思考更容易,比如光栅图像。但这并不意味着我们不能用相对单位来处理它们。如果我们将 background-position 和 background-size 组合在 ems 中,我们可以使用CSS 精灵,它可以按尺寸缩放。
em
和rem
组合我们在这篇文章中主要使用了em
单位。我们已经确定em
单位是基于font-size
并且是级联的。但是em
有一个表亲单位:rem
。rem 单位仍然是相对的,但只相对于根元素(例如html {}
或:root {}
)。因此,它不像 em 那样级联,但如果你改变根元素的font-size
,它也会相应地改变。
通过组合 em 和 rem,我们可以保持一些尺寸固定,而其他尺寸保持动态。例如,假设你想让这些组件中的文本只相对于根元素,但其他元素相对于更直接的字体大小。比如图片,例如

看看调整直接的字体大小现在只影响图片了。
使用相对尺寸构建完整的网站
我构建了一个完整的页面,演示了如何将动态组件的概念应用到真实世界,而不仅仅局限于单个例子。

这里的所有东西都是动态尺寸的:徽标、标签、标题、作者、章节标题、编号列表、表单输入、按钮、引用块……几乎所有东西。

如果我们将默认的浏览器字体大小从 16px 更改为 20px,网站的缩放效果如下

太棒了,对吧?你注意到所有东西都缩放了吗,不仅仅是类型?这就是em
的魅力! 😍
请注意,字体大小也会随着媒体查询断点而变化。
缩放
我们基于 em 的设计也与浏览器缩放兼容。

而基于像素的设计可能会遇到问题

em
带来的挑战
使用 em 时需要注意的一点是,当你在其中设置字体大小时,它是基于最近的父元素中声明的字体大小。
.parent {
font-size: 20px;
.child {
/* This is based on 20px, so it's 30px */
font-size: 1.5em;
}
}
我想我们已经很清楚地表明了这一点。
但是当我们在 em 中调整其他东西的大小,它现在是基于当前元素新调整的字体大小。例如
.parent {
font-size: 20px;
.child {
/* This is based on 20px, so it's 30px */
font-size: 1.5em;
/* This is based on 1.5em (not 20px), so it's also 30px */
border: 1em solid black;
}
}
看到同一个元素中的两个不同的 em 值评估为相同的最终值,这可能很奇怪。
除了 ems 的级联效果本身有时很具有挑战性之外,还会发生这种情况。如果你在组件内部用 ems 调整大小,而这些组件可以嵌套,这会导致大小的级联,这可能是不可取的。

总结
- 用像素调整大小更难维护。它们不与任何其他东西相关。你需要手动调整所有像素才能改变比例。这很困难、费时且容易出错。
- 在 ems 中设置值会使事物与字体大小成比例,因此更改字体大小会缩放该元素上的所有值(并级联到子元素)。
- 用像素设置字体大小可能会阻止用户通过浏览器设置更改其默认字体大小,这对于可访问性来说是不好的。
Mark Boulton,SitePoint 播客访谈
太棒了,开创性的文章。内容详实可靠。已收藏。
很棒的文章。我希望这能成为一种趋势,并取代元素上使用 `font-size:76%` 作为一种权宜之计。
我的理解是,在任何现代浏览器中,这不再是一个问题,因此我不一定会说人们应该出于“无障碍访问”的目的使用这些技术。
相应的 WCAG 2.0 指导方针 (1.4.4) 现在几乎不可能失败。:)
比较 CSS-Tricks.com 和 americanpressinstitute.org 在您浏览器设置的不同字体大小下的显示效果,您会发现明显的区别。
在 Chrome 中,转到设置并搜索“字体大小”(或在 URL 栏中输入 chrome://settings/search#font)。
在 Firefox 中,转到“偏好设置”,然后是“内容”,并增大字体大小。
将字体大小设置为“极大”,然后比较这两个网站。CSS-Tricks 以像素为单位布局,看起来几乎相同。American Press Institute 网站使用 em 为单位布局,因此它会根据浏览器设置的字体大小进行缩放。
这在无障碍访问方面为什么重要?视力障碍人士需要更大的字体大小才能阅读。他们可以访问每个网站并按 Ctrl 或 Command 加几次来放大网站。或者,他们可以更改浏览器的默认字体大小设置,这样他们访问的所有网站都会发生更改。一个考虑了这种情况的设计良好的网站应该会根据读者对更大字体大小的偏好进行调整。
这真的很棒,但我强烈建议使用辅助函数,而不是手动计算您的 em 值。
这使得维护代码变得容易得多,尤其是在其他人接手代码并需要调整样式时。
它还有助于处理以下情况:
糟糕。
.foo-bar
不会默认设置为 `12px`,而是会默认设置为 `15px`,但我们不希望这样。相反,我们可以这样做:
啊,好多了。
.foo
的 em 值为 `20 / 16 = 1.25`,而.foo-bar
的 em 值为 `12 / 20 = 0.6`,但请记住 `0.6 * 1.25 * 16px = 12px`,这就是我们想要的结果。这也有助于处理相关属性,如文章中所述。
这将为我们提供一个想要的默认边框宽度为 `2px` 的结果,即使 `$font-size` 被更改。当然,它也会随着组件进行缩放。
等等,您已经在您的示例笔中这样做了。为什么文章中的文字示例使用 `ems`?您应该一开始就展示您的 `em()` 辅助函数,它可以解决文章末尾的许多挑战。
嗨,阿戈普,
非常感谢您的建议。您说得对,我们正在使用一个 Sass 函数来帮助计算 `em` 值。代码片段使用 `em` 单位,只是为了简化对 CSS 预处理器不了解的人员的理解。我认为,解释 CSS 背后的内容(幕后)比只展示特定的 Sass 函数更重要。
我会想办法添加一个关于使用 Sass 函数的部分,以便更多人可以学习它。
再次感谢,
好文章。我一直使用像素很长时间了,我正在计划转向相对单位。我有一个问题。如果我们在父元素中指定像素为单位的字体大小,则使用 em 为单位的子元素会使用该值。但如果我们没有为父元素指定字体大小,它会采用什么字体大小?
谢谢
谢谢阿肖克!
好问题 :) 如果我们没有指定 `font-size`,它将从具有指定 `font-size` 的最近父元素继承。如果没有,它将从根元素 `html` 继承。
希望这有帮助。
谢谢…
很棒的文章。内容有帮助,解释得很好。非常好的示例,谢谢。
喜欢这篇文章.. 是我在 css-tricks 上读过的最好的文章。
很棒的总结!演示完美地说明了 em 的强大之处,我希望看到更多的人在他们的设计中广泛采用这种方法。
我已经使用纯 em 制作了几个网站,这在为超大尺寸的“桌面”显示器逐步放大时使生活变得更加轻松;只需在媒体查询中增加根字体大小,然后 BAM!所有内容都会按比例变大,只需要进行一次小的编辑 :)。
我尝试过的一件事是使用 em 进行整个大小设置,并使用 vw 设置根字体大小。这使得网站在调整浏览器大小时按比例缩放。我设置了一些媒体查询断点,这些断点会升高/降低根 vw,并根据需要调整设计。
您能发布一些代码来说明吗?谢谢!
我在一些组件中这样做,我真的很喜欢。我会更加努力地使用 em。您的文章是必读文章。
太棒了,已收藏!
评论也很有帮助
非常好的文章。
不同意关于字体大小和无障碍访问的评论。是的,大多数浏览器现在即使是固定的字体也可以缩放,但并非总是如此,而且它经过了测试,所以为什么不提到它作为一种优势呢,因为它会填补一些小差距?
如果您的 SVG 示例使用 aria 或类似的东西,这样您就可以显示具有最高无障碍访问性的所有内容(不过不要过度使用),以配合所有其他精心完成的示例,那就更好了。
有人可以解释一下为什么我们首先需要缩放吗?
每当我遇到一篇宣扬 em 或 rem 缩放优势的文章时,我都没有看到关于这种缩放的充分解释。每个人似乎都跳到技术的细节,而不是谈论为什么。
作为旁注,IE9 开始支持使用像素值的字体缩放,甚至在那之前,许多浏览器供应商开始支持缩放。您实际上可以使用代码缩放网站,只需设置 `html{zoom:150%;}` 即可。
如果您谈论的是根据浏览器宽度进行缩放,那么最佳缩放值是多少,您是如何得出这些值的,以及为什么?
非常有帮助的文章。我一直希望使用比例单位,但我没有找到一篇像这样用这么多示例来展示其各个方面的文章。我很快就会有一个新项目,我计划开始使用比例单位。有了这篇文章作为参考,我就不怕迷路在森林里了 :D。