当前位置: 代码迷 >> 综合 >> 移动前端开发之 viewport 的深入理解
  详细解决方案

移动前端开发之 viewport 的深入理解

热度:66   发布时间:2023-10-21 13:54:20.0

在移动端设备上进行网页的重构或开发,首先得搞明白的就是移动设备上的 viewport 了,只有明白了 viewport 的概念以及弄清楚了跟 viewport 有关的 meta 标签的使用,才能更好地让我们的网页适配不同分辨率的移动设备。

一、viewport 的概念

通俗地讲,移动设备上的 viewport 就是设备的屏幕上能用来显示我们的网页的那一块区域,再具体一点,就是浏览器上(也可能是一个 app 中的 webview)用来显示网页的那部分区域,但 viewport 又不局限于浏览器可视区域的大小,它可能比浏览器的可视区域要大,也可能比浏览器的可视区域要小。在默认情况下,一般来讲,移动设备上的 viewport 都是要大于浏览器可视区域的,这是因为考虑到移动设备的分辨率相对于桌面电脑来说都比较小,所以为了能在移动设备上正常显示那些传统的为桌面浏览器设计的网站,移动设备上的浏览器都会把自己默认的 viewport 设为 980px 或 1024px(也可能是其他值,这个是有移动设备自己决定的),但带来的后果就是浏览器会出现横向滚动条,因为浏览器可视区域的宽度是比这个默认的 viewport 的宽度要小的。

二、css 中的 1px 并不等于设备的 1px

在 css 中我们一般使用 px 作为单位,在桌面浏览器中 css 的 1px 往往都是对应着电脑屏幕的 1 个物理像素,这可能会造成我们的一个错觉,那就是 css 中的像素就是设备的物理像素。但实际情况却并非如此,css 中的像素只是一个抽象的单位,在不同的设备或不同的环境中,css 中的 1px 所代表的设备物理像素是不同的。在早先的移动设备中,屏幕像素密度都比较低,如 iphone3 ,它的分辨率为 320x480,在 iphone3 上,一个 css 像素确实是等于设备的一个物理像素。后来随着技术的发展,移动设备的屏幕像素密度越来越高,从 iphone4 开始,苹果公司推出了所谓的 Retina 屏,分辨率提高了一倍,变成 640x960,但屏幕尺寸却变化,这就意味着同样大小的屏幕上,像素却多了一倍,这时,一个 css 像素是等于设备的两个物理像素的。其他品牌的移动设备也是这个道理。设备上的一个 css 像素相当于多少个屏幕物理像素,也因设备的不同而不同。

还有一个因素也会引起 css 中 px 的变化,那就是用户缩放。例如,当用户把页面放大一倍,那么 css 中 1px 所代表的物理像素也会增加一倍;反之把页面缩小一倍,css 中 1px 所代表的物理像素也会减少一倍。

在移动端浏览器中以及某些桌面浏览器中,window 对象有一个 devicePixelRatios 属性,它的官方定义为:设备物理像素和设备独立像素的比例,也就是 devicePixelRatio = 物理像素 / 独立像素。css 中的 px 就可以看作是设备的独立像素,所以通过 devicePixelRatio,我们可以知道设备上一个 css 像素代表多少个物理像素。例如,在 devicePixelRatio 值为 2 的设备上,css 的 1px 就相当于 2 个物理像素。但要注意但是,devicePixelRatio 在不同浏览器中还存在些许的兼容性问题。

三、关于三种 viewport 的理论

首先,移动设备上的浏览器认为自己必须能让所有的网站都正常显示,即使是那些不是为移动设备设计的网站。但如果以浏览器的可视区域作为 viewport 的话,因为移动设备的屏幕都不是很宽,所以那些为桌面浏览器设计的网站放到移动设备上显时,必然会因为移动设备的 viewport 太窄而挤作一团,甚至布局什么的都会乱掉。所以这些浏览器就决定默认情况下把 viewport 设为一个较宽的值,比如 980px,这样的话即使那些为桌面设计的网站也能在移动浏览器上正常显示了。这个浏览器默认的 viewport 就叫做 layout viewport(布局视口)。这个 layout viewport 的宽度可以通过 document.documentElement.clientWidth 来获取。

然而,layout viewport 的宽度是大于浏览器可视区域的宽度的,所以我们还需要一个 viewport 来代表浏览器可视区域的大小,这个 viewport 就叫做 visual viewport(视觉视口),即设备的像素分辨率。其宽度可通过 window.innerWidth 获取。

移动前端开发之 viewport 的深入理解
移动前端开发之 viewport 的深入理解

现在我们已经有两个 viewport 了:layout viewport 和 visual viewport。但是还不够,还必须有一个能完美适配移动设备的 viewport 才行。所谓的完美适配指的是,首先不需要用户缩放和横向滚动条就能正常地查看网站的所有内容;其次是显示的文字大小是合适的,不会因为高分辨率而变小。这个 viewport 就叫 ideal viewport,也就是第三个 viewport,移动设备的理想视口。

四、利用 meta 标签对 viewport 进行控制

移动设备默认的 viewport 是 layout viewport,也就是那个比屏幕要宽的 viewport,但在进行移动设备网站的开发时,我们需要的是 ideal viewport。那么怎么才能得到 ideal viewport 呢?这就该轮到 meta 标签出场了。我们在开发移动端网站时,最常见的一个动作就是把下面这个东西复制到我们的 head 标签中:

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

该 meta 标签的作用是让当前 viewport 的宽度等于设备的宽度,同时不允许用户手动缩放。这个 name 为 viewport 的 meta 标签到底有哪些东西呢,又都有什么作用呢?meta viewport 标签首先是由苹果公司在其 safari 浏览器中引入的,目的就是解决移动设备的 viewport 问题。后来安卓以及各大浏览器厂商也都纷纷消防队,引入对 meta viewport 的支持。在苹果的规范中,meta viewport 有6个属性,如下:

属性 取值
width 设置 layout viewport 的宽度,为一个正整数,或字符串 “device-width”
initial-scale 设置页面的初始缩放值,为一个数字,可以带小数
minimum-scale 允许用户的最小缩放值,为一个数字,可以带小数
maximum-scale 允许用户的最大缩放值,为一个数字,可以带小数
user-scalable 是否允许用户进行缩放,值为 “no” 或 “yes”
height 设置 layout viewport 的高度,很少使用

五、把当前的 viewport 宽度设置为 ideal viewport 的宽度

要得到 ideal viewport 就必须把默认的 layout viewport 的宽度设为移动设备的屏幕宽度。因为 meta viewport 中的width能控制 layout viewport 的宽度,所以我们只能要把 width 设为 device-width 这个特殊值就行了。但要注意的是,在 iphone 和 ipad 上,无论是竖屏还是横屏,宽度都是竖屏时 ideal viewport 的宽度。

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

还有一种方法也可以得到跟上面一样的效果。因为 inital-scale = ideal viewport / layout viewport。

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

如果 width 跟 initial-scale=1 同时出现,并且还出现了冲突呢?比如:

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

width=400 表示把 layout viewport 的宽度设为 400px,initial-scale=1 则表示把 layout viewport 的宽度设为 ideal viewport 的宽度,那么浏览器到底该服从哪个命令呢?当遇到这种情况时,浏览器会取它们两个中较大的那个值。例如,当 width=400,ideal viewport 的宽度为 320 时,取的是 400;当 width=400,ideal viewport 的宽度为 480 时,取的是 480。

最后,总结一下,要把 layout viewport 的宽度设为 ideal viewport 的宽度,既可以设置 width=device-width,也可以设置 initial-scale=1,但这两者各有一个小缺陷,就是 iphone、ipad 以及 IE 会横竖屏不分,统统以竖屏的 ideal viewport 宽度为准。所以,最完美的写法应该是两个都写上去,这样就 inital-scale=1 解决了 iphone、ipad 的缺陷,width=device-width 则解决了 IE 的缺陷。

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