移动端适配

1,203 阅读4分钟

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);
}
postcss-px-to-viewport插件