什么是Rem

rem和em很容易混淆,其实两个都是css的单位,并且也都是相对单位,现有的em,css3才引入的rem,在介绍rem之前,我们先来了解下em

em作为font-size的单位时,其代表父元素的字体大小,em作为其他属性单位时,代表自身字体大小——MDN

我在面试时经常问会一道和em有关的题,来看一下面试者对css细节的了解程度,如下,问s1、s2、s5、s6的font-sizeline-height分别是多少px,先来想一想,结尾处有答案和解释

<div class="p1"><div class="s1">1</div><div class="s2">1</div>
</div>
<div class="p2"><div class="s5">1</div><div class="s6">1</div>
</div>
.p1 {font-size: 16px; line-height: 32px;}
.s1 {font-size: 2em;}
.s2 {font-size: 2em; line-height: 2em;}.p2 {font-size: 16px; line-height: 2;}
.s5 {font-size: 2em;}
.s6 {font-size: 2em; line-height: 2em;}

em可以让我们的页面更灵活,更健壮,比起到处写死的px值,em似乎更有张力,改动父元素的字体大小,子元素会等比例变化,这一变化似乎预示了无限可能

有些人提出用em来做弹性布局页面,但其复杂的计算让人诟病,甚至有人专门做了个px和em的计算器,不同节点像素值对应的em值,o(╯□╰)o

em做弹性布局的缺点还在于牵一发而动全身,一旦某个节点的字体大小发生变化,那么其后代元素都得重新计算,X﹏X

rem作用于非根元素时,相对于根元素字体大小;rem作用于根元素字体大小时,相对于其出初始字体大小——MDN

rem取值分为两种情况,设置在根元素时和非根元素时,举个例子

/* 作用于根元素,相对于原始大小(16px),所以html的font-size为32px*/
html {font-size: 2rem}/* 作用于非根元素,相对于根元素字体大小,所以为64px */
p {font-size: 2rem}

rem有rem的优点,em有em的优点,尺有所短,寸有所长,我一直不觉得技术没有什么对错,只有适合不适合,有对错的是使用技术的人,杰出与优秀的区别就在于能否选择合适的技术,并让其发挥优势

我一直觉得em就是为字体和行高而生的,有些时候子元素字体就应该相对于父元素,元素行高就应该相对于字体大小;而rem的有点在于统一的参考系

Rem布局原理

rem布局的本质是什么?这是我问过很多人的一个问题,但得到的回答都差强人意。

其实rem布局的本质是等比缩放,一般是基于宽度,试想一下如果UE图能够等比缩放,那该多么美好啊

假设我们将屏幕宽度平均分成100份,每一份的宽度用x表示,x = 屏幕宽度 / 100,如果将x作为单位,x前面的数值就代表屏幕宽度的百分比

p {width: 50x} /* 屏幕宽度的50% */

如果想要页面元素随着屏幕宽度等比变化,我们需要上面的x单位,不幸的是css中并没有这样的单位,幸运的是在css中有rem,通过rem这个桥梁,可以实现神奇的x

通过上面对rem的介绍,可以发现,如果子元素设置rem单位的属性,通过更改html元素的字体大小,就可以让子元素实际大小发生变化

html {font-size: 16px}
p {width: 2rem} /* 32px*/html {font-size: 32px}
p {width: 2rem} /*64px*/

如果让html元素字体的大小,恒等于屏幕宽度的1/100,那1rem和1x就等价了

html {fons-size: width / 100}
p {width: 50rem} /* 50rem = 50x = 屏幕宽度的50% */

如何让html字体大小一直等于屏幕宽度的百分之一呢? 可以通过js来设置,一般需要在页面dom ready、resize和屏幕旋转中设置

document.documentElement.style.fontSize = document.documentElement.clientWidth / 100 + 'px';

那么如何把UE图中的获取的像素单位的值,转换为已rem为单位的值呢?公式是元素宽度 / UE图宽度 * 100,让我们举个例子,假设UE图尺寸是640px,UE图中的一个元素宽度是100px,根据公式100/640*100 = 15.625

