首页 >web前端 >html教程 >REM vs EM_html/css_WEB-ITnose

REM vs EM_html/css_WEB-ITnose

WBOY
WBOY原创
2016-06-24 11:25:531146浏览

网页字体排版的最佳实践之一就是使用相对单位,如 rem 和 em .

问题是,你应该使用哪一个呢?一直以来, rem 支持者和 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 选择器的真正大小是多少呢?

我们要根据

的父元素来计算 font-size 。它的父元素是 ,并且它的 font-size 被设置为 16px 。

通过这种方式,我们可以计算出 h1 的值为 32px ,或者说 2 * 16px .

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

虽然也可以实现,但是这并不被认为是一个好主意,通过在 中设置 font-size 的像素值将影响用户浏览器所设置的值。

取而代之,你可以使用 percentage 值,或者完全摒弃 font-size 。

注意:如果你完全摒弃 font-size ,它的值将被默认为 100% .

html { font-size: 100% } /*这里的意思是默认值为16px*/

对于大多数的用户(和浏览器), font-size 的值为 100% ,就会默认为 16px ,除非用户通过浏览器设置来改变 font-size 的默认值。但是很少有人这么做。

好了,让我们回到 em 。

em 也可以用来指定除了 font-size 的其它属性值。 margin 和 padding 属性也经常用 em 设置大小。

这里是很多人开始对 em 的值产生困惑的地方。

考虑下面的代码。

