与Viewport有关的理解

前言

国内有关viewport的文章和信息,我想大多来源于PPK的文章(篇一篇二)。从二手资料获取到的信息老是不够深, 也有限,我就有不少地方无法理解,看完原文才理解地透彻,推荐你去看看。有时间我想把这两篇文章翻译出来,既锻炼翻译能力,又学习技术,一箭双雕;如果对你们还有点帮助,那就更好了。css

一些重要基础知识

有些基础概念,你们看得不少,但未必真理解透了,有必要好好澄清。html

因为一些术语翻译成中文,我以为更容易混淆,因此保留英文名称,容易辨别和理解。前端

Device Pixel, CSS Pixel

Device Pixel

Device Pixel,说出来你们都知道,设备的物理像素。没错,它是指设备显示屏幕的实际像素。设备呈现画面是靠一些单颜色的色块显示的,这个色块在屏幕上就是一个一个小点,它们排列组合造成显示画面,这些在屏幕上实际显示的点就是设备像素。java

设备的分辨率单位就是device pixel。好比,设备分辨率是320*480,表示横向有320个点,即320device pixel,纵向有480个点,即480device pixelweb

注意,320,不是长度单位,不是它有320那么宽,而是表示横向有320个点,至于这点有多大,那不一样设备就不一样样了。因此,640*960的设备不必定比320*480的宽,只是代表前者横向的点多些,密度大些。因此一样设备宽度,好比4.7英寸,分辨率能够是640*960,也能够是320*480。前者像素更多,能显示的图像信息更多,但咱们看到的图像的宽度是同样的,只是前者清晰,后者画质差些。chrome

CSS Pixel

CSS Pixel, 你们叫法不同,有设备独立像素,相对像素,参考像素(reference pixel,这个叫法相对靠谱),懒得翻译了,就叫CSS像素,形象,由于这个像素就是指CSS中用的像素,适用于开发者的像素单位。之因此称为单位,是由于我以为它是一种单位体制。开发网站时,咱们用的是一套统一的单位,使得页面上各元素的布局和相对大小是固定的。编程

好比,我设定body的宽度是800px,里面有一个div,设定的宽度是400px,那么表现出来的效果就是这个div占了body的一半。无论你是在电脑上看,在平板上看,仍是在手机上看,它始终都是占一半,不一样的是,电脑上看着宽一些(电脑屏幕有二十几厘米吧)手机上看着窄一些(手机屏幕不到十厘米)。windows

你看,我设定的宽度是800px,但不一样设备上的显示效果同样,这就像咱们编程写了一个通用接口,接口的底层我无论,我只要最后通用的效果;又或者像Java的JVM,你写通用的java代码,至于运行在windows上仍是Linux上,它们用的什么命令执行,你无需操心,我只关心在各个设备上的执行结果是否一致。浏览器

CSS pixel就像是这个通用接口或者Java代码,device pixel就是底层接口。因此CSS Pixel是一种与设备无关的开发者像素单位。bash

二者关系

各自的概念搞清楚了,再来看看二者的关系。

前面打了个比方,说CSS Pixel就像是一个接口,Device Pixel就像是底层,接口表现出效果,而不用管各类各样的底层。那么接口和底层的“适配”是怎么适配的呢?也就是说当要表现出800px(CSS pixel)的效果时,各设备怎么计算用多少实际的device pixel来呈现呢?

对于电脑端,很简单,所见即所得,也就是800px的CSS pixel显示出来就是800个device pixel。

手机端就复杂些,“适配”机制由手机厂家说了算。厂家根据本身的生产工艺,决定说,我这台4.7英寸的手机,对外显示的CSS像素是320*480(CSS pixel),也就是说,无论手机一行有多少个实际像素点,一行都表示320px(css pixel),这就是device pixel与css的“适配”机制。

呈现的方式就是,

  • 对于 320*480分辨率的手机,一行表示320px(css pixel),而手机一行有320个点(device pixel),所以恰好一个CSS pixel对应一个device pixel来显示;
  • 对于 640*960分辨率的手机,一行仍是表示320px(css pixel),而这里手机的一行有640个点(device pixel),所以用2个点(device pixel)来显示1个px(CSS pixel)示;

下面的图例,css宽高都设置为2px:

  • 左图是1个css pixel对应1个device pixel,那么2px(css pixcel)的宽高,用2个device pixel显示;
  • 右图是1个css pixel对应2个device pixel,那么2px(css pixcel)的宽高,用4个device pixel显示。

Viewport

PPK定义了三种viewport:Layout viewport, Visual viewport, Ideal viewport,前二者我是认同的,第三种我认为应该定义为“厂家定义的对外适配视窗”更好(Adapt viewport),说理想视窗,反而让你们迷糊,缘由后面解释。

