从 viewport 起谈谈移动端布局

背景

早期的网站都是适应于 PC 端浏览器的,在移动端打开的时候,页面会被缩小,用户体验很不好。于是,Mobile Safari引入了「viewport 元标签」来让我们可以控制页面显示的尺寸和视口,如今其它移动端浏览器也支持了这个标签。在学习 viewport 之前,我们先了解一些概念。

基础概念

设备像素和 CSS 像素

设备像素,指的是屏幕能够显示的最小单位,比如 iPhone 6 的分辨率是 750*1334,指的是对角线长度为 4.7 英寸的一个长方形,它的高被分为 1334 个单位,宽被分为 750 个单位,这每一个单位,就是一个设备像素。设备像素在设备生产完成之后就是不变的。

CSS 像素(也叫逻辑像素),是为 web 开发者创造的,指屏幕能够显示的抽象像素点。它是一个相对单位,表示的真实物理长度是可变的。比如 iPhone 6 的 CSS 像素是 375px*667px。

屏幕像素比——DPR

DPR(devicePixelRatio),指的是默认 100% 缩放的情况下,设备像素和 CSS 像素的比值。

DPR = 设备像素 / CSS 像素(某个方向上)

在 PC 端,通常一个 CSS 像素就对应着一个设备像素,即屏幕像素比为 1;而在移动端,会出现一个 CSS 像素宽对应着 2 个设备像素宽,即屏幕像素比为 2,就像上面举例的 iPhone 6,就是我们常说的 Retina 屏幕。

相关的 BOM 属性

  • screen.width——拿到的是屏幕的 CSS 像素
  • window.innerWidth——拿到的是包含滚动条的浏览器视口宽度
  • document.documentElement.clientWidth——拿到的是浏览器的可见区域宽度
  • document.documentElement.offsetWidth——拿到的是 html 的宽度

viewport

现在我们来详细讨论一下 viewport。

viewport,叫视口,就是屏幕上能够用来显示网页的那片区域,但是它又不局限于浏览器的可视区域那么大。默认情况下,移动端的 viewport 都是大于浏览器可视区域的,因为移动设备的分辨率通常比 PC 设备小,为了能在移动设备上正常显示传统的为 PC 端设计的网站,移动端的浏览器会把 viewport 设成980px(也可能是其他值)。

layout viewport 和 visual viewport

视口有layout viewport和visual viewport 的区别,以下是 stackoverflow 上一个关于这两者概念的解释:

把 layout viewport 想像成为一张不会变更大小或者形状的大图。现在想像你有一个小一些的框架,你通过它来看这张大图。这个小框架的周围被不透明的材料所环绕,这掩盖了你所有的视线,只留这张大图的一部分给你。你通过这个框架所能看到的大图的部分就是 visual viewport。当你保持远离框架(缩小)来看整个图片的时候,你可以不用管大图,或者你可以靠近一些(放大)只看局部。你也可以改变框架的方向,但是大图(layout viewport)的大小和形状永远不会变。

meta 标签

通过 name 为 viewport 的 meta 标签,可以控制 viweport:

  • width:控制 viewport 的大小,可以指定的一个值(如 600),或者是特殊的值(如 device-width, 为设备的宽度)。
  • height:和 width 相对应,指定高度。
  • initial-scale:初始缩放比例,也即是当页面第一次 load 的时候缩放比例。
  • maximum-scale:允许用户缩放到的最大比例。
  • minimum-scale:允许用户缩放到的最小比例。
  • user-scalable:用户是否可以手动缩放,值为yes或者no。

移动端适配

在工作中,我们会通过以下方案对移动端网站做适配:

  1. 通过 meta 标签控制 viewport

    1
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"">
  2. 用 rem 处理字体

    1
    2
    3
    html {font-size: 62.5%; /*10 ÷ 16 × 100% = 62.5%*/}
    body {font-size: 1.4rem; /*1.4 × 10px = 14px */}
    h1 { font-size: 2.4rem; /*2.4 × 10px = 24px*/}
  3. 用媒体查询有针对性地处理不同宽度下的元素效果

    1
    2
    3
    4
    5
    @media (max-width: 600px) {
    div {
    font-size: 2.8rem;
    }
    }

阿里的手淘团队经过多年的摸索和挑战,总结了一套移动端适配的方案——flexible.js。具体用法和原理,大家可参考:flexible.js

参考: