【译】REM vs EM - 世纪之争

原文链接:https://zellwk.com/blog/rem-vs-em/

在网络上排版的最佳做法之一是使用像rem和em这样的相对单位。

问题是,你应该使用哪个? 在rem支持者和em支持者之间存在长期争论,rem支持者认为你应该使用rem而非em,em支持者则相反。

在本文中,您会了解我对rem和em的看法,了解rem和em究竟是什么,以及如何使用它们来构建模块化组件。

#什么是EM?

EM是一种排版单位,等于当前指定的磅值(point-size)。
--维基百科

这个定义放在网络上说不通,因为我们不使用point-size,但如果我们把point-size改成font-size,整句话就很好理解了。

意思是:如果一个选择器的font-size值是20px,那么1em = 20px。

h1 { font-size: 20px; } /* 1em = 20px */
p { font-size: 16px; } /* 1em = 16px */

em单位可以用于声明字体大小,事实上,最好使用像em这样的相对单位来设置font-size。

设想一下以下情况:

h1 { font-size: 2em; }  /* 这到底表示什么呢?! */

这里h1选择器的实际大小是多少呢?

要计算<h1>的font-size,我们得先找到它的父元素。 假设父元素是<html>,且父元素的font-size设为16px。

这样我们可以计算出<h1>的font-size值是32px,或2 * 16px。

html { font-size: 16px; }
h1 { font-size: 2em; } /* 16px * 2 = 32px */

虽然可以使用px来设置<html>的font-size,但这是一个非常糟糕的做法,因为这样会重写用户浏览器的设置。

所以,你应该改用百分比值,或者干脆不要修改font-size声明。

注意:如果你没有声明font-size,它的默认值是100%。

html { font-size: 100%; } /* 表示默认为16px */

对大部分用户(和浏览器)来说,值为100%的font-size默认为16px,除非它们通过浏览器设置修改了默认font-size,不过很少人会这样做。

到目前为止没问题吧?让我们回过头来看看em吧。

除了font-size,em还可以用于设置其他属性值,margin和padding是两个比较常见使用em作单位的属性。

这是许多人开始对em值感到困惑的地方。

设想一下下面的代码。 <h1>和<p>元素的margin-bottom值分别是多少?(假设<html>的font-size设为100%。)

h1 {
    font-size: 2em; /* 1em = 16px; */
    margin-bottom: 1em; /* 1em = 32px; */
}

p {
    font-size: 1em; /* 1em = 16px; */
    margin-bottom: 1em; /* 1em = 16px; */
}

两个margin-bottom的值同为1em,但在两种情况下它们的计算值却不同,你是否对此感到惊讶?

之所以出现这种情况,是因为1em是等于当前font-size的。 由于<h1>的font-size现在设置为2em,<h1>中使用em计算的其他属性会认为1em = 32px;

让人们觉得头晕的是,在代码的不同部分1em可以等于不同的值。如果你刚开始使用em,你可能会觉得很困惑。

不管怎样,这就是em了,下面我们来看看rem吧。

#什么是REM?

rem指的是Root EM,它是为了解决许多人面临的em计算问题而诞生的。

rem是一个等于root(根元素)font-size的排版单位,即1rem总是等于<html>上定义的font-size值。

设想如果上面的代码使用rem来写,那么margin-bottom的计算值会是多少?

h1 {
    font-size: 2rem;
    margin-bottom: 1rem; /* 1rem = 16px */
}

h1 {
    font-size: 1rem;
    margin-bottom: 1rem; /* 1rem = 16px */
}

如你所见,不管你把1rem放在哪里,它总是等于16px(除非你修改了<html>的font-size)。

这很可靠,也很容易理解。

这就是rem了,一旦你知道em是什么,你就很容易理解rem了,不是吗?

现在我们来到了这篇文章的核心,应该选择rem还是em?

#REM或EM?

这是个非常值得商榷的问题。

有些开发者完全不用rem,他们认为rem会减低组件模块化;有些开发者则不管什么时候都用rem,因为rem非常简单。

奇怪的是,在我的开发职业生涯中,我在不同阶段分别掉进了“只用rem”或“只用em”的陷阱。 我喜欢em能帮我构建模块化组件,但我讨厌它使我的代码更复杂。 我也喜欢rem能让计算变简单,但我讨厌还要使用hack来模块化我的组件。