元素的 margin-bottom 的值应该是多少?(假设 的 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 。因为

中的 font-size 被设置为了 2em 。其他用在

内的 em 来计算的属性,就为 1em = 32px 。

在不同的代码中, 1em 就会有不同的取值,这就是经常迷惑人们的地方。如果你也是刚刚接触 em ,你也会产生迷惑。

不管怎么说,这就是 em .接下来,让我们认识 rem 。

什么是REM?

rem 指根 em 。 它的产生是为了帮助人们解决 em 所带来的计算问题。

它是字体排版的一个单位,等同于根 font-size 。这意味着 1rem 等同于 中的 font-size 。

考虑相同的用 rem 表示的代码。现在 margin-bottom 计算出来的值为多少呢?

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

正如您看到的,无论您在哪里设置它, 1rem 的取值均为 16px 。

这是十分可靠的,很容易去理解。

这就是 rem 。一旦你知道了什么是 em ,就很容易去理解,你是不是也同意这个观点?

现在让我们步入这篇文章的正题, rem 还是 em ?

REMs or EMs?

这是极具争议的问题。

一些开发人员完全避免使用 rem ,声称使用 rem 会使他们的组件缺少模块化。另外一些人则什么都使用 rem ,因为喜欢 rem 所带来的便捷。

奇怪的是,在我的职业生涯中,我掉进了在不同的地方是使用 rem 或者 em 的陷阱中。我喜欢 em 帮助我完成模块化组件,但是讨厌它所带来的代码复杂性。我喜欢 rem 计算的便捷,但是讨厌他是我模块化组件的阻碍。

事实证明。 rem 和 em 均有各自的优缺点。应给根据实际情况来判断其使用方式。

这里我有两个简单的规则:

  • 如果这个属性根据它的 font-size 进行测量,则使用 em
  • 其他的一切事物均使用 rem .

有点太简单了么?让我们考虑用 rem 还是 em ,来书写一个简单的组件(头部元素),此过程中你就会发现这两个规则发挥的良好作用。

仅使用 rem 来制作标题元素

你有一个看起来如下图所示的标题元素(

):

如果你用 rem 设置一切属性的大小,标题元素的样式应该和上图相似:

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

目前为止,一切都好。

既然在相同的网页上会有不同大小的元素,接下来让我们创建一个稍微大的头部元素。这里,我们尽可能继承样式。

更大元素的标记可能如下所示:

<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--larger 下,文本和边缘的空间太小。

如果你坚持使用 rem ,唯一的办法就是使用 padding 重新声明大标题:

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

有没有注意到这里的模式? .header--larger 的 font-size 是 header 的两倍大。因此, .header--large 的 padding 是 .header 的两倍大小。

如果我们有更多大小的标题,或者改变标题大小时,又会发生什么呢?你已经可以看到如果使用 rem 对整个网站进行编码所带来的重复性以及复杂性。

我们可以同时使用 rem 和 em 简化代码,这样就不需要对 .header-larger 的 padding 进行声明。

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

正如你所看到的, 当有属性需要用它的字体大小( font-size )进行大小声明时,这时 em 就相当有用。 这就是第一条原则产生的地方。

接下来让我们看看,如何只使用 em 来创建相同的标题。

只使用 EMs 制作标题元素

只使用 em 来制作标头元素和只使用 rem 制作的代码差不多,只需要将 rem 该更为 em .

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

.header 和 .header--larger 的效果看起来和 rem 实现效果一样。

不是吗?

不是的!

你的网页只包含一个标题元素是极不可能的。我们必须考虑标题与页面其他元素的交互。

在标题之前或之后看见其他元素是十分正常的,如下图所示:

对于这个元素集的标记如下:

<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 标签的左边和右边添加一点外边距:

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

不不不! :(

.header--larger 左边和右边的 padding 太大了!

如果你坚持只使用 em 来解决这个问题,唯一的方法就是重新声明大标头的 padding-left 和 pading-right .

.header {  font-size: 1em;  padding: 0.5em 0.75em;  /* Other styles */}.header--large {  font-size: 2em;  padding-left: 0.375em;  padding-right: 0.375em;  margin: 0.75em 0; }

注意到这里的模式了么? .header--larger 的 font-size 是 .header 的 font-size 的两倍大小,然而 .header--larger 的 padding-left 和 padding-right 是 .header 的一半。

在上述的案例中,如果我们可以同时使用 em 和 rem 就可以简化代码。具体来说就是, em 负责 padding 的左边和右边, rem 负责 padding 的顶部和底部。

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

正如你所看到的,当一个元素用 font-size 声明大小时, em 单位是十分有用的。但是,当你需要根据根 font-size 来设置属性大小时,你就会陷入麻烦之中。

在一个组件之中看 rem 和 em 如何配合工作,不是更加清楚么?

现在,让我们提高一个档次,看标题和段落之间如何在网格中进行交互。

网格组件

在这之前,让我们先把标题和段落组成一个组件:

<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/3 的网格布局中

当组件被放置在一个较小的位置时,如侧边栏。这时,标题元素就会使用一个较小的 font-size 来呈现。

通过修改组件的类,我们可以创建变量。标记将如下所示:

<div class="component component--small">  <!-- Contents of the component. --></div>

变量的样式如下:

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

现在,关于组件的样式,两条规则同样适用:

  • 如果这个属性根据它的 font-size 进行测量,则使用 em
  • 其他的一切事物均使用 rem

通过标题元素,我们了解到,是否使用 em 进行大小声明,只需判断该属性是否与页面其他元素进行交互。这里有两种不同的方式来思考如何构建此组件:

  • 所有内联元素缩放都根据组件的 font-size 决定。
  • 部分内联元素缩放根据组件的 font-size 决定。

让我们用两种方式构建组件,你就会明白我的意思。

案例1: 所有内联元素缩放都根据组件的 font-size 决定

我们通过一个例子来看这样子的组件是什么样子:

注意当组件的大小改变时,同一时间内 font-size 、 margin 和 padding 的变化。

当组件大小变化时,如果您想要这样的效果,那么就需要使用 em 进行大小声明:

.component {  background: white;  border: 2px solid #7F7CFF;}.component__header {  font-size: 2em;  padding: 0.5em 0.75em; /* Changed padding into em */  background: #7F7CFF;  margin: 0;}.component p {  padding-left: 1.5em; /* Changed padding into em */  padding-right: 1.5em; /* Changed padding into em */  margin: 1.5em 0; /* Changed margin into em */}// Small variant .component--small .component__header {  font-size: 1em;  padding-left: 1.5em; /* Added em-sized padding */  padding-right: 1.5em; /* Added em-sized padding */}

然后,要激活变化大小,你不得不更改组件的 font-size 属性。

.component {  // Other styles  @media (min-width: 800px) {    font-size: 1.5em;  }}

目前为止,一切都好。

现在,让我们开始复杂部分。

想象一下你是否有一个这样子的网格。每个网格项之间的垂直和水平空间在不同设备上需要保持一致(良好的美学需要).

网格标记为:

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

在根 font-size 大小为 16px 的情况下,我已经将每个网格项之间的间距设置为 2em 。换句话说,间距计算的宽度为 32px 。

在这个网格之中的挑战就是,小组件A和小组件B之间要保持 32px 的外边距。开始的时候我们可以将组件B的 margin-top 设置为 2em 。

.component {  /* Other styles */  @media (min-width: 800px) {    font-size: 1.25em;  }}.component + .component {  margin-top: 2em;}

不幸的是,这效果并不是很好。小组件A和小组件B之间的 margin 的大小在视觉上远远大于视窗宽度 800px 时的列间距。

这种情况的发生是因为当视窗大于 800px 时,组件的 font-size 大小为 1.5em ( 24px )。因为 font-size 为 24px ,所以 2em 就是 48px ,这不同于我们所期待的 32px .

幸运的是,当我们知道是根据 font-size 来设置列间距大小时,我们就可以用 rem 轻易地解决这个问题。

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

这里有一个Codepen,你可以尝试一下。

注意:你需要用Flexbox来创建此网格。这里我将不再过多的解释,因为不仅仅是代码问题。如果你想了解更多关于Flebox的知识,你可以参考这里的文章。

顺便说一下,我没有赶上这一技术。Chris Coyier(他是一个天才)在一年之前就写了 它 。

不管怎样,我们就到目前为止好吗?如果好的话,让我们转向案例2。如果不好的话,有时间就留下评论,我会想办法作进一步解释。

案例2:部分内联元素缩放根据组件的 font-size 决定

案例1很容易理解。缺点是 很难保持模块化缩放,主要是垂直方向间距(vertical rhythms)并且在同一组件内保持大小一致 (特别是建设响应式网站)。

有时候你只需要调整组件的一部分,而不是一次性调整所有部分。例如,您可能仅仅想要更改一个较大视区标题的 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;}

既然我们只是更改标题的 font-size 为 1200px ,我们可以使用 rem 控制一切属性的大小(不包括标题的 padding-top 和 padding-bottom 属性)

.component {  background: white;  border: 2px solid #7F7CFF;}.component__header {  font-size: 2rem; /* Sized in rem instead */  padding: 0.5em 1.5rem; /* Sized in rem instead */  background: #7F7CFF;}.component p {  padding-left: 1.5rem; /* Sized in rem instead */  padding-right: 1.5rem; /* Sized in rem instead */  margin: 1.5rem 0; /* Sized in rem instead */}.component--small .component__header {  font-size: 1rem; /* Sized in rem instead */}

然后你就可以通过在不同视区下增加一个媒体特性,来更改标题的 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  }}

注意,当我们改变浏览器大小时,标题 font-size 是如何改变的。这就是我们创建的案例2:)

还有一件事。

因为最好只使用少量的字体大小,我经常从组件上发现抽象的 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; }

这就是案例2!这里有一个Codepen供你去尝试:

这里你可能会问一个问题,“你应该使用哪种方法呢?”所以我还是先回答吧。

我会回答,这取决于您的设计。

就我个人而言,自从喜欢上自由文字排版模式,我使用案例2的时候相对多一点。

总结

所以,你应该使用 rem 或者 em 吗?我想这并不是一个很好的问题。 rem 和 em 都各有优缺点,应该综合使用它们以帮助您更简单的建立模块化组件。

扩展阅读

  • Rem VS Px
  • CSS中强大的EM
  • CSS3的REM设置字体大小
  • Sass基础——Rem与Px的转换
  • Sass函数功能——rem转px
  • 何时使用 Em 与 Rem

本文根据 @Zell 的《 REM vs EM – The Great Debate 》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处: http://zellwk.com/blog/rem-vs-em/ 。

静子

在校学生,本科计算机专业。一个积极进取、爱笑的女生,热爱前端,喜欢与人交流分享。想要通过自己的努力做到心中的那个自己。微博:@静-如秋叶

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn