乐趣区

关于rem:Rem布局的原理解析

什么是 Rem
rem 和 em 很容易混同,其实两个都是 css 的单位,并且也都是绝对单位,现有的 em,css3 才引入的 rem,在介绍 rem 之前,咱们先来理解下 em。

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

我在面试时常常问会一道和 em 无关的题,来看一下面试者对 css 细节的理解水平,如下,问 s1、s2、s5、s6 的 font-size 和 line-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;}
.s1 {font-size: 2em; line-height: 2em;}

.p2 {font-size: 16px; line-height: 2;}
.s5 {font-size: 2em;}
.s5 {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/640100 = 15.625
p {width: 15.625rem}

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

UE 图宽度 UE 图中元素宽度 640px100px480px75px320px50px
上面的表格是通过咱们的元素在不同屏幕宽度下的计算值

页面宽度 html 字体大小 p 元素宽度 640px640/100 = 6.4px15.6256.4=100px480px480/100=4.8px15.6254.8=75px320px320/100=3.2px15.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 安卓 rem4.1+2.1+vw6.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 不是银弹,这个世上也没有银弹,每个计划都有其长处,也有其毛病,学会做出抉择和斗争

退出移动版