再谈 Viewport

651 阅读7分钟

前言

做了有一段时间的移动端h5应用了,适配方案基本上就是使用Flexible,偶尔也用用viewport单位,但是对于移动端适配的一些概念和实现本质还是处于一知半解的程度。

这种感觉就好像,你会驾驶一辆车,但是你却不知道车的内部是如何工作的,一旦遇到车抛锚,那你只能寻求帮助了,因为自己没有足够的能力去解决,这让我非常没有安全感。

于是最近花了一些时间,看了一些文章,写了写demo,终于理清了这里。

1. 像素单位

首先让我们来区分几个不同的度量像素的单位,这是比较重要的点。

1. 物理像素(physical pixel)

物理像素也叫做设备像素,它指的是显示屏幕中,真实的一个一个物理部件,如果你静距离观察过一些老的电视,就可以看到整个的画面是由一颗一颗的不同颜色的点组成的,这个点就是物理像素点。

在手机设备中,有两个规格属性,一个是分辨率,另一个是PPI,以iPhone11为例

这里的1792 X 828 指的就是该手机屏幕在垂直和水平方向拥有这么多数值的物理像素。

而PPI(Pixel Per Inch),则指的是每英寸包含的物理像素数,这个值越大,则我们感官上屏幕会越清晰。

2. 设备独立像素(density-independent pixel)

设备独立像素是比较抽象的一个单位,我们通过screen.width/height来拿到的值就是设备独立像素所度量出来的,通常情况下可认为与我们设置的css像素是等价的,

以iphone6为例,它的屏幕宽度为375px(设备独立像素),然后我们给一个元素设置css像素宽度也为375px,这个元素就会完整的铺满这个手机屏幕。

但是如果你对浏览器进行缩放的时候,就会有不同情况了,这点下面会着重解释。

3. css像素

这个就是我们写css样式时用到的像素单位。

4. 设备像素比

经常听到的一个名词,设备像素比(device pixel ratio)简称dpr,即物理像素和设备独立像素的比值。

有两种方式可以获得,

一种是window.devicePixelRatio,一种是css的媒体查询min-device-pixel-ratio

2. viewport 视口

共有三种,分别是布局视口视觉视口理想视口,搞清楚了这三个的区别,基本上也就明白了整个移动端适配的和网页的显示了。

1. 布局视口 (layout viewport)

关于布局视口这个东西,其宽度是可能会大于浏览器的可视区域宽度的,那么我们就只能通过滚动的方式进行浏览,一图胜千言,我们来先看一下这张图片。

它是我们网页的一个基准窗口,我们页面的html的宽高度都是基于这个布局视口计算的,可以通过调用document.documentElement.clientWidth / clientHeight来获取布局视口大小,度量单位是css像素。

pc浏览器中,它的大小是等于浏览器的文档窗口的。

但是在移动设备上,它的宽度会被设为一个默认值(html代码中未添加meta viewport标签),大部分为980px,并且整体内容宽度会被缩小至浏览器窗口相同,具体表现就是平时见到的把pc网页用手机打开,就像这样

那么问题就来,怎么会在375px宽度内,显示出980px的内容呢。这里回顾下之前说的设备独立像素和css像素的等价关系。

默认情况下,浏览器缩放100%时,设备独立像素是和css像素等价的,也就是一个单位的设备独立像素完整覆盖一个单位的css像素。

但是比如将网页进行缩小时,那么一个单位的设备独立像素上面会重叠多个css像素,而设备独立像素是不会变化的,所以出现了上图的表现,在375个单位宽的设备独立像素上,覆盖了980个单位宽的css像素的内容。

不过这里不需要我们担心,因为浏览器会自行计算覆盖的比例,保证我们的网页在缩放前后布局一致。

2.视觉视口 (visual viewport)

就是我们可以通过屏幕实际看到的区域,它默认就是当前浏览器的大小。

可以通过wndow.innerWidth/innerHeight来获取,度量的单位是css像素

当我们在移动端进行放大缩小时,布局视口是不会变化的,它是固定不变的,但是视觉视口会变化,体现在就是在布局视口那块讲到的css像素与设备独立像素的重叠关系,浏览器窗口放大,则一个单位的css像素也会变大。

3.理想视口 (ideal viewport)

理想视口是布局视口的一个理想尺寸,能完美适配移动设备的viewport。所谓的完美适配指的是,首先不需要用户缩放和横向滚动条就能正常的查看网站的所有内容;第二,显示的元素的大小是合适,比如我们设置一个宽100px的元素,不会因为在一个高密度像素的屏幕里显示得太小而无法看清,理想的情况是这个元素无论是在何种密度屏幕,何种分辨率下,显示出来的大小都是差不多的。

理想视口 可以通过screen.width/height获得,想必你也发现了,它的值是用独立设备像素度量的。

所以理想视口,就是我们所设置的css像素要完全等价于设备独立像素,这样我们的页面就可以完美呈现在不同设备了。

4. 移动端适配

我们开发移动端网页,都会在html加上这么一行代码,meta标签就是用来对viewport进行控制的

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

它作用的就是布局视口,详细的属性见下图

当我们把width设为device-width时,其宽度就等于理想视口的宽度了,这时1个css像素等于1个设备独立像素,所以设置width=device-width就相当于让布局视口等于理想视口。

如果你给width设置具体数值时,如果设置的数值比实际的device-width小,那么它会默认设为device-width大小的宽度。

5. 其它

  • 经过测试,vw,vh单位是基于布局视口计算的
  • fixed定位,是基于初始包含块的,也就是html元素,即布局视口

总结

1.layout viewport(布局视口):在PC端上,布局视口等于浏览器窗口的宽度。而在移动端上,由于要使为PC端浏览器设计的网站能够完全显示在移动端的小屏幕里,此时的布局视口会远大于移动设备的屏幕,就会出现滚动条。

js获取布局视口:document.documentElement.clientWidth/ClientHeight

度量单位:css像素


2.visual viewport(视觉视口):用户正在看到的网页的区域。用户可以通过缩放来查看网站的内容。如果用户缩小网站,我们看到的网站区域将变大,此时视觉视口也变大了,同理,用户放大网站,我们能看到的网站区域将缩小,此时视觉视口也变小了。不管用户如何缩放,都不会影响到布局视口的宽度。

js获取视觉视口: window.innerWidth/innerHeight

度量单位: css像素


3.ideal viewport(理想视口):布局视口的一个理想尺寸,只有当布局视口的尺寸等于设备屏幕的尺寸时,才是理想视口。

js获取理想视口:window.screen.width/height

度量单位:设备独立像素