移动端适配理解和rem适配方案介绍

85 阅读7分钟

移动端适配

1 名词定义

  1. 设备物理像素 (Device Physical Pixels)

    • 定义:设备屏幕上最小的物理显示单元,也就是我们常说的“像素点”。每个像素点由红、绿、蓝子像素组成。

    • 特点:是硬件的固有属性,出厂时固定,无法改变。

    • 例子:iPhone 12 的屏幕有 2532 x 1170 个物理像素点。

  2. 设备像素比 (Device Pixel Ratio, DPR)

    • 定义:一个设备物理像素与设备独立像素(逻辑像素)之间的比例关系。公式为:DPR = 物理像素 / 逻辑像素(在同一方向上)。

    • 作用:描述了屏幕的密度(清晰度)。DPR 越高,屏幕越清晰。

    • 例子:iPhone 12 的 DPR 为 3,意味着在水平方向上,1 个设备独立像素(逻辑像素)由 3 个物理像素来渲染。

  3. 设备独立像素 (Device Independent Pixels, DIPs) / 逻辑像素 (Logical Pixels)

    • 定义:一种由软件定义的像素单位,用于抽象不同物理像素密度的设备,使得应用程序和网页在不同设备上有一致的视觉大小。

    • 特点:与设备物理像素无关,由操作系统管理。在同一个操作系统中,设备独立像素(逻辑像素)的大小是固定的(例如,1 逻辑像素约等于 1/160 英寸)。

    • 例子:iPhone 12 的逻辑分辨率为 390 x 844 逻辑像素。

  4. 逻辑分辨率 (Logical Resolution)

    • 定义:用逻辑像素表示的屏幕分辨率,即屏幕在逻辑像素尺寸上的宽高。

    • 子:iPhone 12 的逻辑分辨率为 390 x 844。

  5. CSS 像素 (CSS Pixels)

    • 定义:在 CSS 和 Web 开发中使用的抽象单位。我们编写 CSS 时使用的 px 单位就是 CSS 像素。

    • 特点:在默认情况下(即未进行移动端适配时),1 个 CSS 像素对应 1 个设备独立像素(逻辑像素)。但是,当用户进行缩放时,CSS 像素会发生变化(例如放大时,1 个 CSS 像素会占用多个设备独立像素)。

    • 与逻辑像素的关系:在理想视口(ideal viewport)下,1 CSS 像素 = 1 设备独立像素(逻辑像素)

  6. 物理分辨率 (Physical Resolution)

    • 定义:用设备物理像素表示的屏幕分辨率,即屏幕在物理像素尺寸上的宽高。

    • 例子:iPhone 12 的物理分辨率为 2532 x 1170 物理像素。

2 关系梳理

设备物理像素和物理分辨率是硬件层面的概念,描述了屏幕实际的像素点数量。

设备独立像素(逻辑像素)和逻辑分辨率是软件层面的概念,由操作系统定义,目的是统一不同密度设备上的尺寸度量。

设备像素比(DPR) 是连接物理像素和逻辑像素的桥梁:物理像素 = 逻辑像素 × DPR。

CSS 像素是 Web 开发中的单位,在默认情况下与逻辑像素等价,但可以通过 viewport 缩放、CSS 变换等操作改变其实际占用的物理像素。

举例说明(以 iPhone 12 为例)

物理分辨率:2532 x 1170(物理像素)

逻辑分辨率:390 x 844(逻辑像素)

DPR:3(因为 1170 / 390 = 3,2532 / 844 ≈ 3)

CSS 像素:在理想视口下,1 CSS 像素 = 1 逻辑像素,所以一个宽度为 390 CSS 像素的元素将刚好充满 iPhone 12 的屏幕宽度。

3 为什么要有这些概念?

主要是为了应对不同屏幕密度的设备。如果直接使用物理像素,那么在高密度屏幕上(如 DPR=3),网页上的元素会显得非常小(因为物理像素点非常密集)。通过引入逻辑像素,操作系统和浏览器可以提供一个统一的尺度,使得同样大小的 CSS 元素在不同密度的屏幕上看起来物理大小相近。

通过引入设备独立像素(逻辑像素)和 DPR:

  • 开发者始终面对统一的逻辑尺寸(如 375px 宽度)
  • 操作系统/浏览器根据 DPR 自动选择用更多物理像素来渲染,实现高清显示

4 移动端适配的意义

移动端适配的核心就是让网页在不同逻辑分辨率(即不同设备宽度)下都能良好显示。我们通过 viewport 设置和 CSS 媒体查询、相对单位(如 rem、vw)等,使页面布局根据逻辑分辨率(CSS 像素)自适应调整。

5 示意图

在这里插入图片描述