p {width: 15.625rem}

下面来验证下上面的计算是否正确,下面的表格是UE图等比缩放下,元素的宽度

UE图宽度 UE图中元素宽度
640px 100px
480px 75px
320px 50px

下面的表格是通过我们的元素在不同屏幕宽度下的计算值

页面宽度 html字体大小 p元素宽度
640px 640/100 = 6.4px 15.625*6.4=100px
480px 480/100=4.8px 15.625*4.8=75px
320px 320/100=3.2px 15.625*3.2=50px

可以发现,UE图宽度和屏幕宽度相同时,两边得出的元素宽度是一致的

上面的计算过程有些繁琐,可以通过预处理的function来简化过程,下面是sass的例子,less类似

$ue-width: 640; /* ue图的宽度 */@function px2rem($px) {@return #{$px/$ue-width*100}rem;
}p {width: px2rem(100);
}

上面的代码编译完的结果如下

p {width: 15.625rem}

其实有了postcss后,这个过程应该放到postcss中,源代码如下

p {width: 100px2rem}

postcss会对px2rem这个单位进行处理,处理后的结果如下,感兴趣的话来写一个px2rem的postcss插件吧

p {width: 15.625rem}

比Rem更好的方案

上面提到想让页面元素随着页面宽度变化,需要一个新的单位x,x等于屏幕宽度的百分之一,css3带来了rem的同时,也带来了vw和vh

vw —— 视口宽度的 1/100;vh —— 视口高度的 1/100 —— MDN

聪明的你也许一经发现,这不就是单位x吗,没错根据定义可以发现1vw=1x,有了vw我们完全可以绕过rem这个中介了,下面两种方案是等价的,可以看到vw比rem更简单,毕竟rem是为了实现vw么

/* rem方案 */
html {fons-size: width / 100}
p {width: 15.625rem}/* vw方案 */
p {width: 15.625vw}

vw还可以和rem方案结合,这样计算html字体大小就不需要用js了

html {fons-size: 1vw} /* 1vw = width / 100 */
p {width: 15.625rem}

虽然vw各种优点,但是vw也有缺点,首先vw的兼容性不如rem好,使用之前要看下

兼容性 Ios 安卓
rem 4.1+ 2.1+
vw 6.1+ 4.4+

另外,在使用弹性布局时,一般会限制最大宽度,比如在pc端查看我们的页面,此时vw就无法力不从心了,因为除了width有max-width,其他单位都没有,而rem可以通过控制html根元素的font-size最大值,而轻松解决这个问题

Rem不是银弹

rem是弹性布局的一种实现方式,弹性布局可以算作响应式布局的一种,但响应式布局不是弹性布局,弹性布局强调等比缩放,100%还原;响应式布局强调不同屏幕要有不同的显示,比如媒体查询

用户选择大屏幕有两个几个出发点,有些人想要更大的字体,更大的图片,比如老花眼的我;有些人想要更多的内容,并不想要更大的图标;有些人想要个镜子。。。——颜海镜

我认为一般内容型的网站,都不太适合使用rem,因为大屏用户可以自己选择是要更大字体,还是要更多内容,一旦使用了rem,就剥夺了用户的自由,比如百度知道,百度经验都没有使用rem布局;一些偏向app类的,图标类的,图片类的,比如淘宝,活动页面,比较适合使用rem,因为调大字体时并不能调大图标的大小

rem可以做到100%的还原度,但同事rem的制作成本也更大,同时使用rem还有一些问题,下面我们一一列举下:

首先是字体的问题,字体大小并不能使用rem,字体的大小和字体宽度,并不成线性关系,这个函数我还没算出来,所以字体大小不能使用rem;由于设置了根元素字体的大小,会影响所有没有设置字体大小的元素,因为字体大小是会继承的,难道要每个元素都显示设置字体大小???