事实证明,rem和em都有各自的优点和缺点,我们应该根据具体情况分别使用它们。

怎样根据情况?我有两条简单的规则

1. 如果属性是根据font-size缩放的,那就使用em。
  2. 其他情况一律用rem。

好像太简单了?好吧,我们试试分别使用rem和em来写一个简单的组件(一个标题元素),然后你就会明白这两条规则是如何出色地发挥作用的。

#只使用REM构建一个标题元素

假如你有这样一个标题元素(<h2>):

如果你以rem为单位定义大小,则标题的样式应该与以下内容类似:

.header {
    font-size: 1rem;
    padding: 0.5rem 0.75rem;
    background: #7F7CFF;
}

到目前为止都没问题。

接下来,我们来创建一个略大的标题元素,同一个网站上有不同大小的元素是很常见的事情。在这个过程中,我们尽可能继承更多的样式。

大标题元素的HTML代码可能会是这样的:

<a href="#" class="header header--large">header!</a>

它的CSS可能会是这样:

.header {
    font-size: 1rem;
    padding: 0.5rem 0.75rem;
    background: #7F7CFF;
}

.header--large {
    font-size: 2rem;
}

不幸的是,这些代码的结果不太尽人意,你可以看到,在.header--large中边缘和文本之间的空间太小了。

如果你坚持只用rem,那解决这个问题的唯一办法就是在大标题元素中重新声明padding:

.header {
    font-size: 1rem;
    padding: 0.5rem 0.75rem;
    background: #7F7CFF;
}

.header--large {
    font-size: 2rem;
    padding: 1rem 1.5rem;
}


你注意到规律了吗?.header--large的font-size是.header的两倍,因此.header--large的padding也是.header的两倍。

如果我们需要更多不同大小的标题,或者是已有的标题元素需要调整大小,会怎么样呢?你已经可以看到,只使用rem来编写整个网站会导致重复或超级复杂的代码。

如果我们不介意同时使用em和rem的话,我们就可以简化代码,不必再.header--large上重新声明padding。

.header {
    font-size: 1rem;
    padding: 0.5em 0.75em;
    background: #7F7CFF;
}

.header--large {
    font-size: 2rem;
}

如你所见,对于需要根据font-size来调整大小的属性,em的作用非常大,这样我们就得到了第一条规则。

接下来,我们来看看在同一个标题元素上只使用em作单位会发生什么事情吧。

#只使用EM构建一个标题元素

用em来实现的代码与之前用rem方法的代码差不多,我们只需要把rem改成em就行了。

.header {
    font-size: 1em;
    padding: 0.5em 0.75em;
    background: #7F7CFF;
}

.header--large {
    font-size: 2em;
}

.header和.header--large都会跟使用rem时一模一样。

是吗?

错!

你的网站不可能只有一个标题元素,我们还需考虑这个标题如何与页面上的其他元素相互作用。

标题前后出现其他元素是很常见的情况,像这样:

这组元素的HTML代码是:

<div class="header header--large">A Header Element</div>
<p>A paragraph of text</p>
<p>A paragraph of text</p>
<div class="header">A Header Element</div>
<p>A paragraph of text</p>

在样式表中,我们需要给<p>标签的左右加上一些margin。

p {
    margin-left: 0.75em;
    margin-right: 0.75em;
}

糟糕,大标题中的padding跟文本没有对齐