Layout viewport

Layout viewport, 布局视窗(PS. 翻译过来总以为变了味),它是用于承载咱们的html文档的一个视窗容器,对,当成容器更容易理解。它有固定宽度,若是里面的html文档宽度比它的宽度还宽,就会出现横向滚动条;若是比它还窄,就会出现空白。

Layout viewport的宽高用document.documentElement.clientWidthdocument.documentElement.clientHeight得到(单位是CSS pixel,与web开发有关的px都是CSS pixel)。

document.documentElement就是<html>元素,得到<html>所在的客户端的宽度,其实就是外面容器Layout viewport的宽度

对于电脑端,Layout viewport比较好理解,就是咱们看到的浏览器的窗口区域。

手机端就复杂了。

手机端 Layout viewport

因为手机端屏幕窄,不能像电脑端那样看到那么多的东西,但手机厂商也但愿能在手机上查看适配于电脑的网页,但又不能让浏览器的宽度跟手机屏幕同样宽,由于那样的话,咱们的网页宽度超过了窗口宽度,会出现横向滚动条。好比浏览器的宽度设成和手机屏幕(对外适配屏幕宽度)同样的宽度320px(css pixel),而电脑网页的宽度多是1024px(css pixel),显然须要横向滚动,用户须要右划来查看网页。

可否不出现横向滚动条,一加载就看到网页全貌呢?他们想了个办法,让手机浏览器宽度仍是足够宽(好比980px),手机浏览器宽度超过手机屏幕宽度,这时拿手机看浏览器的网页,只看到网页的一小部分(想象管中窥豹),这时候浏览器的宽度是超过手机屏幕的。而后把浏览器缩放,缩放到和手机屏幕同样宽,这时候看到的,就是一个缩小版的电脑网页。

缩小前
缩小后

layout viewport在手机端不直观,经过上面两张图可以更好理解layout viewport。

最后,Layout viewport size(css pixel)一旦设置了就是固定的,即容器设定了就不会变化。页面加载完成后,它不会由于页面放大和缩小而改变,改变的是咱们看到的内容范围,也就是后面要说的visual viewport。

注意,这里说的浏览器宽度,是开发者意义上的宽度,不是咱们见到的尺寸的宽度。好比,layout viewport宽度是980px,那么它无论放在电脑上显示,仍是缩放在手机屏幕上,表明的都是980px,若是里面有一个div是490px宽,那么咱们看到的效果都是占一半宽度,只不过电脑上的长度很长,手机上的看着很短,但这个div都是490px。

一般设置的viewport

咱们一般设置viewport的<meta>,设置的就是layout viewport,能够理解为它是浏览器中物理存在的视窗。

<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
复制代码

Visual viewport

Visual viewport, 可视窗口,是可见到的文档部分的窗口区域。

想象一张桌子上放了一张地图,你正在用放大镜看地图。桌子就是layout viewport,地图就是html文档,放大镜就是Visual viewport。

Visual viwport size(css pixel)就是你放大镜里看到的内容区域的大小,它不是固定的。放大镜里看到的是一个县,visual viewport size就是一个县的面积那么大;看到的是一个镇,visual viewport size就是一个镇的面积那么大。

你能够右手持放大镜,左手移动地图来查看不一样部份内容(固然生活中不会这么作),至关于手机端滑动查看文档;你能够把放大镜放得离地图近些或者远些,来看得更清楚或看得更多,至关于手机端的缩放。想象地图会缩小,缩小到跟你的放大镜同样大,你看到的就是整张地图。

因此,Visual viewport是文档可见部分的视窗,就像手机后面有一个浏览器,里面装了文档,你拿一个矩形方框在看文档同样。

Visual viwport的宽高能够用window.innerWidthwindow.innerHeight来获取,不过支持性不是很是全面,未验证。

Adapt viewport(Ideal viewport)

前面二者都是真实存在的视窗,第三种是只有手机端才有的概念。

电脑端的网页在手机端查看,效果确定不如意,过小,但愿针对手机端的屏幕,有手机端的理想网页显示尺寸。这个尺寸不会太宽,宽到电脑浏览器那么宽;不会太窄,窄到变成一条竖条,要恰好能适配手机的宽度。符合这个尺寸的视窗,PPK称为理想视窗,这个理想视窗是相对于用电脑浏览器宽度的。我倒认为应该定义为适配视窗,由于手机厂家为本身的手机设置了固定的适配尺寸,即,我这台手机横向表明多少个CSS pixel, 纵向表明多少个CSS pixel, 这是定死的。

手机分辨率也是固定的。所以device pixel和css pixel的适配关系也就固定了。也就是咱们常见到的DPR

