移动端rem精讲
最近有学生问我移动端的自适应布局,整理了一下资料,正好发上来当个博文。
目标
本文介绍rem,主要从原理层出发,介绍如何解决移动端自适应问题和诸如 一像素bug 这样的高清屏幕问题,不做实战演示,文章最后附上代码。文中关于自适应的观点也是个人见解,不喜勿喷,并欢迎留下宝贵意见。
rem
the fontSize of the root element
rem 表示的是页面根元素 html 的字体大小,它是css的属性,你可以直接使用,浏览器中默认字体大小为16px,因此 1rem = 16px
header{
width: 100%;
height: 2rem;
line-height: 2rem;
text-align: center;
font-size: 1rem;
background: #ededed;
}
在浏览器中看下效果:

自适应
自适应应该包含两个方面的内容
- 多终端自适应(安卓,ios,ipad…)
- 横屏自适应(移动端横屏显示)
针对多端自适应,我比较赞同手淘的方案,即在不同大小的屏幕中,对页面元素进行相应的放大或者缩小来实现自适应
- 手淘在iphone6下
![在这里插入图片描述]()
- 手淘在ipad下
![在这里插入图片描述]()
针对横屏显示,我比较倾向于大众点评的方案
- 手淘在iphone6的横屏下
![的横屏]()
- 大众点评在iphone6的竖屏下
![在这里插入图片描述]()
- 大众点评在iphone6的横屏下
![在这里插入图片描述]()
可以看到,手淘在横屏的时候也进行了同比放大,在高度只有375的屏幕中体验不是很好,相比之下大众点评更加清爽一点
但是大众点评这一部分是通过 flex+百分比来实现的,并没有用到rem
rem如何自适应
了解了自适应的需求,如何使用 rem 来达到呢?
其实只需要一段 js 代码,以设计稿 750*1334 为例:
var docEl = document.documentElement,
clientWidth = Math.min(docEl.clientWidth,docEl.clientHeight);// 始终以屏幕的最短边进行计算,保证横屏和竖屏 html 字体大小不变
docEl.style.fontSize = clientWidth / 7.5 + 'px';
假如我们页面头部 header 是 750*40, 字体大小是14px,那么css 代码如下:
header{
width: 100%;
height: 0.8rem;
line-height: 0.8rem;
text-align: center;
font-size: 0.28rem;
background: #ededed;
}
在浏览器里看下效果:
- 竖屏下的效果
![在这里插入图片描述]()
- 横屏下的效果
![在这里插入图片描述]()
- ipad下的效果
![在这里插入图片描述]()
rem在使用的时候,有可能会出现小数点,这是避免不了的,虽然浏览器字体自带点阵,不会出现11,13这样的奇葩尺寸,但是rem在使用上并不因此带来问题,这一点大家不用质疑。
rem 实现自适应的核心代码就是这样简单,但是偶尔也有不灵的时候
高清屏问题
有时候,UI小姐姐会不假辞色的指出你有些地方不行,不是她想要的那样,比如:

虽然,你努力的给她解释这是1px,1px,真的是1px啊,她还是认为太粗了,她可能想要这样的:

虽然在这里我努力的帮你复现,但是由于浏览器并不是真正的高清屏,所以这里只是用来说明问题
这个问题可以这样来解释(下面以横向范围来解释)
想像一下,非高清屏中,375的屏幕里有375个竖向的条纹,每一个条纹都是物理能够达到的显示的最小单元,这是设备上的概念。在下面这个图中,每一个黑条和每一个白条,都可以理解为1个设备像素

而我们css中使用的1px,我们习惯称为逻辑像素,在非高清屏幕中,逻辑像素和设备像素是1:1的关系,所以这时候你画一个1px的边框,就会看到

但是随着高清屏的出现,虽然屏幕宽度还是375,(以iphone6为例),但是设备像素却提高了一倍,变成了750,因为逻辑像素不变,所以逻辑像素和设备像素是1:2的关系,这时候你画一个1px的边框,就会看到和上面一样的图。
这就是为什么UI小姐姐总是跑来找你,作为UI,她们的电脑基本都是mac这种高清屏,加上自己的专业,看设计稿和页面绝对不超过1px的误差,实际上她们想看的是这样的

解决
如何俘虏UI小姐姐芳心呢?直接上代码,莫废话
var docEl = document.documentElement,
px = window.devicePixelRatio, //设备像素比,逻辑像素与设备像素的比值
clientWidth = Math.min(window.screen.width,window.screen.height);
//防止页面缩放带来的影响,将布局的基准值(rem)放大
docEl.style.fontSize = px * clientWidth / 7.5 + 'px';
var meta = document.querySelector('meta[name="viewport"]')
meta.content = meta.content.replace(/1/,1/px) //让页面按设备像素比进行缩放
整理一下代码
一般我们在使用 rem 的时候,会顺便检测屏幕的横屏事件 ‘orientationchange’,为了防止其他人的代码带来的影响,我们将我们的代码放入闭包函数中
(function(doc, win) {
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in win ? 'orientationchange' : 'resize',
px = win.devicePixelRatio,
recalc = function() {
var clientWidth = Math.min(win.screen.width,win.screen.height);
if (!clientWidth) clientWidth = 375;
docEl.style.fontSize = px * clientWidth / 7.5 + 'px';
};
if (doc.addEventListener) {
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
}else{
win['on'+resizeEvt] = recalc
doc['on'+resizeEvt] = recalc
}
var meta = document.querySelector('meta[name="viewport"]')
meta.content = meta.content.replace(/1/g,1/px)
})(document, window);
添加了这样一段代码以后呢, rem的默认值变成了 100px,即 1rem = 100px。
所以在布局的时候,计算也很方便,比如一个元素宽度为300px,那么就是 300/100 = 3rem,对于字体、图片都适用。
最后附上一个自己修改的页面
- ipad下
![在这里插入图片描述]()
- iphone6下
![在这里插入图片描述]()
- iphone6横屏
![在这里插入图片描述]()
- iphone4下
![在这里插入图片描述]()
博文图片有点多,哈哈哈,都是问了说明问题嘛,最后欢迎各位issue或者留言交流。













浙公网安备 33010602011771号