我们可以在body上做字体修正,比如把body字体大小设置为16px,但如果用户自己设置了更大的字体,此时用户的设置将失效,比如合理的方式是,将其设置为用户的默认字体大小

html {fons-size: width / 100}
body {font-size: 16px}

那字体的大小如何实现响应式呢?可以通过修改body字体的大小来实现,同时所有设置字体大小的地方都是用em单位,对就是em,因为只有em才能实现,同步变化,我早就说过em就是为字体而生的

当然不同屏幕字体大小相同也是非常合理和不错的效果,需要你自己做决策

@media screen and (min-width: 320px) {body {font-size: 16px}
}
@media screen and (min-width: 481px) and (max-width:640px) {body {font-size: 18px}
}
@media screen and (min-width: 641px) {body {font-size: 20px}
}p {font-size: 1.2em}
p a {font-size: 1.2em}

第二,如果用户在PC端浏览,页面过宽怎么办?一般我们都会设置一个最大宽度,大于这个宽度的话页面居中,两边留白

var clientWidth = document.documentElement.clientWidth;
clientWidth = clientWidth < 780 ? clientWidth : 780;
document.documentElement.style.fontSize = clientWidth / 100 + 'px';

设置body的宽度为100rem,并水平居中

body {margin: auto;width: 100rem
}

第三,如果用户禁用了js怎么破?其实这种用户真不多了,要不放弃吧。。。

首先可以添加noscript标签提示用户

<noscript>开启JavaScript,获得更好的体验</noscript>

给html添加一个320时的默认字体大小,保证页面可以显示

html {fons-size: 3.2px}

如果你想要更好的体验,不如添加媒体查询吧

@media screen and (min-width: 320px) {html {font-size: 3.2px}
}
@media screen and (min-width: 481px) and (max-width:640px) {html {font-size: 4.8px}
}
@media screen and (min-width: 641px) {html {font-size: 6.4px}
}

rem不是银弹,这个世上也没有银弹,每个方案都有其优点,也有其缺点,学会做出选择和妥协

rem仅能做到内容的缩放,但是对于非矢量资源,比如图片放大时的失真,并无法解决,这个以后有缘再讨论。

Rem布局方案

通过上面可以得出实现缩放布局,共有四种方案,下面做一个对比

缩放布局 用户体验 兼容性 依赖js 超大屏幕 修正字体
rem+media-query IOS4.1 AN2.1 ×
rem+js IOS4.1 AN2.1 × ×
rem+vw IOS6.1 AN4.4 ×
vw IOS6.1 AN4.4 ×

如果要求兼容性,建议rem+js方案,需要解决的问题如下:

  • 修正body字体大小

  • 浏览器禁用js(可选)
  • 宽度限制,超大屏幕居中(可选)
  • 字体缩放(可选)

如果兼容性满足,建议使用rem+vw方案,需要解决的问题如下:

  • 修正body字体大小
  • 宽度限制,超大屏幕居中(可选)
  • 字体缩放(可选)

但是上面的方案还有个问题,就是分成100份的话,假设屏幕宽度320,此时html大小是3.2px,但浏览器支持最小字体大小是12px,怎么办?那就分成10份呗,只要把上面的100都换成10就好了

下面给一个rem+js方案的完整例子,css的计算没有使用预处理器,这个很简单

html代码如下

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"><title>rem布局——rem+js</title>
</head>
<body><noscript>开启JavaScript,获得更好的体验</noscript><div class="p1">宽度为屏幕宽度的50%,字体大小1.2em<div class="s1">字体大小1.2.em</div></div><div class="p2">宽度为屏幕宽度的40%,字体大小默认<div class="s2">字体大小1.2em</div></div>
</body>
</html>

css代码如下