且不说是否是理想视窗,看看安卓那一堆的DPR,1.5, 2, 2.5, 3.5, 乱七八糟,适配尺寸五花八门,谁知道它们定出来的适配尺寸是否是理想的。苹果的尺寸都好歹有规律,DPR成倍数关系,适配尺寸也就那几种。

所以,Adapt viewport是手机厂商设定的该手机的适配窗口尺寸,即屏幕的横向纵向表明的CSS pixel数,与手机的分辨率无关。

  • 假设手机的分辨率是320*480, Adapt viewport size能够是320*480,横向320px(CSS pixel),一个CSS pixel对应一个device pixel;
  • 假设手机的分辨率是640*960, Adapt viewport size也能够是320*480,横向仍是表明320px(CSS pixel),只不过这时一行里1个CSS pixel用2个device pixel来呈现。

Adapt viewport获取

adpat viewport的宽度经过<meta>标签里的device-width获得,以及媒体查询的device-width

<!-- 设置layout viewport的宽度为adapt viewport的宽度(好比320px) -->
 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
复制代码
@media screen and (max-device-width: 375px) {
    .footer {
        background-color: black;
    }
}
复制代码

注意,width是layout viewport的宽度,device-width才是adapt viewport的宽度,也就是厂家设定的页面显示适配宽度。你们能够用chrome的手机模式测试下。这也好理解,特别强调device-width,就表示厂家对这台设备对外宣称的设备宽度,用来讲明它横向表示多少像素(css pixel),纵向多少宽度(css pixel)。

看看<meta>标签的设置width=device-width, 就是让layout viewport的宽与adapt viewport的宽一致,从这里也能够区分width, device-width的意义了。

关于width和device-width的区别也能够参看此文章:Media Queries: Width vs. Device Width

viewport <meta>

viewport的meta是苹果手机最开始引入的,用来设置屏幕的布局尺寸(layout viewport),后来安卓也跟随其方法,都支持了这个标签。

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minum-scale=1.0, user-scalable=no" />
复制代码
  • name, meta字段名称,为“viewport”
  • content,具体舌质红字段,用key value键值对来表示,键值对之间用逗号分隔。
    • width, 直接设置layout viewport宽度,能够是具体数值,如300,也能够是一个特殊值device-width(css pixel), 表示手机的adapt viewport width(css pixel),也就是厂家设定的适配尺寸。
    • initial-scale, 初始的缩放值,能够决定layout viewport尺寸和visual viewport尺寸
    • maximum-scale, 用户能缩放的最大值
    • minimum-scale, 用户能缩放的最小值。若是maximum-scal和minimum-scale都为1,用户就不能对页面进行缩放。
    • user-scalable, 用户是否能缩放,值:yes/no,这个值没测试,彷佛是为了兼容性。

viewport scale

视窗缩放,这个东西困扰了我好久。

首先思考的是,缩放的是什么视窗?Layout viewport? visual viewport?

答案是,Layout viewport

试想以前放大镜的例子,此次换成用一块黑色矩形边框的玻璃看地图,地图和玻璃的距离固定,要缩放地图怎么办?玻璃(手机屏幕)大小是固定的,因此要缩放地图。

玻璃不动,地图放大,玻璃里看到的地图文字就变大了(至关于文档字体变大),但所看到的地区的面积变少了(原来看到一个县,如今只能看到一个镇),看到的面积变小,也就是visual viewport size变小了;地图缩小,则反之。

补一句,放大时,visual viewport size变小,这里可能比较费解,以前说visual viewport size是看到的内容区域的大小,咱们能耐看到的文档内容变少了,于是visual viewport size变小了。

<meta>标签中的scale

那么<meta>标签中的scale是设置什么的呢?initial-scale=2的意义是什么?

始终记得,viewport<meta>标签设置的是layout viewport。前面也说了scale是对layout viewport的缩放,因此首先scale是设置layout viewport的。

可是这里还没这么简单,这个scale还有一层意思,就是将layout viewport缩放后,要使其能刚恰好铺满屏幕(fit the screen)。

举个例子,initial-scale=0.5,首先它表示将layout viewport缩小到原来的一半;其次,缩小后,整个layout viewport要恰好铺满这个屏幕,换句话说,这时候的visual viewport尺寸就恰好等于layout viewport尺寸,由于咱们看到了layout的所有。

如今就至关于作一道小学数学应用题:

===================================

已知adapt viewport的尺寸为375*667(css pixel),即layout viewport不进行缩放,且尺寸也为375*667时,那么整个浏览器页面要恰好铺满屏幕。问,假设将layout viewport缩放至原来的一半后,其恰好铺满整个屏幕,layout viewport尺寸须要多大,此时的visual viewport尺寸是多少?

