移动端viewport

Published on

文章转载自 https://www.cnblogs.com/ssh-007/p/7196748.html

我们通常在写移动端页面时,往往都会在 html 页面中加入这样一段话

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

可能我们只知道这三个字段的含义(视口宽度等于设备宽度,屏幕缩放为 1,禁止用户缩放),但是为什么要这么写,其原理又是什么呢?

我们先看一个简单的 demo 吧。

<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Test 02</title>
</head>
<style>
    body{
        margin: 0;
    }
    .pic{
        width: 320px;
        height: 568px;
        background-color: #72DFFF;
        color: white;
        font-size: 60px;
        text-align: center;
        line-height: 568px;
        font-family: cursive;
    }
</style>
<body>
    <div class="pic"> 320*568 </div>
</body>
</html>

该 demo 展示一个宽度为 320px 的 div,我们在 iphone5 上面打开看一下。 p9ZvM6S.png

有没有感觉很诡异?明明 iphone5 的分辨率是 320px*568px(我使用的是谷歌的 mobile 模拟),但是只显示了三分之一左右。

在回答此问题之前,我们需要先普及一下一些移动端的概念。

px:逻辑像素

dp:设备像素(物理像素)

dpr:设备像素缩放比

(某一方向上-->计算:dpr = 设备像素/逻辑像素,平面上-->计算:1px = (dpr)² *dp)

ppi:屏幕每英寸的像素数量,即单位英寸内的像素密度(计算:分辨率平方后开跟/屏幕尺寸)

ppi 与 dpr 的关系表

ldprmdprhdprxhdpr
ppi120160240320
默认缩放比0.751.01.52.0

我们得知 iphone5 的尺寸为 4 英寸,设备分辨率为 1136dp640dp,由此我们可以得出 iphone5 的分辨率为 320px568px,如下图(retina 为高清)。 p9ZvQOg.png

该页面展示三分之一的原因是 ios 中默认的布局 viewport 是 980px,然后根据刚才的计算的 iphone5 分辨率才会出现此情况。

逻辑像素(css pixels)与设备像素(device pixels)的区别------------

我们姑且认定设备的 pixels 为正确(标准)的 pixels 宽度。这些 pixels 决定了你工作所用的那些设备上正式的分辨率。

如果用户缩放(zoom)了浏览器,当然必须改变计算方式。

现代浏览器上的缩放,是基于“伸展”pixels。结果是,html 元素上的宽度并没有因为缩放 200%而由 128pix 变成 256px,而是真实的 pixels 的被计算成了双倍。html 元素在形式上依然是 128CSS 的 pixels,即便它占用了 256 设备的 pixels 。

换言之,缩放 200%将一个单位的 CSS 的 pixels 变成了 4 倍的设备的 pixels 那么大,即宽度 _ 2、高度 _ 2,面积扩大了 2 * 2.

下列图片将清楚的解释这个概念。如图 1-1.有 4 个 1 像素,缩放为 100%的 html 元素,CSS 的 pixels 完整的和设备的 pixels 重叠

当我们缩小浏览器时,CSS 的 pixels 开始收缩,导致 1 单位的设备的 pixels 上重叠了多个 CSS 的 pixels,如图 1-2

同理,放大浏览器时,相反的事情发生了,CSS 的 pixels 开始扩大,导致 1 单位的 CSS 的 pixels 上重叠了多个设备的 pixels,如图 1-3

总体而言,你只需要关注 CSS 的 pixels,这些 pixels 指定你的样式被如何渲染。

就像刚开始的那个小 demo,在 pc 以及 iphone5 上展示是两种完全不同的效果。

在这里我普及一个知识点,对于 viewport,苹果手机浏览器默认做了两件事——

1.页面渲染在一个 980px(IOS)的 viewport(安卓 viewport 宽度不固定)

2.缩放

说的详细一些,viewport,就是手机浏览器把页面放到一个虚拟的窗口中,窗口可大于或小于手机的可视区域,一般会大于可视区域。这样不会破坏没有针对手机浏览器优化的网页的布局,用户可以通过平移或缩放来看网页的其它部分。

这也就是为什么我们没写 viewport,手机会默认将布局宽度置为 980px 的原因。

为什么要有 viewport? 一个 300 多像素的屏幕,放一个 1000 多像素的页面,会混乱,所以要先虚拟一个 980 像素的页面,然后进行缩放。

为什么不使用默认 980px 的布局 viewport 1.宽度不可控,不同设备(安卓)默认值可能不同 2.页面缩小版展示,交互不友好 3.有缩放,缩放后有滚动 4.font-size 可能要设置 40px 才等于 pc 上 12px,不规范

然后为了在 iphone5 上正常展示,我们需要写这样一个 viewport

<meta name="viewport" content="width=320">

这样效果 ok,但是如果我们的设备是 iphone6,iphone6s 呢?

<meta name="viewport" content="width=375">

显然是不符合规定的,所以我们需要设置

<meta name="viewport" content="width=device-width">

但是每个不同的设备都会有不同的缩放比 window.innerWidth/document.body.clientWidth 为 initial-scale 度量 viewport/布局 viewport [Layout Viewport(布局视口)] 比如如果要让 iphone6 展示 1000px 的页面,只设置"width=device-width",肯定都会挤在一起。

所以需要让缩放比为 1,设置 initial-scale=1,所以最终版本是这样

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

最后总结一下移动端中的三个 viewport——

1.布局视口

document.body.clientWidth 为手机浏览器 viewport 宽度(布局 viewport),默认 980 跟 width=device-width 相关,其值等于 meta 标签中的 width initial-scale = 2 ,它会跟着缩小一倍 当你需要使用 js 而不是媒体查询来编写业务逻辑的时候,这很有帮助

if(document.body.clientWidth >= 400){

  .class{...}
}

等价于

@media all and (max-width>=400){

  .class{...}
}

我们用到的 vw,vh 尺寸单位代表视口的百分比,比如 width:50vh,这里的视口就是指布局视口,因为如果是视觉视口,每次用户缩放都会导致元素狂傲发生变化,先不说这个变化带来的大计算量,这种设计对用户来说本身就是毫无意义的。

2.视觉视口

window.innerWidth 屏幕上显示的网站区域尺寸,会受缩放的影响

3.理想视口

screen.width

它是对设备来说最理想的布局视口尺寸。


在手机上,桌面视口被拆分成两个——布局视口限制你的 css 布局,视觉视口决定用户能看到什么。

其实这么多的 viewport 看起来可能会乱一点,但事实并不是这样。最佳实践就是让浏览器直接使用它的理想视口,即把布局视口设置为理想视口,然后使用媒体查询来响应不同的理想视口就 OK。

响应式设计的核心—— width 和 height 的媒体查询设置了当前布局视口的宽高。 使用最佳 mate 标签后,就可以放心的抛开布局视口的宽度,只专注于理想视口

@media all and (max-width:400) {
  .class {
    ...
  }
}

各机型 viewport