这一篇关于移动端适配的文章,简单明了

1,120 阅读3分钟

为什么要做适配?

因为在不同尺寸的设备上,同一个元素,呈现在屏幕上的肉眼大小不同。

效果图对比:

为了对比明显,特选以下两种像素差很大的设备

iphone 12 Pro 下18px的字体效果:

1.png

iPad Air 下同样18px字体的显示效果:

2.png

怎么样?是不是感觉iPad下字体很小?

值的注意的是,有时候,就是希望大屏幕下看到更多的内容,而不是更大的元素。

方案一(rem):

核心原理:rem单位是基于文档根节点(html)字体大小的相对单位,所以我们只需动态设置html的font-size属性,css中用rem替代px,则可以达到适配效果。

  • 1.通过js动态设置根字体大小=(当前设备横向独立像素*100)/设计稿宽度
function setRem() {
  const deviceWidth = document.documentElement.clientWidth;
  // 这里选择以iphone 12 pro的390宽度作为基准值
  // 然后将宽度划分为100份(这个可以自定义),目的是为了模拟vw的效果
  const rem = (deviceWidth * 100) / 390;
  // 动态设置html的font-size
  document.querySelector('html').style.fontSize = rem + 'px';
}
  • 2.编写css样式时,使用rem作为单位,值为设计稿/100:
    设计稿样式:
.box {
  font-size: 18px;  
}

rem写法

.box {
  // 计算方式:设计稿尺寸/100(上面定义的划分为多少份)
  // 18 / 100 = 0.18
  font-size: 0.18rem;
}

这样就完成了rem适配;

效果展示:

iphone 12 Pro(基准尺寸下,px和rem显示效果一致):

3.png

iPad Air:

4.png

可以看到,rem单位始终如一,占据的比例一直都是那么大,而px单位在iPad上看起来似乎变小了。

以上这种方案,有一个经典的库
flexible:github.com/amfe/lib-fl… 需要注意的是,flexible基准宽度是使用时参与计算,而不是在封装中计算,其划分的是10份,而不是100份。

方案二(viewport):

建议使用,目前兼容性也非常不错了

核心原理:使用vh、vw、vmin、vmax等css单位代替px单位,这些单位都是相对于屏幕的尺寸的,所以就不需要用js动态获取文档根节点的宽度了,另外还需要注意meta标签的设置。

vw: 1vw等于1%屏幕宽度 100vw则等于100%屏幕宽度;
vh: 1vh等于1%屏幕高度 100vh则等于100%屏幕高度;
vmin:vw和vh中较小的值
vmax:vw和vh中较大的值

同样还是以iPhone 12 pro 的390为基准宽度

设计稿css:

.box {
  font-size: 18px;
}

viewport:

.box {
  // 设计稿尺寸/基准尺寸*100(因为vw是将屏幕划分为100份)
  // 18 / 390 * 100 = 4.615
  width: 4.615vw;
}

iphone 12 Pro(基准尺寸下,vw和rem显示效果一致):

5.png

iPad Air:

6.png

可以看到,仅仅使用了vw单位,没有任何hack手段,就实现了rem的效果。

以上这种方案也有一个库帮助将px单位转换为viewport单位
postcss-px-to-viewport: github.com/evrone/post…

1px问题

通常设计稿的宽度都是真机的多倍,比如设计稿宽度是750,而真机的像素是375,只有设计稿的1/2;由于css最低只支持1px,所以真机上1px占据的大小看起来视乎就变粗了。

解决方法1:媒体查询,对不同dpr设置transform缩放或0.5px或伪元素高度0.5等操作;

解决方法2:

通过 meta的viewport,调整缩放,进行校正

<script>
    (function (window, document){
      const viewport = document.querySelector("meta[name=viewport]");
      const pixelRatio = window.devicePixelRatio;
      const scale = 1 / pixelRatio;
      viewport.setAttribute('content', `width=device-width,initial-scale=${scale}, maximum-scale=${scale}, minimum-scale=${scale}, user-scalable=no`);
    }(window, document))
</script>

不过这种是对整体进行缩放,所以需要再配合rem适配方案使用。