Nooo!:(

.header--large左右两边padding太大了!

如果你坚持只使用em,那解决问题的唯一办法是在大标题中重新声明padding-left和padding-right属性:

.header {
    font-size: 1em;
    padding: 0.5em 0.75em;
    background: #7F7CFF;
}

.header--large {
    font-size: 2em;
    padding-left: 0.375em;
    padding-right: 0.375em;
    margin: 0.75em 0;
}

你注意到规律了吗?.header--large的font-size是.header的两倍,但是.header--large的padding-left和padding-right却是.header的一半!

跟上面的例子一样,如果你愿意在代码中同时使用rem和em的话,代码是可以简化的。更明确地说,是在左右padding中使用rem,在上下padding中使用em:

.header {
    padding: 0.5em 0.75rem;
    font-size: 1em;
    background: #7F7CFF;
}

.header--large {
    font-size: 2em;
}

如你所见,如果需要根据font-size来调整属性大小,em是非常有用的。但是,如果需要根据根元素(root)的font-size来调整属性大小,这时候再使用em则会出问题。

在一个组件中可以更清楚地看到rem和em是如何合作的,不是吗?

现在,我们进一步来看看标题和段落如何与栅格(grid)相互作用。

#栅格中的组件

继续往下之前,我们先把标题和段落合并到一个组件中。

<div class="component">
    <div class="component__header">A header element</div>
    <p>Some paragraph text</p>
</div>

这个组件的基础样式:

.component {
    background: white;
    border: 2px solid #7F7CFF;
}

.component__header {
    font-size: 2em;
    padding: 0.5em 1.5rem;
    background: #7F7CFF;
    margin: 0;
}

.component p {
    padding-left: 1.5rem;
    padding-right: 1.5rem;
    margin: 1.5rem 0;
}

目前都没问题,这些都是我们在前面提到的东西。

我们继续,这个组件可能会出现在网站的不同地方,可能出现的地方包括:

1.主要内容区域
  2.边栏
  3.一个1/3栅格布局中
  4....

(可能会出现的地方)

如果组件位于一个比较窄的区域,比如边栏,标题元素的font-size可能需要减小:

我们可以通过修改组件的类名来创建这样一个变体,HTML代码会是这样的:

<div class="component component--small">
    <!-- 组件内容 -->
</div>

这个变体的样式:

.component--small .component__header {
    font-size: 1em;
}

对于组件的样式,之前提的两条规则依然适用:

1. 如果属性是根据font-size缩放的,那就使用em。
  2. 其他情况一律用rem。

与标题元素的例子一样,你可以通过查看属性是否与页面其余部分相互作用来确定是否使用em来定义它们的大小。 有两种不同的方法来思考如何构建这个组件:

1.所有内部元素的属性都根据组件的font-size来缩放。
2.部分内部元素的属性根据组件的font-size来缩放。

让我们分别使用两种方法来构建这个组件,然后你就会懂我的意思了。

#案例一:所有内部元素的属性都根据组件的font-size来缩放

我们先来看看这样的组件会是什么样子的:

注意到组件内所有元素的font-size、margin和padding如何同时改变的了吗?

如果你的组件需要在调整窗口大小时以这种方式改变,你需要用em来定义所有东西。代码是这样的:

.component {
    background: white;
    border: 2px solid #7F7CFF;
}

.component__header {
    font-size: 2em;
    padding: 0.5em 0.75em; /* 把padding改成em */
    background: #7F7CFF;
    margin: 0;
}

.component p {
    padding-left: 1.5em; /* 把padding改成em */
    padding-right: 1.5em; /* 把padding改成em */
    margin: 1.5em 0; /* 把margin改成em */
}

// 小组件变体
.component--small .component__header {
    font-size: 1em;
    padding-left: 1.5em; /* 添加以em为单位的padding */
    padding-right: 1.5em; /* 添加以em为单位的padding */
}

然后,要激活尺寸的更改,你只需更改组件的font-size属性。

.component {
    // 其他样式
    @media (min-width: 800px) {
      font-size: 1.5em;
    }
}

目前一切还好。

现在我们搞复杂一点。

想象一下你有这样一个栅格(grid),每个栅格项(grid item)之间垂直和水平间隔需要在所有设备上保持一致(为了美观起见)。

这个栅格的HTML代码是这样的:

<div class="grid">
    <div class="grid-item">
        <div class="component"><!-- 组件 --></div>
    </div>

    <div class="grid-item">
        <div class="component component--small"><!-- A --></div>
        <div class="component component--small"><!-- B --></div>
    </div>
</div>

我把每个栅格项(grid item)之前的间隔设为2em,根元素(root)的font-size是16px,也就是说,间隔的计算值是32px;

构建这个栅格的难点是把小组件A和小组件B用32px的margin隔开。我们可以先尝试把组件B的margin-top设为2em。

.component {
    /* 其他样式 */
    @media (min-width: 800px) {
        font-size: 1.25em;
    }
}

.component + .component {
    margin-top: 2em;
}

不过结果不尽人意,当视口大于800px时,A、B两个小组件之间的margin会大于栅格间隔。

Boo:(

之所以会这样,是因为当视口大于800px时,组件的font-size是1.5em(即24px)。因为font-size是24px,2em的计算值变成了48px,而不是我们想要的32px。

Grrrrr!(╯°□°)╯︵ ┻━┻

幸运的是我们可以通过使用rem作单位轻松解决这个问题,因为我们知道栅格间隔的宽度是基于根元素(root)的font-size的。

.component + .component {
    margin-top: 2rem;
}

Tada!问题解决了:)你可以在这个codepen上测试一下:

注意:这个栅格需要使用Flexbox来构建,我不会在这里解释如果构建它,因为超纲了,如果你有兴趣了解更多关于Flexbox的信息,可以看看这篇文章

对了,顺便说一下,这技巧不是我想出来的,Chris Coyier一年前写过相关文章(他是个天才)。

#案例二:部分内部元素的属性根据组件的font-size来缩放

案例一很好理解,不过也有不足之处,你很难保持模块化,很难确保能同时定义好每个组件的大小(特别是构建响应式网站的时候)。

有时你只需调整组件的一小部分,而不是一下子调整所有内容的大小。 例如,你可能想在视口变大时只改变标题的font-size。

我们先看一下上面写的基本样式,然后开始给这个案例添加样式:

.component {
    background: white;
    border: 2px solid #7F7CFF;
}

.component__header {
    font-size: 2em;
    padding: 0.5em 1.5rem;
    background: #7F7CFF;
    margin: 0;
}

.component p {
    padding-left: 1.5rem;
    padding-right: 1.5rem;
    margin: 1.5rem 0;
}

.component--small .component__header {
    font-size: 1em;
}

因为在1200px我只更改标题的font-size,所以我们可以安全地用rem作其他属性的单位(除了标题的padding-top和padding-bottom属性)。

.component {
    background: white;
    border: 2px solid #7F7CFF;
}

.component__header {
    font-size: 2rem; /* 用rem作单位 */
    padding: 0.5em 1.5rem; /* 用rem作单位 */
    background: #7F7CFF;
    margin: 0;
}

.component p {
    padding-left: 1.5rem; /* 用rem作单位 */
    padding-right: 1.5rem; /* 用rem作单位 */
    margin: 1.5rem 0; /* 用rem作单位 */
}

.component--small .component__header {
    font-size: 1rem; /* 用rem作单位 */
}

然后你就可以通过媒体查询轻松改变不同视口中标题的font-size了:

.component__header {
    font-size: 2rem;
    @media (min-width: 1200px) {
        font-size: 3rem;
    }
}

.component--small .component__header {
    font-size: 1rem;
    @media (min-width: 1200px) {
        font-size: 1.5rem;
    }
}

Tada!注意到当我们调整浏览器大小时,标题的font-size是如何改变的了吗?这就是我们构建案例二的方法。

还有一点。

由于最好只少量地使用字体大小,因此我经常发现把font-size从组件中抽离出来会比较好,这样你可以轻松确保所有组件的字体保持一致。

h2 {
    font-size: 2rem;
    @media (min-width: 1200px) {
        font-size: 3rem;
    }
}

h3 {
    font-size: 1rem;
    @media (min-width: 1200px) {
        font-size: 1.5rem;
    }
}

.component__header { @extend h2; }
.component--small .component__header { @extend h3; }

关于案例二就这么多!你可以在这个codepen上测试一下:

你可能有一个问题想问,所以我还是先回答一下吧:
你应该用哪个方法?

我会说取决于你的设计。

就我个人而言,比起案例一,我更多地使用案例二,因为我喜欢将字体抽象到它们自己的文件夹里。

#总结

那么,你应该用rem还是em呢?我想这不是个该问的问题。rem和em有它们各自的优点和缺点,它们可以一起使用,帮你构建简单、模块化的组件!

原文地址:https://www.cnblogs.com/sukiY/p/9787083.html

时间: 2024-10-13 15:10:32

【译】REM vs EM - 世纪之争的相关文章

rem和em和px vh vw和% 移动端长度单位

1.rem和em.px 首先来说说em和px的关系 em是指字体高度 浏览器默认1em=16px,所以0.75em=12px;我们经常会在页面上看到根元素写的font-size:65%; 这样em就成了16px*62.5=10em;这是显示在页面的字体大小是10px; 这样12px=1.2em,10px=1em,也就是说只需要将你的原来的px数值除以10,然后换上em作为单位就行了, em的特点 em是个相对值 他会根据父级元素的大小而变化 但是如果嵌套了多个元素 要计算它的大小,是件很头疼的事

CSS中的 REM PX EM

px像素(Pixel).相对长度单位.像素px是相对于显示器屏幕分辨率而言的 em是相对长度单位.相对于当前对象内文本的字体尺寸.如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸. em相对于父级元素! 任意浏览器的默认字体高都是16px.所有未经调整的浏览器都符合: 1em=16px.那么12px=0.75em,10px=0.625em.为了简化font-size的换算,需要在css中的body选择器中声明Font-size=62.5%,这就使em值变为 16px*62.5

CSS 中的rem,em,vh,vw一次说清楚

关于css中的长度单位,我们用的最多就是px,因为他简单直接.但是当一套方案匹配不同终端时,px就会显得过于生硬,不容易变通. 然而rem,em,vh,vw就可以有效的解决这一问题.让我们来看看这些东西是个啥? 首先是rem,W3C官网描述是"font size of the root element",即rem是相对于根元素.概念不好理解接咋们就直接直接看demo: DOM结构如下: CSS 代码如下: 效果如下:     现在对于rem是否有了点认识,设置html的font-siz

浅谈rem、em、px

1.px:像素(Pixel) px是相对长度单位,他是相对于显示器屏幕分辨率而言的 优点:比较稳定.精确 缺点:在浏览器 中放大或者缩小浏览页面,会出现页面混乱的情况. 如下例子: .buttonPX{ width:100px; height:60px; line-height:60px; display: inline-block; font-weight:bold;">#00a0b6; -webkit-border-radius:90px; -moz-border-radius:60p

px,rem,em 通过媒体查询统一的代码

@media only screen and (max-width: 1080px), only screen and (max-device-width:1080px) { html,body { font-size:16.875px; } } @media only screen and (max-width: 960px), only screen and (max-device-width:960px) { html,body { font-size:15px; } } @media o

rem和em的用法

1.rem转化为向素值的方法 rem单位转化为像素大小取决于根元素的字体大小,即HTML元素的字体大小,根元素字体大小乘以rem. 例:根元素的字体大小 16px,10rem 将等同于 160px,即 10rem x 16px = 160px 2.em单位如何转化为像素值 当使用em单位时,像素的单位是em值乘以使用em单位的元素的字体的大小 例:如果一个 div 有 18px 字体大小,10em 将等同于 180px,即 10 × 18 = 180 总结: rem 和 em 单位是由浏览器基于

中心化与去中心化,BDEX或将终结交易所世纪之争

数字资产交易所领域一直有一个世纪之争---中心化,还是去中心化? 都说币圈一天,世间一年.币圈一个小小的举动,就有可能在你不经意之间掀起一番巨浪,或者直接迎来一个时代的变革.那么,去中心化跨链交易所BDEX的横空出世,圈内如何评判,看好还是看空?它是否会终结中心化与去中心化的世纪之争?我们从以下几个方面聊起: 一.去中心化---区块链技术的最大特征之一提到区块链,相信90%以上的人首先想到的就是去中心化这一关键词.区块链的本质就是一个去中心化的分布式账本或数据库,它依靠遍布全球的全节点运行,每个

rem和em,px的使用

rem是CSS3中新增加的一个单位值,他和em单位一样,都是一个相对单位.不同的是em是相对于元素的父元素的font-size进行计算:rem是相对于根元素html的font-size进行计算.这样一来rem就绕开了复杂的层级关系,实现了类似于em单位的功能. Rem的使用 前面说了em是相对于其父元素来设置字体大小的,这样就会存在一个问题,进行任何元素设置,都有可能需要知道他父元素的大小,在我们多次使用时,就会带来无法预知的错误风险.而rem是相对于根元素<html>,这样就意味着,我们只需

移动端rem、em单位的使用

好多文档上老是说用rem就给html设置font-size,用em就给body设置font-size 看了下bootstrap样式表,html {font-size:62.5%;}  body {font-size:14px;},就讲这两个主要的. 解释如下: 因为在用到em和rem的时候互不影响,因为rem就是去参照你html的font-size,管你body设不设置,都与我没关系. 一.那么如果你确定要使用rem单位,就按以下三个步骤来计算: 1.确定基数:一般10px,自己记住就行,不用写