Fork me on GitHub

移动web开发适配方案之Rem

移动端为什么要做适配

移动端相对PC端来说大部分浏览器内核都是基于Webkit的,所以大部分都支持CSS3的最新语法。但是由于手机的屏幕尺寸和分辨率都不太一样(尤其是安卓),所以不得不对不同分辨率的手机做适配来达到近似的展示效果。

一般来说,UI只会给我们提供一份设计图,目前比较多的是参考手机淘宝的方案给一份750px宽的设计稿,而我们前端要做的就是在不同分辨率的手机上以同样的效果展示这份设计稿。

在讲适配方案之前,有几个基本的移动端开始相关的知识点得了解一下

  • rem单位: 说到rem这个单位就不得不提一下在它之前出现的一个类似单位em,em时相对于父级font-size的相对单位,而rem是相对于根节点html的相对单位,也就是说,当html的font-size为12px时,某一个元素的font-size设为1rem也就是等同于12px了。正因为rem单位的这一特性,从而让它可以成为移动端适配的一个关键单位。
  • vw单位:相对于视窗的宽度,视窗宽度是100vw,与整个单位类似的是wh,就是视窗高度,视窗高度时100vh。更详细的特性可以参考视区相关单位vw, vh..简介以及可实际应用场景
  • 物理像素: 也可以说是设备无关像素,例如iPhone6的分辨率(750x1334)指的是物理像素
  • 逻辑像素: 是浏览器使用的抽象单位,状态是可变的,例如在PC浏览器调试面板上我们可以看到iPhone6的物理像素为(375x667)
  • 物理像素与逻辑像素的关系就是设备像素缩放比dpr

适配思路

1、使用CSS的@media媒体查询设置在不同屏幕尺寸下现实不同的效果,类似于这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@media only screen and (min-width: 375px) {
.logo {
width : 62.5px;
}
}

@media only screen and (min-width: 360px) {
.logo {
width : 60px;
}
}

@media only screen and (min-width: 320px) {
.logo {
width : 53.3333px;
}
}

首先,这样只照顾了固定分辨率的机型,肯定是不够的,而且,如果针对页面上的每一个元素写这么多套适配也不现实,媒体查询还是比较适合PC端不同分辨率屏幕之间的适配。

2、使用css的单位rem,类似于这样:

1
2
3
4
5
6
7
8
9
10
11
@media only screen and (min-width: 375px) {
html {
font-size : 62.5px;
}
}

@media only screen and (min-width: 360px) {
html {
font-size : 60px;
}
}

当然,在实际开发中不可能真的这样去写,既然上面已经提到了rem这一单位的特性,那么我们要做的就是根据不同分辨率的设备动态地改变html的font-size就好,也就是1rem代表的大小。比较常见的有两种方案:

  • 通过js动态获取屏幕的宽度,从而计算出html的font-size,还是拿日常开发常见的750px的设计稿为例:
    1
    2
    3
    4
    5
    6
    7
    8
    let htmlWidth = document.documentElement.clientWidth || document.body.clientWidth;
    let htmlDOM = document.getElementsByTagName('html')[0];
    htmlDOM.style.fontSize = htmlWidth / 7.5 + 'px';

    window.addEventListener('resize', (e) => {
    let htmlWidth = document.documentElement.clientWidth || document.body.clientWidth;
    htmlDOM.style.fontSize = htmlWidth / 7.5 + 'px';
    })

这样一来,在375px宽的设备下,html的font-size就是50px,为什么要除以7.5呢,因为这样设计稿上的数值与需要得到的rem值正好是100倍的关系,这样便于换算,当然,引入了scss等预处理工具之后,取多少都不重要了,反正用一个处理函数统一转化一下就可以了,当html的font-size是37.5的时候:

1
2
3
4
@function px2rem ($px) {
$rem: 75;
@return ($px / $rem) + rem;
}

  • 另一种方案同样是通过vw这一单位实现rem适配

    • 上面那种方案说白了就是通过JS动态改变html的font-size的大小,而现在有这么一种单位本身的大小就会随着屏幕的变化而变化,那岂不是省去了JS操作Html字体大小的代码!
    • 我最开始有点担心的是兼容性,不过从caniuse上查的的兼容性上来看兼容性还是比较高的,安卓版本大于4.0的浏览器都是兼容的的。尤其对于在微信上使用的H5页面是完全不用担心兼容性问题的
    • 具体实现如下:

      1
      2
      3
      4
      5
      6
        /*
      当在Ip6下时,100vw代表375px,而视觉稿一般是750px,为了方便算,当html上的1rem代表50px时,
      视觉稿上的像素跟rem就存在了100倍的转化关闭,而此时1vw代表是3.75px,所以html上的font-siez为50/3.75,
      约等于13.33333vw,这样即使不用scss也是比较利于换算的
      */
      html {background-color: #eee; font-size: 13.33333vw;}

      设为上面这样一个数值同样是为了计算方便,当然不是必须的,在这样一个数值下,相对应的元素除以100就可以了,写成scss方法如下

      1
      2
      3
      4
      @function px ($px) {
      @return ($px / 100) + rem;
      }
      .demo2 {width: px(200); height: px(200); background-color: #ddd;}

      我看了一下网易新闻的h5页面目前就是使用的这种方案

    总结

    最开始想写这篇文章是因为之前只知道通过JS动态调节html的font-size这么一种适配方案,刚好前段时间接触到了公司的一个移动端项目,我只是单独开发几个页面,但我发现是用的vw单位实现的rem方案,刚开始还觉得蛮新奇的,其实后来查资料仔细一想,跟JS那种方案本质上并没有什么区别,都是以屏幕宽度作为底,动态地调节了html的font-size,也就是1rem的大小。

    为了写这篇文章又回看了慕课网上这个视频:移动web开发适配秘籍Rem,真的挺感谢这些大牛无私分享的。就像他所说的,移动web开发适配的方案有许多,然而最好的方案一定要掌握。Rem适配方案是我目前所看到的的使用的最多的,多多了解这种方法背后的原理和熟练掌握这种方法还是挺重要的,再次感谢这些大牛的精彩分享,希望我的总结在提升自己的同时也能帮到别人!

参考文章: