移动端适配

527 阅读5分钟

我正在参加「掘金·启航计划」

移动端适配

rem

rem 指的是根元素的字体大小

本质

移动端设备的宽高各式各样,有的宽是 375 px,有的是 400px,有的是 500px,在这种情况下,如果页面元素宽高还是写死的话就会导致在不同的手机上显式的效果不一致,这很好理解,同样的 50px 在 375px 和 500px 的屏幕上肯定是不一样的,375 显大,500 显小,所以如何解决这个问题呢?既然绝对单位 px 不行,那我们只要写一个相对单位,即大的屏幕就让该单位变大,小的屏幕就让该单位变小不就可以解决这种问题了吗,这样即使不同的屏幕大小,所显示出来的效果也是大致一致的,没错,rem 就是这一问题的解决方案,它是一个相对单位。

在定义长宽时使用 rem 作为单位,在不同的屏幕上就会显示不同的大小,使得不同屏幕的显示效果尽可能达到一致,举个简单的例子,相同的 rem 在 300px 的屏幕上就会显示为 30px,在 400px 的屏幕上就会显示为 40px。

那么该如何实现 rem 的适配呢,通常我们会这么写

let domEl = document.documentElement
let clientWidth = document.documentElement.clientWidth
let designWidth = 750 // 这个是设计稿的宽度,并不是固定的,不是重点
domEl.style.fontSize = clientWidth / designWidth + 'px'; // domEl.style.fontSize 就是 1rem 的大小

上面这段代码里最重要的是 clientWidth,注意后面的 designWidth 是多少其实并不重要。怎么理解这句话呢,还记得我们为什么要使用 rem 布局吗?我们想要在不同大小的屏幕上通过一个相对单位使得元素在不同屏幕上显示效果一致,所以我们要让 rem 与 clientWidth 关联起来,这样不同大小屏幕所对应的 rem 也会对应不同的 px,达到我们想要的效果。

在上面我说了 designWidth 是多少并不重要,肯定有的同学会想:“你就扯吧,说它不重要,我在好多 rem 的文章里都看到 designWidth 是写成 750 的,它怎么就不重要了?”我自己之前也一直是这么认为的,要想知道它到底重不重要,别急,我们先来理解一下它的作用是什么,它到底为什么要写成 750。想要知道这个问题的答案,我们首先需要了解两个概念,虚拟像素和物理像素。

想要具体了解这两个东西请看底下的参考文章,我在这里简单的说一下方便大家理解,我们平常所看到的设计稿上面给的宽度往往是 750 px,这就是为什么 designWidth 写成 750 的原因,而这里的 px 和我们平常写 css 里的 px 是不一样的,设计稿的 px 指的是物理像素,css 里的 px 是虚拟像素,之所以要搞得这么花里胡哨是因为手机屏幕为了达到更清晰的显示效果,往往会用多个物理像素去渲染一个虚拟像素,举个例子,比如二倍屏,即 1 个虚拟像素用 2 × 2 个物理像素显示,若是三倍屏,则 1 个虚拟像素用 3 × 3 个物理像素显示,所以二倍屏的手机比如 iPhone6 的物理分辨率为 750 × 1334,实际对应的逻辑(虚拟)分辨率就为 375 × 667,三倍屏手机同理。

好,了解了这些前置知识,让我们来想一个问题,设计稿上的宽高都是按照 px(物理像素)给的,一般来说设计稿都是按照 iPhone6,7,8 的物理分辨率给,即 750 × 1334。假如这个 designWidth 就写成 750,因为我们平时写的代码用到的都是虚拟像素,比如 clientWidth 获取到的就是屏幕的逻辑宽度 375px(这里的 px 是虚拟像素,不要混淆),那么 1 rem 是不是就等于 clientWidth / designWidth = 375px / 750 = 0.5px(虚拟像素),也就是说 100 px 的宽度为了做到适配我们是不是要写成 100 rem,这样在 375 的屏幕会显示为 50px,在 750 的屏幕上会显示为 100px,达到适配的目的,但这个时候问题也就来了,难道每次写我们都需要自己去转换为 rem 吗?这确实有点麻烦,有没有简单的方法,比如设计稿写 100px,我就写 100px 而不用去想着转换也可以达到适配呢,有的,我们继续往下看。

postcss-pxtorem

postcss-pxtoremPostCSS的插件,用于将像素单位转换成 rem 单位

首先我们需要进行安装 npm install postcss-pxtorem --save-dev

安装完成后,我们可以在 vue.config.js 中进行配置,这个插件最重要的是知道以下两点

  1. rootValue (Number)
  • 根元素的值,即1rem的值
  • 用于设计稿元素尺寸/rootValue
  • 比如 rootValue = 100 时,在css中width: 750px; 最终会换算成width: 7.5rem;
// vue.config.js
module.exports = {
  //...其他配置
  css: {
    loaderOptions: {
      postcss: {
        plugins: [
          require('postcss-pxtorem')({
            rootValue: 100,
            minPixelValue: 2,
            propList: ['*'],
          })
        ]
      }
    }
  },
}
  1. 新建rem.js文件,于main.js中引用
const baseSize = 100; // 这个是设计稿中1rem的大小,对应的就是rootValue。
function setRem() {
    // 设计稿的宽度
    const deviceWidth = 750;
    // 实际设备页面宽度和设计稿的比值
    const scale = document.documentElement.clientWidth / deviceWidth;
    // 计算实际的rem值并赋予给html的font-size
    // 假如说实际设备宽度为375px,那么 1rem = 50px
    document.documentElement.style.fontSize = (baseSize * scale) + 'px';
}
setRem();
window.addEventListener('resize', () => {
    setRem();
});

知道了以上两点我来举个例子,比如说设计稿是 750px,一个button的高度给了 100px,然后你在 css 中也写的是 100px,该插件会将 100px 相对于 rootValue 进行转换得到 1rem,然后又知道在实际设备 375px 的屏幕上 1rem = 50px,所以显示为50px,完成了不同大小移动端设备的适配

以上就是我查阅资料对移动端适配的总结,希望能够对你有所帮助。

文章参考

rem布局解析

移动端开发 - 物理像素、逻辑像素、DPR 等概念梳理

Vue中rem与postcss-pxtorem的应用