html {font-size: 32px; /* 320/10 */
}
body {font-size: 16px; /* 修正字体大小 *//* 防止页面过宽 */margin: auto;padding: 0;width: 10rem;/* 防止页面过宽 */outline: 1px dashed green;
}/* js被禁止的回退方案 */
@media screen and (min-width: 320px) {html {font-size: 32px}body {font-size: 16px;}
}
@media screen and (min-width: 481px) and (max-width:640px) {html {font-size: 48px}body {font-size: 18px;}
}
@media screen and (min-width: 641px) {html {font-size: 64px}body {font-size: 20px;}
}noscript {display: block;border: 1px solid #d6e9c6;padding: 3px 5px;background: #dff0d8;color: #3c763d;
}
/* js被禁止的回退方案 */.p1, .p2 {border: 1px solid red;margin: 10px 0;
}.p1 {width: 5rem;height: 5rem;font-size: 1.2em; /* 字体使用em */
}.s1 {font-size: 1.2em; /* 字体使用em */
}.p2 {width: 4rem;height: 4rem;
}
.s2 {font-size: 1.2em /* 字体使用em */
}

js代码如下

var documentElement = document.documentElement;function callback() {var clientWidth = documentElement.clientWidth;// 屏幕宽度大于780,不在放大clientWidth = clientWidth < 780 ? clientWidth : 780;documentElement.style.fontSize = clientWidth / 10 + 'px';
}document.addEventListener('DOMContentLoaded', callback);
window.addEventListener('orientationchange' in window ? 'orientationchange' : 'resize', callback);

完整的例子如下

  • rem+js的例子
  • rem+vw的例子
  • vw的例子

页面效果如下

总结

如果对本文有什么疑问,欢迎留言讨论;如果觉得本文对你有帮助,那就赶紧赞赏吧,^_^

最后填一下开头埋的雷吧,demo在这里,代码如下

<div class="p1"><div class="s1">1</div><div class="s2">1</div>
</div>
<div class="p2"><div class="s5">1</div><div class="s6">1</div>
</div>
.p1 {font-size: 16px; line-height: 32px;}
.s1 {font-size: 2em;}
.s2 {font-size: 2em; line-height: 2em;}.p2 {font-size: 16px; line-height: 2;}
.s5 {font-size: 2em;}
.s6 {font-size: 2em; line-height: 2em;}

先来看第一组的答案

p1:font-size: 16px; line-height: 32px
s1:font-size: 32px; line-height: 32px
s2:font-size: 32px; line-height: 64px

和你的答案一样吗?下面来解释下

  • p1 无需解释
  • s1 em作为字体单位,相对于父元素字体大小;line-height继承父元素计算值
  • s2 em作为行高单位时,相对于自身字体大小

再来看看第二组的答案

p2:font-size: 16px; line-height: 32px
s5:font-size: 32px; line-height: 64px
s6:font-size: 32px; line-height: 64px

意不意外?惊不惊喜?下面来解释下

  • p2 line-height: 2自身字体大小的两倍
  • s5 数字无单位行高,继承原始值,s5的line-height继承的2,自身字体大小的两倍
  • s6 无需解释

