H5手机适配主要从两个维度考虑:
- 适配不同屏幕大小,也就是适配不同屏幕下的 CSS 像素
- 适配不同像素密度,也就是适配不同屏幕下 dpr 不一致导致的一些问题
设备独立像素:
这里的 375 * 667 表示的是什么呢,表示的是设备独立像素(DIP),也可以理解为 CSS 像素,也称为逻辑像素:
设备独立像素 = CSS 像素 = 逻辑像素
物理像素:
可以看到,iPhone7 的分辨率是 1334 x 750,这里描述的就是屏幕实际的物理像素。
设备像素 = 物理像素
DPR(Device Pixel Ratio) 设备像素比
简单的计算公式:
DPR = 物理像素 / 设备独立像素
利用上面的iPhone7的数据:
iPhone7’s DPR = iPhone7’s 物理像素宽度 / iPhone7's 设备独立像素宽度 = 2
750 / 375 = 2 或者是 1334 / 667 = 2
解决方案
rem布局
固定viewport的宽度等于设备宽度,宽度自适应
<meta name="viewport" content="width=device-width, initial-scale=1,
maximum-scale=1, user-scalable=no"> (适合响应式网站)
- width:设置layout viewport 的宽度,为一个正整数,或字符串"device-width"
- initial-scale:设置页面的初始缩放值,为一个数字,可以带小数
- minimum-scale:允许用户的最小缩放值,为一个数字
- maximum-scale:允许用户的最小缩放量,为一个数字
- user-scalable:是否允许用户进行缩放,值为 "no" 或 "yes", no 代表不允许,yes 代表允许
只用上面的viewport标签解决移动端自适应,会出现边框1px问题,是因为有的手机的dpr的值是2或者是3。
解决办法就是通过js动态获取手机的DPR,然后通过dpr来动态设置 html 的 font-size,以及设置缩放比例。
手淘方案:lib-flexible (过时了)
具体操作事项:
- 动态改写标签
- 给元素添加data-dpr属性,并且动态改写data-dpr的值
- 给元素添加font-size属性,并且动态改写font-size的值
实现步骤:
- 在中引入flexible.js
<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>
- 动态设置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');
- 动态计算html的font-size
document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';
总结,综合
//获取屏幕宽度、dpr值
var deviceWidth = document.documentElement.clientWidth,
dpr = window.devicePixelRatio || 1;
//设置根字体扩大dpr倍
//由于deviceWidth当页面缩小dpr倍时,本身获取的值就增加dpr倍
//所以这里不需要再乘以dpr了
document.documentElement.style.fontSize = deviceWidth + 'px';
//设置页面缩放dpr倍
document.getElementsByName('viewport')[0]
.setAttribute('content','width=device-width;initial-scale=' + 1/dpr)
- 布局的时候,各元素的css尺寸=设计稿标注尺寸/设计稿横向分辨率/10
@media(写出不同设备媒体查询font-size值)
首先居中布局,定宽。
以iphone6为基准,设计稿是750px。
设计稿宽度/100 = 7.5 把1rem=100px转换,比值是7.5。
也就是 设计稿宽度与rem的比值是7.5。
320px /7.5 = 42.6666(html的font-size值)
@media only screen and (min-width: 320px) {
html {
font-size: 42.6666px
}
}
设计稿元素高宽/100 就得出元素的高宽rem
div {
height: 100px;
width: 100px;
}
/*转rem*/
div {
height: 1rem;
width: 1rem;
}
利用新的css属性 @viewport 进行适配。
@viewport {
width: device-width; /*设置宽度为设备宽度*/
min-width: 640px;
max-width: 800px;
}
@viewport {
user-zoom:fixed; /*zoom 允许用户缩放,fixed 不允许用户缩放*/
zoom: 0.75;
min-zoom: 0.5;
max-zoom: 0.9;
}
@viewport {
orientation: landscape; /*landscape 页面横屏显示,landscape 页面竖屏显示。*/
}
vw,vh进行适配
vw:viewport width(可视窗口宽度)
vh:viewport height(可视窗口高度)
我们可以这样理解 100vw = window.innerwidth, 100vh = window.innerheight 在移动端我们一般都可以认为,100vw就是屏幕宽度。若使用vw布局,就不需要再像rem那样,在js中去动态设置根元素的font-size了,sass中只需要使用这个函数做转换即可
//以iphone7尺寸@2x 750像素宽的视觉稿为例
$baseFontSize: 750;
@function vw($px) {
@return ($px / $baseFontSize) * 100vw;
}
//假设一个div元素在视觉稿中,宽度为120px,字体大小为12px
div {
width: vw(120);
font-size: vw(12);
}
如果设计稿的宽度是按照750像素设计的,前端只需要按照比例还原即可。
//以iphone7尺寸@2x 375像素宽的视觉稿为例
$baseFontSize: 375;
@function vw($px) {
@return ($px / $baseFontSize) * 100vw;
}
//假设一个div元素在视觉稿中,宽度为120px,字体大小为12px
div {
width: vw(240);
font-size: vw(24);
}