本文是看了PPK大神等的文章后总结的,基本还是搬砖吧。对于viewport
的认识比之前清晰了很多,希望对别的小伙伴也有帮助。
先来说说PC端的视口吧。在PC端,就一个视口,即浏览器窗口的大小。页面的大小和浏览器窗口的大小相等。CSS中的像素和浏览器屏幕的像素一一对应。
如果还不明白什么是分辨率、屏幕尺寸、PPI,可以看这篇文章:
(全解析)屏幕尺寸,分辨率,像素,PPI之间到底什么关系?
还需要搞清楚以下几个概念:
桌面的screen.width
是指电脑屏幕的宽度,是读的物理像素(device pixel),固定不变的。
以CSS pixel为单位,表示浏览器中网页可视区域的宽度和高度(能展现的CSS大小),即viewport
的大小。这两个值包含了滚动条。如果用户进行了放大,屏幕承载的CSS像素变少了,那么这两个值就会变小;反之用户缩小页面,这两个值就变大了。
PPK大神提到:
That tells you exactly how much space the user currently has available for your CSS layout.
In theory, the width of thehtml
element is restricted by the width of the viewport. Thehtml
element takes 100% of the width of that viewport.
The viewport, in turn, is exactly equal to the browser window. The viewport is not an HTML construct, so you cannot influence it by CSS.It just has the width and height of the browser window — on desktop. On mobile it’s quite a bit more complicated
意思是viewport
的大小是由这两个值决定的。但之后又提到也可以通过document.documentElement.clientWidth
来获取。但这两个值并不总是相等的,请看下面:
在以下两种情况下,viewport
的大小会发生改变:
1. 用户对浏览器进行了调整,即触发`resize` 事件,例如将窗口调小,那么`viewport`会变小,因为能够承载的CSS像素变少了。此时,页面文档(`html` 元素)的大小就是视口的大小,即`document.documentElement.innerWidth` 和`window.innerWidth` 保持一致。此时浏览器会产生滚动条,可以滚动查看更多的页面内容。
2. 用户进行了缩放。如果放大,那么`viewport`也会变小,因为,放大后一个CSS像素占据的物理像素变多,窗口就那么大,能够承载的CSS像素变少。而此时`document.documentElement.innerWidth` 并不会发生变化,元素的CSS大小还是那么大,只不过是放大了一屏放不下,需要拖动页面才能查看完整,这个不是滚动条的效果。
从上面的可以看出,在不缩放的情况下,html标签的大小=viewport大小=浏览器可视窗口的大小。那么问题来了,如果缩放了,viewport
到底应该是哪个值? 我更倾向于通过document.documentElement.innerWidth
来获取吧,这也是移动端获取layout viewport
的方式。其实在移动端更关心layout viewport
怎么渲染在屏幕上吧。桌面端应该也是关心整个文档怎么显示的吧,而且媒体查询查到的也是document.documentElement.innerWidth
的值。不知道自己说得对不对。
另外,关于页面的布局还有以下几个比较重要的值:
offsetWidth: 盒子在页面中占据的位置大小,包括能看见的content(即除开滚动的部分)、padding、滚动条、border。不管是块元素还是内联元素;
clientWidth: 如果是内联元素,返回0.如果和块级元素,返回能看见的content(即除开滚动的部分)、padding.
scrollWidth: 整个元素的大小,包括滚动不可见的部分。
pageX/Y gives the coordinates relative to the
html
element in CSS pixels.(以offset获取的为基准)clientX/Y gives the coordinates relative to the viewport in CSS pixels.
screenX/Y gives the coordinates relative to the screen in device pixels.
media query
中的width
是指 viewport
的宽度,即通过document.documentElement.clientWidth
获取的。
移动端有布局视口和视觉视口之分,视觉视口就是屏幕能承载的CSS大小。布局视口比视觉视口要大很多。原因是浏览器厂商想让PC端的页面在手机上显示也要看起来比较舒服,而PC端的屏幕要比手机端大很多,如果直接将PC端的网页满屏显示,那页面上的元素要么会因为放不下而挤成一团,要么元素看上去将会非常小(无论是提供了绝对像素值还是百分比)。这样厂商就提供了比能看到的屏幕大的layout viewport
,这样就像有一张比较大的画,屏幕上能看到画的一部分,通过移动屏幕就能看到画的其他部分。
请记住layout viewport
的尺寸(CSS)是一直保持不变的。html
元素的大小是指layout viewport
的大小,页面上元素的百分比也是基于layout viewport
的。
Thus the
html
element takes the width of the layout viewport initially, and your CSS is interpreted as if the screen were significantly wider than the phone screen. This makes sure that your site’s layout behaves as it does on a desktop browser.
不同的浏览器,其layout viewport
的大小是不一样的:
Safari iPhone uses 980px, Opera 850px, Android WebKit 800px, and IE 974px.
页面的CSS就按照layout viewport
的大小来渲染。这比visual viewport
大很多。
还有一点就是很多移动端的浏览器都会在初始时候将页面进行缩小( in the maximally zoomed-out mode),以使得visual viewport
能够完整地放下整个页面。此时visual viewport == layout viewport
. 不管手机屏幕进行了旋转还是缩放,layout viewport
的尺寸都是一定的,变化的都是visual viewport
。旋转的时候浏览器会自动的将visual viewport
进行适当的缩放以放下整个页面。
先来看一个标签:
<meta name="viewport" content="width=320">;
这个是用来设置layout viewport
的尺寸的。
那么为什么要设置layout viewport
的宽度呢?因为通常,浏览器会自动将页面进行zoom out
使得页面能够完整地被屏幕展示,即visual viewport == layout viewport
,造成的结果是页面上的元素可能会非常小(因为1个CSS像素所占据的物理像素变少了)。
上面的代码将其设置为了320px
,此时layout viewport
的宽度变小了,那么浏览器在初始的时候,将320px
的页面满屏显示,相比之前,CSS宽度小了很多,那么每个CSS像素对应的物理像素就多了,这样看起来页面上的元素就变大了。
那么我们最常看到的设置为width=device-width
, 它的值原本表示设备的物理像素,即screen.width
, 但是如果是高分辨率的设备,这个值又太大了,所以工程师们可能会取少于设备物理像素值作为device-width
的值。
补充:很多设备的理想视口的宽度为320px
的原因,是viewport
首先在iphone3 提出使用,而它的分辨率是320px。现在市面上多数设备的理想视口宽度是320、360、384、400等几种,都接近320,这样页面在不同的屏幕上看起来差别不大。
这里可以查看各种设备的ideal viewport
:
view port
ideal viewport 的意义在于,无论在何种分辨率的屏幕下,那些针对ideal viewport 而设计的网站,不需要用户手动缩放,也不需要出现横向滚动条,都可以完美的呈现给用户。
页面上元素的视觉大小,一方面和其所占据的CSS多少有关(前面通过layout viewport
使得元素在流体布局下占据的CSS增多),还与一个CSS像素对应多少个物理像素有关,这就引出了DPR:
设备像素比(DPR) = 设备像素个数 / device-independent-width
layout viewport
的尺寸可以通过document.documentElement.clientWidth
来获得,这个值是一定的,只有屏幕旋转时-height
会有变化。
visual viewport
的尺寸通过window.innerWidth
获取,当屏幕旋转或者缩放,这个值都会变化。
其中的width
指的是layout viewport
的CSS宽度。device-width
指屏幕中的物理像素值,即screen.width
。
媒体查询通常可以用来检测用户的设备是移动端还是PC端。
在chrome上做了个实验,的确是如果没有设置width=device-width
,那么浏览器会自动缩小页面,让layout view
满屏显示(为毛有时候缩小了有时候没有):
此时页面上的元素显得很小,因为把比较大的layout view
整个放到屏幕上了:
而加了,width=device-width
后:
说了那么多,还是总结一下:
PC端的viewport只有一种,就是浏览器窗口大小
移动端的viewport有layout viewport和visual viewport两种。后者是设备屏幕能承载的CSS大小。之所以厂商增加了layout viewport,是因为想让PC端的页面也能在手机端看清楚,由于手机屏幕比电脑屏幕小很多,如果还是在手机端满屏显示整个页面,例如以宽度10%显示的元素在手机端看起来会很小。或者会因为放不下那么多CSS像素,页面上的元素挤成一团。因此,厂商将页面范围扩大。通过移动页面可以看到其他部分。
通常手机在加载页面的时候会自动缩小页面,使得满屏显示整个页面,layout viewport本来就比visual viewport宽很多,这样一来一个CSS像素占据的物理像素会变少,页面上的元素就很小。
后来提出的width=device-width
,这是设置layout viewport的宽度为设备物理像素宽度。这样一来页面可以完整显示在整个页面。但随着高分辨率屏幕的出现,layout viewport设置成这么多物理像素不合适了,工程师们通常会取一个较小的值。320px比较常见。很多厂商的ideal viewport都是趋于320px的,这样所有页面在不同设备上看起来都差不多。
获取viewport 大小
layout viewport通过
document.documentElement.clientWidth
获取;
visual viewport通过window.innerWidth
获取;
device-width通过screen.width
获取
参考资料:
A tale of two viewports — part one
A tale of two viewports — part two
移动前端开发之viewport的深入理解
一篇真正教会你开发移动端页面的文章(一)