6 对移动端适配的理解

6.1 前提条件:

  1. 设计稿尺寸为 375*667,有一个元素,元素的尺寸为 10px*10px

  2. 设置了理想视口,即此时 1 CSS 像素 = 1 设备独立像素

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> 
    

6.2 设备信息

信息iPhoneSEiPhone12
设备物理像素750*13341170*2532
设备独立像素375*667390*844
DPR23
1rem375/10 = 37.5px390/10 = 39px

6.3 适配思路

移动端适配的最终目的就是:保持元素尺寸与视口宽度的相对比例恒定,从而在不同设备上还原一致的视觉关系和布局意图

首先我们不进行适配,直接使用 px,根据设计稿,我们编写下方的样式:

.block {
  width: 10px;
  height: 10px;
  background: red;
}

我们计算一下比例,计算如下:

在iPhoneSE上
10 / 375 = 0.02666666666666667

在iPhone12上
10 / 390 = 0.02564102564102564

可以看到,元素宽度/设备独立像素的比例是不一致的,这样就导致了页面效果的不一致,看起来就会不协调

接下来,我们采用 rem 进行移动端适配,目的是为了让同一个元素在不同设备上的比例(元素宽度/设备独立像素宽度)一致

根据设计稿的尺寸,我们有以下计算:

1rem = 375 / 10 = 37.5px
1px = 0.02666666666rem;

样式如下:

.block {
  width: 0.266666rem;
  height: 0.266666rem;
  background: red;
}

此时我们再计算比例,计算如下:

在iPhoneSE上
0.266666 * 37.5 = 9.99997
9.99997 / 375 = 0.026666586666666665

在iPhone12上
0.266666 * 39 = 10.399974
10.399974 / 390 = 0.026666600000000002

可以看到,使用 rem 进行移动端适配,再换算为 px 之后,不同设备上,元素宽度/设备独立像素宽度的比例是一致的,这样看起来就是协调的

7 移动端 Rem 适配方案代码

这里以 Vue 项目为例,详细介绍如何实现 rem 适配

7.1 安装相关依赖

"postcss": "^8.5.6",
"postcss-pxtorem": "^6.1.0",

7.2 创建 postcss.config.cjs 文件

在项目根目录下,与 src 目录同级,新增 postcss.config.cjs 文件,文件内容如下

module.exports = {
  plugins: {
    "postcss-pxtorem": {
      // 设计稿宽度/10,即750px设计稿 -> 75
      rootValue: 75,

      // 转换所有属性的单位
      propList: ["*"],

      // 忽略带有'no-rem-[className]'类的元素,这些元素内的px不转换
      // 如 <div class="no-rem-block"></div> 则 .no-rem-block 中的样式都不会进行转换
      selectorBlackList: ["no-rem"],
    },
  },
};

7.3 创建并引入 adaptation.js 文件

创建 adaptation.js 文件,并且在 src/main.js 当中引入此文件

/**
 * 移动端适配
 * 以设计稿750px为例,将布局视口分成10份,则1rem=75px
 * 例如在375px宽的设备上,html的font-size就是 375px / 10 = 37.5px
 */

(function (doc, win) {
  const docEl = doc.documentElement;
  const resizeEvt = "orientationchange" in window ? "orientationchange" : "resize";
  const recalc = function () {
    var clientWidth = docEl.clientWidth;
    if (!clientWidth) return;
    docEl.style.fontSize = clientWidth / 10 + "px";
  };
  if (!doc.addEventListener) return;
  win.addEventListener(resizeEvt, recalc, false);
  doc.addEventListener("DOMContentLoaded", recalc, false);
})(document, window);

7.4 使用

/* 在文件当中直接使用px作为单位,postcss会自动编译为rem */
.block {
  width: 100px;
  height: 100px;
  background-color: red;
}

8 移动端图片模糊问题

前提条件:

  • 设置了理想视口,即 1CSS 像素 = 1 设备独立像素

  • 图片的尺寸为 200 * 200

  • HTML 页面当中设置图片的样式

    .bg-img {
      width: 100px;
      height: 100px;
    }
    

在 DPR 为 2 的设备上,这个图片是清晰的,因为 1 CSS 像素 = 1 设备独立像素 = 2 设备物理像素,100px = 200 设备物理像素,相当于把 200 物理像素的图片,放到 200 设备物理像素的区域里面,刚好放得下

假如把上面的这个图片,放在 DPR 为 3 的设备上,此时 1 CSS 像素 = 1 设备独立像素 = 3 设备物理像素,100px = 300 设备物理像素,也就是 200 物理像素的图片,要放在 300 物理像素的区域里面,想要占满区域,就需要放大这个图片,也就导致了图片模糊