解:

  • layout viewport尺寸为375*667时,即scale=1,恰好铺满整个屏幕,此时visual viewport尺寸等于layout viewport尺寸
  • layout viewport尺寸为750*1334时,假设不对layout viewport进行缩放(scale=1),此时layout viewport有一半伸展到了屏幕外面,只有一半显示在手机中,visual viewport尺寸为375*667
  • 接上面,此时若是把layout viewport缩放到原来的一半,那么伸展在屏幕外面的区域缩到了手机屏幕中,整个layout viewport恰好铺满屏幕,此时visual viewport尺寸为750*1334

答:layout viewport尺寸须要750*1334,此时visual viewport尺寸为750*1334

====================================

从上面的推导能够看出一个关系:当scale=0.5时,adapt viewport是layout viewport的一半,即

adapt-viewport = 0.5 * layout-viewport = scale * layout-viewport
复制代码

那么

layout-viewport = adapt-viewport / scale
复制代码

因为scale的定义要求最后缩放的结果是layout viewport的尺寸恰好铺满屏幕,铺满屏幕就是visual viewport了,所以这种状况下layout-viewport-size = visual-viewport-size。因而,

*【visual-viewport = layout-viewport = adapt-viewport / scale

注意,这里的layout-viewport与adapt-viewport的关系是基于scale得出的关系,若是layout viewport width另外单独定义了(如定义width=400),那么visual viewport不必定等于layout viewport。

这就是定义scale后得出的关系。只要有了scale,就有了layout viewport和visual viewport的尺寸。

initial-scale

scale是经过initial-scale来定义的,它表示页面第一次加载时的scale,此后若是页面修改了这个值,再刷新是无效的,须要关闭从新打开页面。

前面说了设置了scale,就有了layout viewport,若是同时还定义了width呢?

例如:假设设备的adapt viewport为320*480。定义meta:

<meta name="viewport" content="width=700, initial-scale=0.5">
复制代码
  • width=700,定义了layout viewport宽为700;
  • initial-scale=0.5, 能够得出layout viewport为640

那么问题来了,取那个呢?

答案是,取最大的那个值

  • 根据initial-scale的设置,此时页面处于缩小0.5倍的状态,visual-viewport-width=640px(css pixel), layout-viewport-width=640px(css pixel)
  • 因为设置了width=700,大于640, 故 layout-viewport-width=700px(css pixel)(若是width设置为600,那么layout-viewport宽仍是640px)

产生的效果就是屏幕有滚动条,须要滚动一点点(60像素)。

<meta>默认值

若是不设置viewport <meta>标签,那么layout viewport宽度是多少,visual viewport是多少,scale又是多少?

layout viewport大多数浏览器默认是980px,有部分浏览器是其余值。手机浏览器厂商为了提升用户体验,默认会缩放layout将整个layout铺满屏幕显示,使得页面不会出现横向滚动条。咱们看到所有页面,因此visual viewport尺寸等于layout viewport,所以visual viewport宽等于980px(css pixel)

再根据前面的计算公式visual-viewport = adapt-viewport / scale, 那么

scale = adapt-viewport / visual-viewport
复制代码

假设手机适配尺寸adapt-viewport为375*667(css pixel),那么

scale = 375/980 = 0.382653
复制代码

这个值浏览器是自动计算得出的。

width, initial-scale只设置一个值

  • 若是只设置了initial-scale,根据scale的做用,浏览器会计算laytou viewport宽度,而且将layout viewport自动适配到屏幕,使其恰好铺满屏幕;
  • 若是只设置了width,那么浏览器也会将layout viewport自动适配到屏幕,使其恰好铺满屏幕。scale的值会自动计算。

总结

  1. Device pixel是设备物理像素。CSS pixel是参考像素,与实际像素无关。
  2. Viewport有三种:Layout viewport, Visual viewport, Adapt viewport,Layout viewport是文档容器视窗,Visual viewport是文档可见部分视窗,Adapt viewport是手机适配视窗,是厂家为本身的手机设定的屏幕显示尺寸。
  3. <meta>标签设置的是layout viewport,能够经过width字段设置,还能够经过scale字段设置。不设置时,大多数浏览器layout viewport为980px,且彻底铺满于屏幕中。

最后

啰啰嗦嗦说了这么多,但愿把知道的都表述清楚了。大概我比较笨,看别人的文章,有时以为不够详细,看完不理解,因此我尽可能细致的把前因后果和注意事项都说了,生怕哪里掉了什么。

viewport这块看了很多文章,写完这些理解才真正加深了。只要可以理解好viewport的这些知识,移动端的适配就轻松多了。

参考文章