响应式网页开发基础:DPR 与 viewport

响应式设计与开发中,有两个重要的概念,一直会贯穿整个流程,但又有很多人搞不清楚。它们就是 DPR 与 viewport,下面让我们看看这两个概念。

什么是 DPR?

我们知道在 Chrome 浏览器控制台 console 中输入

window.devicePixelRatio

可以获取当前屏幕的 DPR。

那么什么是 DPR (Device Pixel Ratio)?这里不妨先给它个定义:window.devicePixelRatio 是设备上物理像素 (physical pixels) 和设备无关像素 (device-independent pixels (dips)) 的比例。公式表示就是:window.devicePixelRatio = physical pixels / dips

这个定义里的 dips 并不太好理解,现在我们尝试通过下面几点来搞明白:

  • 首先,dips 是一种度量单位
  • 然后,要知道浏览器并不是根据物理硬件的像素来工作的,而是根据 dips 宽度来工作。
  • 最后,还要知道 dips 是将像素值与实际距离联系起来的,不管屏幕的像素密度是多少,dips 为 1px,那么实际宽度就是 1px,也就是对应 CSS 中的 1px,而不是对应物理像素 1px。

这里我们就可以看到,1px 并不总是等于 1px。

搞明白 dips,我们举个简单例子,MacBook Pro 13.3 英寸的显示器分辨率是 2560 x 1600,这个 2560px 就是我们前面说的设备上的物理像素值,而浏览器全屏显示的宽度只有 1280px,这个就是 dips 值,最终可以知道这台 MacBook Pro 电脑屏幕的 DPR 为 2,DPR 在这里所表达的意思就是:1280 dips 在实际显示的时候,被硬件扩展到了 2560 的硬件像素宽度,2 个物理像素对应 1 个 CSS 像素(这个指的水平方向或垂直方向,如果在一个平面内的话 4 个物理像素点对应 1 个 CSS 像素点)

如果现在上面这台电脑里有一张实际宽度为 200px 的高清图片,在浏览器里被 css 设置宽度为 200px,那么这张图片看起来就会有点模糊,因为它实际被硬件扩展到了 400px 的硬件像素宽度,是它实际宽度的两倍。但是,如果它被 css 设置宽度为 100px,这时候它实际被硬件扩展到了 200px 的硬件像素宽度,和它实际像素一致,就不会模糊了。

响应式的第一步:设置 viewport

我们知道响应式网站通常要正确设置名称为 viewport 的 meta 信息,才可以正常显示。例如最常用的 viewport 设置方法:


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

那么什么是 viewport?

viewport 通常是指用户网页的可视区域,简称”视区“。但是我们这里讨论的 viewport 不仅是这个概念。我们不妨把 viewport 分为 layout viewport、visual viewport 和 ideal viewport 三个概念。

在移动设备上,layout viewport 并不局限于浏览器可视区域 visual viewport 的大小,可以比浏览器的可视区域大,也可以比浏览器的可视区域小。默认情况下的 viewport 是 layout viewport,它的宽度通常大于浏览器可视区域,也可以说是大于移动设备的 dips 宽度。

需要注意的是,这个没有设置任何 viewport 相关 meta 的情况下,如果当前页面的 layout viewport 大于移动设备的 dips 宽度,为了使得页面不出现横向滚动条,提高用户体验,移动设备通常会自动给整个网页设置一个默认的缩放值来缩小页面。这就是为什么我们看到一些不是响应式的网站在移动设备如 iphone 和 ipad 中会以整体缩小到刚好布满整个屏幕的形式展现。

对于已经做好响应式的站点,默认的 layout viewport 宽度就不合时宜了,因为这些站点经过优化在移动设备宽度下也可以正常显示,这时候我们需要一个 ideal viewport,可以通过 width=device-width 来设置 layout viewport 等于设备的 dips 宽度来获得 ideal viewport。

但是还不够,在 iphone 和 ipad 上,无论你给 viewport 设的宽度是多少,如果没有指定默认的缩放值,则 iphone 和 ipad 会自动计算这个缩放值,以达到当前页面不会出现横向滚动条的目的。所以我们还要设置 initial-scale=1 来保证网页在浏览器中一开始就根据屏幕尺寸 1:1 缩放或扩大。需要注意的是,设置 initial-scale=1 其实是让 dips 像素与 CSS 像素的比例达到 1:1。单独通过这个设置也会把当前的 viewport 变为 ideal viewport。

更多 viewport 的设置可以参考 W3C viewport 或参考下表,通常情况下,设置上面两个即可且是必须的。

补充:什么是 ppi(Pixels Per Inch)

要补充这个问题是因为,有个问题可能会困扰到你:在 viewport 缩放比例都为 1 (或缩放比例相同即可)的情况下,为什么同样大小的字体(比如16px)或者同一个 app 的 icon 在不同的移动设备下人眼看起来的大小不一样?

这个问题其实和 PPI 和 DPR 两者都密切相关。前面我们已经知道了什么是 DPR,那么什么是 PPI 呢?

PPI 即像素密度,表示每英寸所拥有的像素数量。

同样大小的字体在不同设备为什么看起来大小不一样,本质上就是问一个 dips 像素在不同设备中分别等价于多少英寸。首先假设 viewport 缩放比例都为 1(即 ideal viewport),然后我们知道每个物理像素等于 1/PPI 英寸,那么一个 dips 像素(此时对应一个 CSS 像素)对应的物理像素就是 DPR 个,那么一个 dips 像素的长度就可以由 DPR * (1/PPI) = DPR/PPI 计算出来。

举个例子:iphone7 PPI 为 326,DPR 为 2,DPR/PPI 约等于 0.00613497,而 iphone7 plus PPI 为401,DPR 为 3,DPR/PPI 约等于 0.0074813;所以 iphone7 plus 上的 app 图标和字比 iphone7 要大。

参考文章:

devicePixelRatio
A pixel is not a pixel is not a pixel
A tale of two viewports — part one
A tale of two viewports — part two
Meta viewport
在移动浏览器中使用viewport元标签控制布局
快捷提示:别忘记Viewport Meta标签

▲ 本文作者:金运墨(@tedlife ),中国矿业大学数学系毕业,就职于freelancer。前端开发纳米学位进行中,现已成为编程入门课导师。

编辑于 2017-04-01

文章被以下专栏收录