你是不是被 Web 布局中的各种 viewport 概念搞蒙,不但如此,你还得去考虑网页有放大缩小的情况,更气人的是 Mobile 侧和 PC 侧很多表现竟然不一样。本篇就带你一同探讨下这些问题。
px
css 中的 px 并不代表一个屏幕的物理像素,而是一个逻辑像素。比如我们写了一个 10 X 10 px 的方块,如果我们此时进行放大(ctrl+)操作,让整个网页变为 200%,那会发现这个方块在屏幕上长宽也各增大了一倍,那么同样代码的 10x10 对应占用的物理像素变为了原来的 4 倍(长宽各 2 倍)。所以 css 中的 px 并不是物理像素,这样更加灵活。后来浏览器还引入了 devicePixelRatio
,同样 px 即使在高分辨率的显示屏幕上也不会出现问题,因为会乘以这个系数来作为真实的物理像素。
window.innerWidth
在 PC 浏览器上,当你放大、缩小网页时,你会发现 innerWidth 和 innerHeight 会随着改变,放大时 innerWidth 会变小,这是为啥呢?innerWidth 的官方定义如下:
The read-only Window
property **innerWidth**
returns the interior width of the window in pixels. This includes the width of the vertical scroll bar, if one is present.
所以 innerWidth 和 innerHeight 表现的是网页的布局区域的像素值,如果网页整体放大,那么同样的物理区域内显示的像素当然就变少了,进而导致了 innerWidth 变小。官方定义还有下面一句话:
More precisely, innerWidth
returns the width of the window's layout viewport.
layout viewport 和 visual viewport
继续先来一段官方解释。
The layout viewport is the viewport into which the browser draws a web page. Essentially, it represents what is available to be seen, while the visual viewport represents what is currently visible on the user's display device.
通俗来讲,layout viewport 表示一个可见布局,这个可见布局里的内容并不一定当前可见,当前可见的部分有被称为 visual viewport。
此时我们回顾下刚刚介绍 px 时使用的放大缩小能力,PC 侧和移动侧放大缩小功能是不一样的,而且它们的作用也不同。在 PC 侧的浏览器,我们可以通过浏览器的 zoom 功能。
而在移动端,我们需要用两指缩放、或用单指双击的方式。这种方式并不会引起
window.innerWidth
的变化。也就是说移动侧的 layout viewport 不变,会变动只是 visual viewport。文档也证实了这一说法
This becomes important, for example, on mobile devices, where a pinching gesture can usually be used to zoom in and out on a site's contents. The rendered document doesn't change in any way, so the layout viewport remains the same as the user adjusts the zoom level. Instead, the visual viewport is updated to indicate the area of the page that they can see.
当网页完全缩放塞满整个屏幕时,layout viewport === visual viewport。而当两指放大时,visual viewport 要小于 layout viewport。
viewport
移动端布局中用到一个 name 为 viewport 的 meta,此 viewport 和刚刚所提到的 layout viewport 和 visual viewport 并不同。此属性的作用是约束整个网页布局 html 的大小。所以你可以通过以下两个属性获得他的大小。
document.documentElement.clientWidth
document.documentElement.clientHeight
PC 侧的浏览视窗大小是可以随意变动的,所以在 PC 侧,此属性设置无效,PC 侧的 window.innerWidth === document.documentElement.clientWidth
。而到移动端就不一样了,移动端的浏览器往往占据整个屏幕,你无法调整视窗的比例和大小,此时定义 viewport 就有作用了。并且为了能在移动设备上显示老的 PC 侧页面,移动浏览器厂商默认把这个 viewport 定为了 980px,有些如 IE 定为了 1024px。
例如我写了个以下例子
<html>
<body style="margin: 0">
<div style="width: 100%; font-size: 40px; overflow: hidden; background-color: rgb(220, 220, 220);">12345678912345678912345678</div>
</body>
</html>
在没有加 meta 的情况下,这个 div 长度为 980,由于移动端浏览器机制,针对这种默认场景,浏览器会把整个网页自动缩小到占据屏幕的整个宽。如果要展示如 PC 侧一样的大小,则会出现左右滚动条,体验很差。
此时我们加上 viewport 的 meta,则会发现宽度变为了屏幕的 320 宽。
<meta name='viewport' content="width=device-width">
viewport 可以用来改变移动端 html 的宽度像素值,此值与屏幕本身的宽度并无关,只是你可以通过设置 width=device-width
的方式让两者相同。
另外此 meta 中还有 initial-scale, maximum-scale, minimum-scale, user-scalable
这几个配置,user-scalable 及表示用户是否可以用两指缩放。scale 几个参数表示缩放比例,都是相对于屏幕宽度来说的,所以initial-scale=1.0
和 width=device-width
是一样的意思,如果调成 0.5,则相当于把 width 设置为了 2 倍 device-width。因为内容缩小了一倍,那自然viewport就放大了一倍了。
总结一下
screen.width
, screen.height
表示整个显示屏幕的逻辑像素宽高;
window.innerWidth
, window.innerHeight
表示 layout viewport,在 PC 侧会随着浏览器窗口和 zoom 效果而变大变小。而在移动端侧,则表示整个布局的长宽,由代码决定。
visual viewport
真正表示当前可以看见的区域。
meta viewport
可以定义 html 的宽度。
如果你想了解 Android 中的尺寸布局问题,可以看:《Android布局中的尺寸单位介绍》