Rem布局的原理解析相关推荐

  1. 移动端布局(三) rem布局及原理

    什么是rem 首先来了解一下什么是em: 作为font-size的单位时,其代表父元素的字体大小,em作为其他属性单位时,代表自身字体大小. s1.s2.s5.s6的font-size和line-he ...

  2. html中简述rem布局原理,rem布局原理解析

    移动端的屏幕大小各异,尤其是安卓机,千奇百怪,各种尺寸的机型都有,而且有1倍屏,2倍屏,3倍屏之分,作为精益求精的前端,我们希望找到一种完美适配各种机型的方案.rem是现在主流的移动端自适应布局方案, ...

  3. 移动端rem布局基本介绍及原理

    rem布局 em和rem的认识 在布局中,除了px之外,还有两个常见的单位,em和rem em: 相对于当前元素的字体大小→ 1em = 当前标签的font-size rem: 相对于根元素(html ...

  4. 场景化分析rem布局原理

    移动端rem布局 前端很流行的布局方式rem布局,通过设备之间px像素与rem的转换,达到不同屏幕相同视觉效果的布局方式,在了解rem布局之前需要先明白几个概念,设备像素(物理像素).独立像素.CSS ...

  5. 移动WEB开发四、rem布局

    零.文章目录 文章地址 个人博客-CSDN地址:https://blog.csdn.net/liyou123456789 个人博客-GiteePages:https://bluecusliyou.gi ...

  6. 移动端页面自适应解决方案—rem布局(进阶版)

    之前的一篇<手机端页面自适应解决方案-rem布局>随着时间的推移,该方案已然过时,故为大家介绍一个目前我极力推荐使用的,更加完美的方案--rem布局(进阶版) 该方案使用相当简单,把下面这 ...

  7. LinearLayout测量原理解析:onMeasure(int,int)

    想写这部分内容已经很久了,但是每次写的时候总感觉自己讲的不够清楚,但是感觉这种事情真的不能拖,越拖越解决不了,所以,Let's go!好好理一理LinearLayout的measure的原理,也就是测 ...

  8. php动态引入js文件路径问题,JavaScript_动态加载外部css或js文件,原理解析:第一步:使用dom创 - phpStudy...

    原理解析:第一步:使用dom创建 应用:1.提高代码的复用,减少代码量:2.添加一个javascript控制器和 session可以实现动态改变页面样式:3.由于是页面是从上到下依次加载文件的,并且边 ...

  9. 移动web开发之rem布局(rem基础、媒体查询、 less 基础、rem适配方案)

    移动web开发之rem布局 一.rem基础 rem单位 rem (root em)是一个相对单位,类似于em,em是父元素字体大小. 不同的是rem的基准是相对于html元素的字体大小. 比如,根元素 ...

最新文章

  1. 在 .NET 框架程序中通过DllImport使用 Win32 API
  2. 宁波python学习_python学习第十五天
  3. 看我如何发现Uber合作方网站XXE 0day漏洞并获得9000美元赏金
  4. c语言数组求逆序对,LeetCode 面试题51. 数组中的逆序对
  5. JavaScript中十个一步拷贝数组的方法
  6. Spring注入的基本使用
  7. python脚本编程100例_python100例,python经典例题
  8. 二叉堆时间复杂度 php,二叉堆(Binary Heap)
  9. Tricks(四十七)—— 布尔矩阵(0-1矩阵)取反
  10. 需求与商业模式分析-1-商业模式画布
  11. Vue JSON校验格式化编辑框 -- jsoneditor
  12. Java Swing开发 Label标签 界面中文出现乱码解决方案
  13. Java封装、继承、多态、super杂糅在一起的小练习,公司雇员员工工资问题(Employee),练习扩展:创建一个Employee数组,分别创建不同的Employee对象,并打印某个月的工资
  14. 赫兹的单位换算_频率 时间 单位转换
  15. 网络高清监控摄像头如何安装(图文方法+模拟像机)
  16. gulp-tinypng-nokey [error]: xxx Too many files uploaded at once
  17. 【ZZULIOJ】1000: 从今天开始入坑C语言
  18. (android文档原创翻译)管理Activity的生命周期一
  19. 【报告分享】2020-2021年中国购物中心消费者洞察报告-中国连锁经营协会(附下载)
  20. Linux下MongoDB的入门安装、配置与启动

热门文章

  1. 设计模式之不简单的工厂模式(二)
  2. 虚拟化服务器内存,服务器内存设置虚拟化
  3. HTML中点击div旋转,html – 180度旋转的div只能从一侧点击
  4. 项目权限管理大纲(RBAC+SpringSecurity)
  5. 【端午送福】13000 人正在学习的数据分析实战课,抽奖送送送!
  6. Android小知识-了解下Android系统的显示原理
  7. 《为iPad而设计:打造畅销App》——快速回顾用户界面设计史
  8. Java编程的逻辑 (43) - 剖析TreeMap
  9. nginx 后端获取真实ip
  10. EMC业务连续性和容灾服务