移动端适配 后篇(rem+vm)

涉及到的一些名词, 详细解释可参考 移动端适配前篇--移动端适配 rem

名词解释

【英寸Inch】英寸表示屏幕斜对角线的长度
【像素Pixel】像素是图像的基本采样单位,它不是一个确定的物理量,因为像素点的物理大小是不确定的
【分辨率】分辨率是屏幕像素的数量,一般用屏幕宽度的像素点乘以屏幕高度的像素点。如描述iphone6的分辨率是750*1334.
分辨率又分为【物理分辨率】和【逻辑分辨率】,值得注意的是实际工作中设计师常常给的是物理分辨率,程序中用到的是逻辑分辨率,但是都称为分辨率,容易混淆。
【物理分辨率】是硬件所支持的分辨率,【逻辑分辨率】是软件可以达到的分辨率。
【像素倍率dpr】物理分辨率和逻辑分辨率的商,即常说的几倍屏。

如:iphone6的分辨率写着375*667,指的是逻辑分辨率;750*1334则是它的物理分辨率,dpr=2。

使用rem适配,目前最流行的两种方式:分别是网易和手淘的做法

网易

设备逻辑像素 device-width = 设备物理像素 /(devicePixelRatio * scale)
设备物理像素: iphone6 = 750px
设备逻辑像素: iphone6 = 750/(2 * 1) = 375px
document.documentElement.clientWidth === 设备逻辑像素
body-width(rem为单位) = 设计稿宽度/100 = 640 / 100 = 6.4 rem 【取100,主要为了容易计算】
html font-size(px为单位) = device-width / body-width = 320 / 6.4 = 50 px

【步骤】
(1)视口设置:<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1, minimum-scale=1">
(2)先拿设计稿竖着的横向分辨率除以100得到body元素的宽度:
如果设计稿基于iphone6,横向分辨率为750,body的width为750 / 100 = 7.5rem
如果设计稿基于iphone4/5,横向分辨率为640,body的width为640 / 100 = 6.4rem
(3)布局时,设计图标注的尺寸除以100得到css中的尺寸
设计稿150px的宽度,代码为 150/100 rem
(4)在dom ready以后,通过以下代码设置html的font-size:
document.documentElement.style.fontSize = document.documentElement.clientWidth / 6.4 + 'px';
【html的font-size的值 是根据设备改变而改变的】
(注:6.4是设计稿基于iphone4/5,如果是750的设计稿,应该除以7.5)
(5)font-size可能需要额外的媒介查询,并且font-size不能使用rem【此处的px是指设备逻辑像素】

@media screen and (max-width:321px){
.m-navlist{font-size:15px}
}

@media screen and (min-width:321px) and (max-width:400px){
.m-navlist{font-size:16px}
}

@media screen and (min-width:400px){
.m-navlist{font-size:18px}
}

【注意】最大宽度限制 设备逻辑像素宽度640 =》设备物理像素宽度1280 相当于pc端
var deviceWidth = document.documentElement.clientWidth;
if(deviceWidth > 640) deviceWidth = 640;
document.documentElement.style.fontSize = deviceWidth / 6.4 + 'px'; 【此处6.4,由于网易以iPhone4/5,物理像素为640 * 1136

前提:假如以iPhone6/7/8为设计稿,宽度为150的元素

在 iphone6/7/8中:
由于【dpr = 2】,该元素的逻辑像素 = 150 / 2 = 75 px 
html-fontSize = 375 / 7.5 = 50 px
该元素的 width = 150 / 100 = 1.5 rem 
该元素的逻辑像素 / html-fontSize = 75 / 50 = 1.5


在iPhone4/5中:【逆推】	 
在 iphone4/5中,html-fontSize = 320 / 7.5 = 42.67 px
该元素的 width = 1.5 rem 
该元素的逻辑像素 = html-fontSize * 该元素的 width(rem) = 42.67 * 1.5 = 64 px
由于【dpr = 2】,该元素的物理像素 = 逻辑像素 * dpr = 64 * 2 = 128 (即该元素的宽为128)
该元素的逻辑像素 / html-fontSize = 64 / 42.67 = 1.5

**总结:
64/320 = 75/375 = 0.2 相当于百分比适配,该元素占整屏宽度的20%**

demo:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>移动端适配</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/>
<style>
/* vw + rem */
html{font-size:13.33333333vw}
.box {
width: 1.5rem;
height: 1.5rem;
background-color: #ccc;
font-size: 0.24rem;
}


