说明:动态REM是移动端专用的自适应方案,需要注意的是,它并不属于响应式布局,不支持在PC上使用该方案。
一、em和rem分别是什么
em和rem都是众多长度单位的中的一种,MDN给出的定义分别是
em是一个相对长度单位,这个单位表示元素的
font-size
的计算值。如果用在font-size
属性本身,它会继承父元素的font-size。
rem代表根元素的
font-size
大小(例如<html>
元素的font-size)。当用在根元素的font-size
上面时 ,它代表了它的初始值。
其他的长度单位还有px(像素)、vw(100vw == 视口宽度)、vh(100vh == 视口高度)等等。
注意:
- chrome默认font-size大小为16px
- chrome默认最小字号为12px(可在设置中更改),这意味着即使设置font-size<12px,打开控制台查看计算出来的font-size依旧是12px
二、移动端的特点
打开开发者工具切换到手机端,我们发现所有手机显示的界面都大同小异,不同的仅仅只是屏幕的大小(宽高)
机型 | 大小 |
---|---|
iPhone 4 | 320 x 480 |
iPhone 5/SE | 320 x 568 |
iPhone 6/7/8 | 375 x 667 |
iPhone 6/7/8 Plus | 414 x 736 |
iPhone X | 375 x 812 |
三、移动端适配方案
方案一:媒体查询
从上面可以看出,光是iPhone这一类手机就有如此多不同的宽高,更别说要适配所有手机了,显然这时候如果使用媒体查询来做适配不可取(那得写n多套样式)
方案二:百分比布局
思路:不用定宽/定高,而是将宽高都设置为百分比,这样不管屏幕大小如何变化,总是保持最初的比例不变
我们可以发现,元素宽度随屏幕宽度变化而变化。但问题是,元素高度没办法与屏幕宽度相关联,比如这里我们想让高度为宽度的一半就无法做到,这样就无法保持原始的比例,如果是图片的话会发生明显的形变。
解决方法:去掉高度,使用padding
将元素撑起来
width: 40%; /* 屏幕宽度的40% */
height 0;
padding-bottom: 20%; /* 屏幕宽度的20% */
这样就用百分比布局做到了实现宽高都自适应的效果
代码:http://js.jirengu.com/peziq/3/edit?html,css,output
当然,为了引入我们的主题,这里还介绍另外一种方法动态REM。
四、动态rem(JS动态地调整rem)
从上面对百分比布局的分析中,我们不难发现,只需要把元素的宽高与屏幕宽度关联起来,就可以实现根据屏幕宽度来进行缩放。
换个思路,我们不使用百分比布局,而是改为固定宽高,让元素宽高两者都有的长度单位和手机屏幕宽度进行关联。
但是无论是px、em还是rem都与手机屏幕的宽度无关(vw与屏幕宽度有关,但这个属性的兼容性太差,这里我们不使用它)
将rem与手机屏幕宽度进行关联
虽然除vw之外的长度单位都与屏幕宽度无关,但是1rem == html的font-size
啊,这样我们只需要让font-size == 屏幕宽度
(用JS做),即1rem == html的font-size == 屏幕宽度
,这样就把长度单位rem与手机屏幕宽度关联起来了。
1 rem == html font-size == viewport width
我们用JS来实现font-size == 屏幕宽度
var pageWidth = window.innerWidth
document.write('<style>html{font-size:'+pageWidth+'px;}</style>')
效果如下:
每次运行JS都会改变rem的值,即JS动态地调整rem,这就是动态rem。
五、对rem进行微调
- 别忘了移动端得加一个meta viewport,加了之后才能正常显示出动态rem的效果
- 不一定非得让rem和屏幕宽度保持1:1
比如,上例中我们可以让1 rem == html font-size == viewport width/10
,
即1 rem == 0.1 width
document.write('<style>html{font-size:'+pageWidth/10+'px;}</style>')
这样我们在写宽高的时候就不用总是写小数了,便于我们取整数
不过需要注意的是,不要把比例设置得太小,否则会出bug。
比如你设置1 rem == 0.01width
,因为在chrome中,默认最小字号为12px,当屏幕宽度为375px时,此时html的font-size为3.75<12,字体大小变化是不会生效的,浏览器依然按照最小的12px来计算。
-
REM 可以与其他单位同时存在
当计算出来的rem值特别小时就别用rem值了,比如上例中,如果此时
我要为元素添加border,通过计算1px/640 == 0.0015 == 0.015 rem,
这样计算出来的rem值太小时,border就会显示不精确。因此,当rem值太小时,可以不使用rem,rem可以与其他长度单位混用。
六、让px自动变为rem
每次都要计算rem值比较麻烦,我们可以通过SCSS将px直接翻译为正确的rem值。
使用步骤如下:
- npm config set registry https://registry.npm.taobao.org/
- touch ~/.bashrc
- echo 'export SASS_BINARY_SITE="https://npm.taobao.org/mirrors/node-sass"' >> ~/.bashrc
- source ~/.bashrc
- npm i -g node-sass
- mkdir ~/Desktop/scss-demo
- cd ~/Desktop/scss-demo
- mkdir scss css
- touch scss/style.scss
在scss文件中添加以下内容
$ cat scss/style.scss @function px($px) {
@return $px/$designWidth*10 + rem;
}
$designWidth: 400px; // 400px是设计稿的宽度,你要根据设计稿的宽度填写
.child {
width: px(160px);
height: px(80px);
margin: px(20px) px(20px);
border: 1px solid red;
float: left;
font-size: 16px;
}
- node-sass -wr scss -o css