背景

近几年,用户大规模使用手机等移动设备来进行网页浏览器,这时有一个很现实的问题摆在了厂商面前,用户并不能很好地通过手机等设备访问网页,因为屏幕太小。

需要解决的痛点

  • 用户不需要通过缩放和滚动条就能可以正常查看所有内容。
  • 任何分辨率显示出来的文字图片都是差不多的,比如一段14px大小的文字,不会因为在一个高密度像素的屏幕里显示得太小而无法看清。

    viewport 是什么?

    在 PC 端,视口指的是浏览器的可视区域,其宽度和浏览器窗口的宽度保持一致。
    而移动端则较为复杂,它涉及到三个视口:布局视口(Layout Viewport)、视觉视口(Visual Viewport)和理想视口(Ideal Viewport)。

布局视口(Layout Viewport)

简单的讲,通过 viewport meta标签,创建一个虚拟的布局视口(layout viewport),而这个视口的分辨率接近于PC显示器。这就很好的解决了早期的页面在手机上显示的问题,由于两者之间的宽度趋近,CSS只需要像在PC上那样渲染页面就行,原有的页面结构不会被破坏。

移动设备上的浏览器都会把自己默认的viewport设为980px或1024px(也可能是其它值,这个是由设备自己决定的),但带来的后果就是浏览器会出现横向滚动条,因为浏览器可视区域的宽度是比这个默认的viewport的宽度要小的。下图列出了一些设备上浏览器的默认viewport的宽度。
image.png
layout viewport 的宽度可以通过 document.documentElement.clientWidth来获取。

视觉视口(Visual Viewport)

有了layout viewport,我们还需要一个视口用来承载它,这个视口可以简单的认为是手持设备物理屏幕的可视区域(浏览器可视区的宽度),我们称之为(视觉视口)visual viewport。这是一个比较直观的概念,因为你能看得见你的手机屏幕。

visual viewport的尺寸不会是一个固定的值(不能修改),甚至每款设备都可能不同。大致列几种常见设备的visual viewport尺寸:

  • iPhone4~iPhone5S: 320*480px
  • iPhone6~iPhone6S: 375*627px

image.png
Visual Viewport 的宽度可以通过 window.innerWidth来获取。

理想视口(Ideal Viewport)

我们还需要一个视口,它类似于布局视口,但宽度和视觉视口相同,这就是完美视口(ideal viewport)。
有了完美视口,用户不用缩放和拖动网页就能够很好的进行网页浏览,何种分辨率显示出来的文字图片都是差不多的。

ideal viewport并没有一个固定的尺寸,不同的设备拥有有不同的ideal viewport。所有的iphone的ideal viewport宽度都是320px,无论它的屏幕宽度是320还是640,也就是说,在iphone中,css中的320px就代表iphone屏幕的宽度。
image.pngimage.png
但是安卓设备就比较复杂了,有320px的,有360px的,有384px的等等,而完美视口也是通过viewport meta的某种设置来达到。

viewport特性

通常情况下,viewport有以下6种设置。当然厂商可能会增加一些特定的设置,比如iOS Safari7.1增加了一种在网页加载时隐藏地址栏与导航栏的设置:minimal-ui,不过随后又将之移除了。

Name Value Description
width 正整数或device-width 定义视口的宽度,单位为像素
height正整数或device-height 定义视口的高度,单位为像素
initial-scale [0.0-10.0] 定义初始缩放值
minimum-scale [0.0-10.0] 定义缩小最小比例,它必须小于或等于maximum-scale设置
maximum-scale [0.0-10.0] 定义放大最大比例,它必须大于或等于minimum-scale设置
user-scalable yes/no 定义是否允许用户手动缩放页面,默认值yes

initial-scale
如果我们设置 initial-scale=2 ,此时viewport的宽度会变为只有160px了,就是原来1px的东西变成2px了,但是1px变为2px并不是把原来的320px变为640px了,而是在实际宽度不变的情况下,1px变得跟原来的2px的长度一样了,所以放大2倍后原来需要320px才能填满的宽度现在只需要160px就做到了。

视觉视口和缩放比例的关系为:

  1. visual viewport宽度 = ideal viewport宽度 / 当前缩放值
  2. 当前缩放值 = ideal viewport宽度 / visual viewport宽度

总结

移动设备上的 viewport 分为 layout viewportvisual viewportideal viewport 三类,其中的ideal viewport是最适合移动设备的viewport,ideal viewport的宽度等于移动设备的屏幕宽度,只要在css中把某一元素的宽度设为ideal viewport的宽度(单位用px),那么这个元素的宽度就是设备屏幕的宽度了,也就是宽度为100%的效果。ideal viewport 的意义在于,无论在何种分辨率的屏幕下,那些针对ideal viewport 而设计的网站,不需要用户手动缩放,也不需要出现横向滚动条,都可以完美的呈现给用户。

补充

两种像素(物理像素 、CSS 像素)

像素是计算机屏幕中显示特定颜色的最小区域。相同大小屏幕中的像素越多,画面就越精细。
这里已经涉及了两种不同的像素:物理像素和 CSS 像素。

物理像素(设备像素,device pixels)

指的是设备屏幕的物理像素,任何设备的物理像素数量都是固定的。

CSS 像素(CSS pixels)

是 CSS 和 JS 中使用的一个抽象概念。它和物理像素之间的比例取决于屏幕的特性(是否为高密度)以及用户进行的缩放,由浏览器自行换算。
在 Apple 的视网膜屏(Retina)中,每 4 个像素为一组,渲染出普通屏幕中一个像素显示区域内的图像,从而实现更为精细的显示效果。此时, 250px 的元素跨越了 500 个物理像素的宽度。如果用户进行了放大,那么一个 CSS 像素还将跨越更多的物理像素。

devicePixelRatio 设备像素比

在移动端浏览器中以及某些桌面浏览器中,window对象有一个devicePixelRatio属性;
定义为:设备物理像素和设备独立像素的比例
也就是:devicePixelRatio = 物理像素 / 独立像素

css中的px就可以看做是设备的独立像素,所以通过devicePixelRatio,我们可以知道该设备上一个css像素代表多少个物理像素。

例如,在Retina屏的iphone上,devicePixelRatio的值为2,也就是说1个css像素相当于2个物理像素。但是要注意的是,devicePixelRatio在不同的浏览器中还存在些许的兼容性问题。

一倍图、二倍图、三倍图(答案有疑问)

问:对于一张 100px * 100px 的图片,通过 CSS 设置其宽高:

  1. width:100px;
  2. height:100px;

在普通显示屏的电脑中打开是正常的,但假设在手机或 Retina 屏中打开,按照逻辑分辨率来渲染,他们的 devicePixelRatio = 2,那么就相当于拿 4 个物理像素来描绘 1 个电子像素。这等于拿一个2倍的放大镜去看图片,图片就会变得模糊。
这时,就需要使用 @2x 甚至 @3x 图来避免图片的失真。

参考文档