/* rem 网易*/
.box {
width: 1.5rem;
height: 1.5rem;
background-color: #ccc;
font-size: 14px;
}

/*逻辑像素*/
@media screen and (max-width:321px){
.box{font-size:15px}
}

@media screen and (min-width:321px) and (max-width:400px){
.box{font-size:16px}
}

@media screen and (min-width:400px){
.box{font-size:18px}
}
</style>
<script>
window.onload = function () {
var deviceWidth = document.documentElement.clientWidth;
if(deviceWidth > 640) deviceWidth = 640;
document.documentElement.style.fontSize = deviceWidth / 7.5 + 'px';
}
</script>
</head>
<body>
<div class="box">
oooo
</div>
</body>
</html>

手淘:可使用 lib-flexible

(1)动态设置viewport的scale

var scale = 1 / devicePixelRatio;
document.querySelector('meta[name="viewport"]').setAttribute('content','initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');

(2)动态计算html的font-size

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

(3)布局的时候,各元素的css尺寸 = 设计稿标注尺寸/(设计稿横向分辨率 / 10)
(4)font-size可能需要额外的媒介查询,并且font-size不使用rem,这一点跟网易是一样的。

总结:

设备逻辑像素 device-width = 设备物理像素 /(devicePixelRatio * scale)
由于 scale = 1 / devicePixelRatio,所以【设备逻辑像素 = 设备物理像素】
前提:假如以iPhone6/7/8为设计稿,宽度为150的元素

在 iphone6/7/8中:
设备逻辑像素 = 750 /(`2*0.5`) = 750 px 
由于【dpr = 2】,该元素的逻辑像素 = 150 /(`2*0.5`) = 150 px 
html-fontSize = 750 / 10 = 75 px
该元素的 width(rem) = 150 / html-fontSize = 150 / 75 = 2 rem


在iPhone4/5中:【逆推】	 
在 iphone4/5中,html-fontSize = 640 / 10 = 64 px
该元素的 width = 2 rem 
该元素的逻辑像素 = html-fontSize * 该元素的 width(rem) = 64 * 2 = 128 px


=> 150 / 750 = 128 / 640 = 0.2


var scale = 1 / devicePixelRatio;
document.querySelector('meta[name="viewport"]').setAttribute('content','initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';

demo:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>移动端适配</title>
<!-- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/> -->
<meta name="viewport"/>
<style>
.box {
width: 2rem;
height: 2rem;
background-color: #ccc;
font-size: 14px;
}

/*逻辑像素*/
@media screen and (max-width:321px){
.box{font-size:15px}
}

@media screen and (min-width:321px) and (max-width:400px){
.box{font-size:16px}
}

@media screen and (min-width:400px){
.box{font-size:18px}
}
</style>
<script>
window.onload = function () {
var scale = 1 / devicePixelRatio;
document.querySelector('meta[name="viewport"]').setAttribute('content','initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
// console.log(document.documentElement.clientWidth) // 750 = 750 / (2 * 0.5)
// 设备逻辑像素 device-width = 设备物理像素 /(devicePixelRatio * scale)
document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';

}
</script>
</head>
<body>
<div class="box">
oooo
</div>
</body>
</html>

vw + rem

html{font-size:13.33333333vw}
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">

1vw表示1%的屏幕宽度, 即屏幕宽度被分为100份vw
width:1rem 的div 就是50px* 50px (iphone6为2倍屏,即对应750px设计稿上的100px*100px)
7.5 rem = 100vw = 750px 设计稿 =》1px = 0.1333333vw =》 100px = 13.33333vw => 100px = 1rem
以iPhone6/7/8为设计稿标准, 宽度为 180 px
该元素的宽度(rem)= 180 / 100 = 1.8 rem

最后

布局时各元素的尺寸值都是根据设计稿标注的尺寸计算出来,由于html的font-size是动态调整的,所以能够做到不同分辨率下页面布局呈现等比变化

总结

经过正反推算,发现各种单位适配本质上对应着还是根据手机屏幕尺寸基于百分比进行缩放

参考:
最简单的移动端适配方案(rem+vw)
移动端(手机端)页面自适应解决方案—rem布局
移动前端自适应适配布局解决方案和比较

posted @ 2019-03-28 00:06  adash  阅读(2430)  评论(0编辑  收藏  举报