webApp

191 阅读7分钟

移动端适配

基础知识

  • 设备像素(物理像素)
  • 屏幕尺寸和像素密度(PPI
  • CSS 像素(设备独立像素、逻辑像素)
  • 像素比(DPR

设备像素

设备像素就是指实际存在的像素,也就是设备的分辨率

屏幕尺寸和像素密度

英寸是一个长度单位,1 英寸(inch)等于 2.54 厘米(cm)。其次这里的 6.67 英寸指的是屏幕对角线的长度。

image-20220223135338581 有了屏幕分辨率和屏幕尺寸的信息,我们就可以计算像素密度(*PPI*)。所谓像素密度,就是指 *1* 英寸下的设备像素数量,计算公式如下: image-20220223135410933
// 屏幕斜边的像素
const margin = Math.sqrt(Math.pow(1080,2)+Math.pow(1920,2));
console.log(margin); // 2202.9071700822983
console.log(margin/5.5); // 400.52857637859967 PPI

CSS 像素(设备独立像素、逻辑像素)

image-20220223135513062 image-20220223135530944

CSS 像素和设备像素 1:1 关系,1CSS 像素对应 1 个设备像素,那么现在我修改这个比例,1CSS 像素对应 2 个设备像素即可。

以前在做 PC 端网页开发的时候,由于 CSS 像素始终和设备像素是 1:1 的关系(不考虑缩放),所以给大家了一种错觉,以为 CSS 像素和设备像素就是 1:1 的对应关系,但是实际上 CSS 像素确是一个抽象的单位,具体含有多少个设备像素不是一定的。

像素比(DPR

计算公式为:DPR = 设备像素 / CSS 像素。

举个例子,如果 CSS 像素和设备像素 1:1 关系,那么 DPR 值就为 1。如果 1 个 CSS 像素对应 2 个设备像素,那么 DPR 值就为 2

说简单点,就是一个 CSS 像素要用多少个设备像素来显示。如果 DPR 值为 1,表示用一个设备像素就够了,如果 DPR 值为 2,则表示一个 CSS 像素要用 2 个设备像素来表示。

可以通过 window.devicePixelRatio 获取一个设备的 DPR

viewPort 视口 2024-02-11

视口,英语全称 viewport,指的是设备的屏幕上能用来显示我们的网页的那一块区域,再具体一点,就是浏览器上(也可能是一个 app 中的 webview)用来显示网页的那部分区域。

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        .container{
            width: 375px;
            display: flex;
        }
        .container>div{
            width: 50%;
            height: 50px;
        }
        .container>div:nth-child(1) {
            background-color: red;
        }
        .container>div:nth-child(2) {
            background-color: yellow;
        }
    </style>
</head>

<body>
    <div class="container">
        <div></div>
        <div></div>
    </div>
</body>

在上面的代码中,我们将默认的视口设置取消了,此时就会采用默认的 980px,而我们的 div.contianer 设置的为 375px,效果如下: image.png

可以看到,由于默认的视口宽度为 980px,因此 div.container 并没有占满,只占了一半都还不到。

我们所期待的应该按照设备的 CSS 像素来作为标准。还记得 iPhone 6/7/8CSS 像素是多少么?没错,是 375 x 667,也就是说现在的网页就应该按照 375px 的标准。

视口的分类

  • layout viewport
  • visual viewport
  • ideal viewport

把浏览器默认的 viewport,也就是前面我们所讲的 980px 宽的 viewport 叫做 layout viewport。这个 layout viewport 的宽度可以通过 window.innerWidth 来获取。

然而,layout viewport 的宽度是大于浏览器可视区域的宽度的,所以我们还需要一个 viewport 来代表浏览器可视区域的大小,把这个 viewport 叫做 visual viewportvisual viewport 的宽度可以通过 document.documentElement.clientWidth 来获取。

现在我们已经有两个 viewport 了:layout viewportvisual viewportlayout viewport 是网页实际的宽度,而 visual viewport 是设备的宽度。

在早期 iPhone3GS 时代,由于一个 CSS 像素对应一个设备像素,因此 visual viewport 和设备 CSS 宽度是等价的。

但是从 iPhone4 时代开始,一个 CSS 像素对应 2 个设备像素,设备的 CSS 宽度仍然是 320px,但是物理像素翻了倍。

image-20220225110158908

于是 ideal viewport,也就是第三个 viewport ——移动设备的完美适配 viewport,其实对应的就是设备的 CSS 宽度。

视口相关属性

移动设备默认的 viewportlayout viewport,也就是那个比屏幕要宽的 viewport,但在进行移动设备网站的开发时,我们需要的是 ideal viewport。那么怎么才能得到 ideal viewport 呢?

这就该轮到 meta 标签出场了。

我们在开发移动设备的网站时,最常见的的一个动作就是把下面这个东西复制到我们的 head 标签中:

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

meta 标签的作用是让当前 viewportideal viewport,同时不允许用户手动缩放。

也许允不允许用户缩放不同的网站有不同的要求,但让 viewport 的宽度为 ideal viewport,这个应该是大家都想要的效果,如果你不这样的设定的话,那就会使用那个比屏幕宽的默认 viewport,在不缩放的情况下会出现横向滚动条。

nameviewport 的标 meta 标签最早是由苹果公司在其 safari 浏览器中引入的,目的就是解决移动设备的 viewport 问题。后来安卓以及各大浏览器厂商也都纷纷效仿,引入对 meta viewport 的支持,事实也证明这个东西还是非常有用的。

在苹果的规范中,meta viewport6 个属性(暂且把 content 中的那些东西称为一个个属性和值),如下:

属性名作用
width设置 layout viewport 的宽度,为一个正整数,或字符串"device-width"
height设置 layout viewport 的高度,这个属性对我们并不重要,很少使用
initial-scale设置页面的初始缩放值,为一个数字,可以带小数
minimum-scale允许用户的最小缩放值,为一个数字,可以带小数
maximum-scale允许用户的最大缩放值,为一个数字,可以带小数
user-scalable是否允许用户进行缩放,值为"no"或"yes", no 代表不允许,yes 代表允许

这些属性可以同时使用,也可以单独使用或混合使用,多个属性同时使用时用逗号隔开就行了。

最简单的方式是设置 width=device-width,表示把默认的 layout viewport 的宽度设为移动设备的屏幕宽度。

device-width = 设备分辨率/devicePixelRatio(设备像素比)

下图是这句代码在各大移动端浏览器上的测试结果:

image-20220225110233988

可见通过 width=device-width,所有浏览器都能把当前的 viewport 宽度变成 ideal viewport 的宽度。

例如:

<div class="container">
    <div></div>
    <div></div>
</div>
<script>
    console.log("document.documentElement.clientWidth:",document.documentElement.clientWidth);
    console.log("window.innerWidth:",window.innerWidth);
</script>
* {
    margin: 0;
    padding: 0;
}
.container{
    width: 375px;
    display: flex;
}
.container>div{
    width: 50%;
    height: 50px;
}
.container>div:nth-child(1) {
    background-color: red;
}
.container>div:nth-child(2) {
    background-color: yellow;
}
<meta name="viewport" content="width=device-width">

效果如下:

image-20220225110253028

但要注意的是,在 iphoneipad 上,无论是竖屏还是横屏,宽度都是竖屏时 ideal viewport 的宽度。

另外,如果我们只设置 initial-scale1,也能达到相同的效果,也就是说能把当前的 viewport 变为 ideal viewport

<meta name="viewport" content="initial-scale=1">

关于缩放

最后要说一下关于缩放的问题。

前面我们说过,即使使用手机浏览器打开 PC 端的网页,手机浏览器也能很智能的对页面进行缩放,从而不出现滚动条。

image-20220225110337093

那么这个缩放比例究竟是多少呢?

这里其实有一个公式,那就是:

当前缩放值 = ideal viewport宽度  / layout viewport 宽度

比如说,我们不设置任何的 viewport meta 标签,此时 layout viewport 的宽度为 980px,但我们可以看到浏览器并没有出现横向滚动条,因为浏览器默认的把页面缩小了。

根据上面的公式,缩放比就为 375 / 980 = 0.38 左右。

也就是当前的 initial-scale 默认值应该是 0.38 这样子。但是如果指定了 initial-scale 的值,那么这个默认值就不起作用了。

最后总结一下,为了保证在不同设备中,显示网页的视口正常,最常见的设置如下:

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