有一道高频的面试题经常会出现,请你讲一下em和rem的区别。

1. em与rem的区别

这个题目其实很简单,基本上都能说出来,他们的本质区别就是参照的对象不同。

  • em是相对父元素的字体大小,如果父元素的字体大小是14px,那么它子元素的2em就是28px,不同父元素的子元素的2em的实际大小是可能不同的。
  • rem是相对于根元素,即html元素,如果html的字体大小是14px,那么在任何地方的2rem都是28px。

2. 为什么要用rem?

可能大多数人就回答道这里就完了,那么有没有思考过为什么会有rem的存在,难道仅仅只是为了是全文都有一个统一的相对元素吗。

当然不可能这么简单,rem的出现及使用多用于移动端开发中,我们知道,移动端的设备宽度是不定的,如果我们使用固定的大小,那么在不同大小的设备上就会出现布局错乱、留白、残缺等现象的出现。

举个例子,假设我们拿到的设计图宽度为750px,实际的设备宽度也是750px,这种情况真是好,实际与设计图大小一样,我们只需要把每个元素的大小全部按照设计图的大小开发就可以了。但是如果实际设备宽度只有375px呢,缩小了一般,这是如果我们还是按照原来的大小进行开发,在设备上必然是无法完全显示的。这是我们就需要将开发的元素实际大小都要缩小为设计图的一半,但是缩小后的只能在375px的设备上正常显示,如果换做其他设备,布局又会改变。

3. 如何解决

这时就可以用rem来解决,我们假设在设计图中1rem = 100px,假设有个元素在设计图中的大小为50px,我们就可以写成 0.5rem,如果是80px,可以写成0.8rem。现在我们把开发后的内容放到实际设备中,设备宽度正好为750的话,那么1rem还是等于100px,如果设备为375px,我们只需要把1rem设置为50px,即根元素的字体大小为50px;如果设备大小为400px,那么1rem就应该为 (400/750)*100 = 53.3px。

4.动态计算

因为设备的大小我们是无法预知的,所以1rem的大小在不同设备上也就不同,如果我们在加载时知道了设备的宽度,我们就可以根据这个宽度来动态的计算出在该设备上1rem究竟应该是多少,然后设置到html元素上。假设设计图宽度为designWidth,实际设备宽度为windowWidth,那么可以计算出实际的1rem = (designWidth/windowWidth)*100。这里的100为我们在设计图中设置的1rem的大小,也叫基准值。

5. 为什么选100px作为基准值

上面讲到我们设置的基准值为100px,当然也是可以设置50、14等来作为基准值,那我们为什么要选100作为基准值呢?

主要还是 为了方便计算,20px换算后为0.2rem,16px换算后为0.16rem。如果基准值为14的话,20px = 20/14 = 1.43rem,很明显在计算上要麻烦很多。既然这样,有人问了,我如果选1px作为基准值岂不是更方便,14px就为14rem,20px就为20px。有个问题不要忽略了,浏览器的最小字体大小为12px,所以设根元素的字体大小为1px是不可以的,只能大于12px,大于12的就100计算最为方便。

我的网站:http://www.dzyong.top/ ,觉得还不错的话就关注我吧,不错过我的每一篇推送,微信搜索:【前端筱园】

6. 实际案例

来看一个我们都熟悉的应用《淘宝》,淘宝的首页就是一个嵌入网页,网址:https://main.m.taobao.com/。它就是使用的rem,打开控制台找到根元素html,当我改变页面宽度时,可以看到html元素的宽度也在改变。
 

你真的理解rem吗?面试官再问你就这样回答_html

当我尝试改变窗口使根元素font-size大小为100px时,看到此时窗口的大小为375px,375px也真是设计师常用的一个尺寸,此时的font-size为100,说明淘宝的基准值就是我们说的100,还可以知道当时设计图的宽度为375px。

7. 代码实现动态改变根元素大小

计算代码如下,当页面大小改变后需要重新计算:

$(function(){
  function setRem(){
    var windowWidth = $(window).width();
    console.log(windowWidth);
    var rem = parseInt(windowWidth/750*100)+'px';
    $('html').css('font-size',rem);
    console.log(rem)
  }
  setRem();
  var timer;
  $(window).on('resize',function(){
    timer=setTimeout(function(){
      clearTimeout(timer);
      setRem();
    },50)
  })
})