viewport的理解和使用(面试必看)

html-css08

viewport的理解和使用(面试必看),第1张

查看github原文

移动端浏览器通常都在一个比屏幕更宽的虚拟窗口中渲染页面,这个虚拟窗口就是viewport,目的是正常展示没有做移动端适配的网页,可以让他们完整的展现给用户。我们有时用移动设备访问桌面版网页就会看到一个横向滚动条,这里可显示区域的宽度就是viewport的宽度。

在桌面网页开发时,css中的1px就是设备上的1px;然而css中的1px仅仅是一个抽象的值,不代表实际像素为多少;而在移动设备中,不同设备的像素密度是不一样的,css中的1px可能并不等于真实设备的一个像素值。用户缩放也会改变css中的1px代表多少设备像素。这个比例就是devicePixelRatio

我们可以在浏览器中进行缩放,在控制台中打印 window.devicePixelRatio 来查看 devicePixelRatio 的大小。其中的独立像素可以理解为css中的px。

一个典型的针对移动端优化的站点包含类似下面的内容:

以下为viewport的几个属性,这些属性可以混合来使用,多个属性同时使用要用逗号隔开。这里我们展开一个概念,叫做 ideal viewport ,指的是理想情况下的viewport,不需要用户缩放和横向滚动条就能正常查看网页的所有内容,并且能够看清所有文字,无论这个文字在css中定义为多小,显示出来时可以看清的。

当设置了 width 和 initial-scale 时,浏览器会自动选择数值最大的进行适配。如设置:

浏览器会选择数值大的进行适配,如果当前窗口ideal viewport宽度为300, initial-scale 值为1,取得是width为400的值;如果当前窗口的ideal viewport为480,则取480。

事实上, width=device-width 和 initial-scale=1 都代表应用 ideal viewport ,但在ipad、iphone等移动设备和IE上,横竖屏不分,默认都取竖屏的宽度,兼容性最好的写法就是

下面就告诉大家如何解决。   

1.  使用HTML中的viewport来实现

viewport语法如下:

HTML代码

<!--在html代码的<head>...</head>中嵌入下面代码-->

<meta name="viewport"

  content="

    height = [pixel_value | device-height] ,

    width = [pixel_value | device-width ] ,

    initial-scale = 0.5 ,

    minimum-scale = float_value ,

    maximum-scale = float_value ,

    user-scalable = [yes | no] ,

  "

  

/>

width

控制 viewport 的大小,可以指定的一个值或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)。

height

和 width 相对应,指定高度。

initial-scale

初始缩放。即页面初始缩放程度。这是一个浮点值,是页面大小的一个乘数。例如,如果你设置初始缩放为“1.0”,那么,web页面在展现的时候就会以target density分辨率的1:1来展现。如果你设置为“2.0”,那么这个页面就会放大为2倍。

maximum-scale

最大缩放。即允许的最大缩放程度。这也是一个浮点值,用以指出页面大小与屏幕大小相比的最大乘数。例如,如果你将这个值设置为“2.0”,那么这个页面与target size相比,最多能放大2倍。

user-scalable

用户调整缩放。即用户是否能改变页面缩放程度。如果设置为yes则是允许用户对其进行改变,反之为no。默认值是yes。如果你将其设置为no,那么minimum-scale 和 maximum-scale都将被忽略,因为根本不可能缩放。

(设置屏幕宽度为设备宽度,禁止用户手动调整缩放)

HTML代码

<meta name="viewport" content="width=device-width,user-scalable=no" />

(设置屏幕密度为高频,中频,低频自动缩放,禁止用户手动调整缩放)

HTML代码

<meta

name="viewport" content="width=device-width,target-densitydpi=high-dpi,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"

/>

注:1). 所有的缩放值都必须在0.01–10的范围之内。

     2). minimum-scale、maximum-scale要么写值,要不留这两个

2. 不使用绝对宽度

    由于网页会根据屏幕宽度调整布局,所以不能使用绝对宽度的布局,也不能使用具有绝对宽度的元素。这一条非常重要。

具体说,CSS代码不能指定像素宽度:

width:xxx px

只能指定百分比宽度:

width: xx%

或者

width:auto

3. CSS的@media规则

     同一个CSS文件中,也可以根据不同的屏幕分辨率,选择应用不同的CSS规则。

HTML代码

@media screen and (max-device-width: 400px) {

.column {

float: none

width:auto

}

#sidebar {

display:none

}

}

上面的代码意思是,如果屏幕宽度小于400像素,则column块取消浮动(float:none)、宽度自动调节(width:auto),sidebar块不显示(display:none)。

4.  流动布局

    各个区块的位置都是浮动的,不是固定不变的。

HTML代码

  .main {

float: right

width: 70%

}

.leftBar {

float: left

width: 25%

}

float的好处是,如果宽度太小,放不下两个元素,后面的元素会自动滚动到前面元素的下方,不会在水平方向overflow(溢出),避免了水平滚动条的出现。

另外,绝对定位(position: absolute)的使用,也要非常小心。

5. 图片的自适应

    图片的宽度和高度要按百分比来设定,千万不可以设定成固定大小。

HTML代码

  <img width="95%" src="" alt="" />

关于viewports以前一直都是知道个大概但是一直没有详细去了解,加上最近在项目中遇到了比较近点的1像素问题,就乘着这个机会再加深一下印象回顾一下基础。

screen.width/height

含义:用户的屏幕的完整大小。

度量:设备的pixels。

意思就是用户屏幕的物理宽度,它们的值不会随着用户的缩放而改变:它们是显示器的特征,而不是浏览器的特征。换句话说是屏幕出厂的时候就决定了的

window.innerWidth/Height

含义:包含滚动条尺寸的浏览器完整尺寸

度量:CSS的pixels

document.documentElement.clientWidth/Height

含义:viewport尺寸:浏览器窗口尺寸。

度量:CSS的pixels

随浏览器大小变化而变化,但宽度不包含滚动条宽度。具体请看图一比较两者的差别。

viewport的功能在于控制你网站的最高块状(block)容器:<html>元素。怎么理解这句话呢?

假设定义了一个可变尺寸的布局(liquid layout),且你定义一个侧边栏的宽度为width: 10%。当你改变浏览器窗口大小时,该侧边栏会自动扩张和收缩。这是什么原理呢?

技术上讲,原理是侧边栏的宽度为它父元素宽度的10%,我们设它的父元素是body,且你未指定宽度。那么问题就变为了<body>的宽度到底是多少?

通常,一个块级元素占有起父元素的100%的宽度(这里有异常情况,暂时忽略)。所以<body>的宽度就是其父元素<html>的宽度。

那么<html>元素到底有多宽?

<html>的宽度受viewport所限制,<html>元素为viewport宽度的100%。,因为它的宽度恰好为浏览器的宽度。所以你的侧边栏宽度width: 10%会占用10%的浏览器宽度。

反过来,viewport是严格的等于浏览器的窗口:定义就是如此。viewport不是一个HTML的概念,所以你不能通过CSS修改它。它就是等于浏览器窗口的宽度高度 –—— 在桌面浏览器上如此,移动设备浏览器上有点复杂。

注意:当我们设置html上面手动的设置了宽度,在那种情况下document. documentElement. clientWidth/Height依然给出了viewport的尺寸,而不是<html>元素。

比如 我手动设置html的样式为

html {width:2000pxheight: 2000px}

通过document. documentElement. clientWidth/Height 获取到的值只会是viewport的大小,而不是html元素的大小 2000px

所以document. documentElement. clientWidth/Height只会给出viewport的尺寸,而不管<html>元素尺寸如何改变。

document. documentElement. offsetWidth/Height

含义:<html>的尺寸

度量:CSS的pixels

如果clientWidth/Height一直用以标示viewport的尺寸,我们该如何去获取<html>元素的尺寸呢?通过document.doucmentElement.offsetWidth/Height来获取html的宽度。

像上面的那个例子,这个就会返回2000px

含义:页面的移位

度量:CSS的pixels

window.pageXOffset 和 window.pageYOffset,定义了页面(document)的相对于窗口原点的水平、垂直位移。因此你能够定位用户滚动了多少的滚动条距离.

对应viewport我们现在普遍理解为两种视图:

1.visualviewport:window.innerWidth/Height定义 包含滚动条

2. layoutviewport: document.documentElement.clientWidth/Height 不包含滚动条

在理解这两种viewport之前,我们先认识理解这几个名词的意思:首先我们要记住: 1 px 就一个像素点

iphone 默认viewport 是980 

vw:是Viewport's width的简写,1vw等于window.innerWidth的1%

vh:和vw类似,是Viewport's height的简写,1vh等于window.innerHeihgt的1%

vmin:vmin的值是当前vw和vh中较小的值

vmax:vmax的值是当前vw和vh中较大的值

1. 像素密度 :每英寸可以显示的像素点的数量,像素密度越大,表示在同样的尺寸里面,像素点越多

比如:iphone 3 的屏幕像素是320x480,iphone4s的屏幕像素是640x960,刚好两倍,然而两款手机都是3.5英寸的。

1英寸是一个固定长度,等于2.54cm。 像素密度越高,代表屏幕显示效果越精细。 Retina屏比普通屏清晰很多,就是因为它的像素密度高。

2.像素: 可以分为物理像素和CSS像素

物理像素(device independent pixels ): 物理像素也叫设备像素,任何设备的物理像素是固定不变的。比如我的笔记本的分辨率是1366 * 765,表示的就是宽度上最多容纳1366个物理像素点,高度上最多容纳765个物理像素点

CSS像素(CSS pixels ):CSS像素也叫逻辑像素,是为web开发创造的。通常情况下,在桌面端,CSS像素的大小和设备像素的大小是相等的,即一个CSS像素完全覆盖了一个设备像素。如下图

但是在手机端,我们都知道网页可以通过手指进行缩放,这时候CSS像素也会改变

缩小操作 :当用户进行缩小操作时,一个物理像素覆盖了多个CSS像素。图中深蓝色表示物理像素,半透明的浅蓝色表示CSS像素

当用户进行放大操作时,一个CSS像素覆盖了多个物理像素 : 这里的一个css像素就不在等于一个物理像素了。当缩小两倍的时候,两个css像素相当于一个物理像素。

DPR

DPR(devicePixelRatio)指的是设备像素比,即网页在不进行缩放使,设备像素和CSS像素的比值

DPR = 设备像素 / CSS像素(某一方向上)

从iphone4开始,苹果公司推出了retina视网膜屏幕,这种技术在屏幕大小不变的情况下,屏幕像素密度提高了一倍,分辨率自然也提高了一倍,于是DPR等于2

通过JS的screen.width和screen.height属性,可以获取屏幕的CSS像素

通过JS的window.devicePixelRatio属性,可以获取屏幕的DPR值

以iphoneX为例,css像素(设备独立像素)为375px * 812px,DPR是3,可以计算出设备像素(物理像素)是1125px * 2436px

屏幕分辨率

屏幕分辨率就是设备像素,一般以纵向像素 * 横向像素来表示分辨率。比如iphoneX的设备像素是1125px * 2436px,分辨率也就是1125px * 2436px

在不同的屏幕上,CSS像素所呈现的物理尺寸是一致的,而不同的是CSS像素所对应的物理像素具数是不一致的。在普通屏幕下1个CSS像素对应1个物理像素,而在Retina屏幕下,1个CSS像素对应的却是4个物理像素(某一方向上相当于1个css像素对应2个物理像素。)。

比如:

在普通屏中 我设置一个div的样式 width:100px ( 100px=100个物理像素。) ,当我将这个样式放在了Retina的屏幕(dpr=2)上的时候,发现变的更加清晰了。这是我们由于两个屏幕的像素密度不一样的结果,后者的像素密度是前者的两倍,所以在100px的css像素中的距离里面就存在了200个物理像素。但是两个展现的效果是一样的(CSS像素所呈现的物理尺寸是一致的。),只是里面的像素点的数量不同。

同时:visualviewport还是显示100px 但是对于layoutviewport来说就相当于200px。 因为layoutviewport表示的是物理像素。

但是对于图片来说:

在普通屏幕下,1个位图像素对应着1个物理像素,图片可以完美的显示。可是在retina屏幕下,1个位图像素对应着4个物理像素,由于位图像素不可以再分割,所以图片就会只能就进取色,导致图片模糊。

如何来处理这个问题呢。比如一个200 x 300的图片,如果想在retina屏幕上清晰显示的话,就要提供一个400 x 600的2倍图片(@2x),这样的话,1个位图像素就会对应上retina屏上的1个物理像素。图片就不会模糊啦。

说明:retina屏是一种具备超高像素密度的液晶屏,同样大小的屏幕上显示的像素点由1个变为多个,如在同样带下的屏幕上,苹果设备的retina显示屏中,像素点1个变为4个。

在高清显示屏中的位图被放大,图片会变得模糊,因此移动端的视觉稿通常会设计为传统PC的2倍。那么,前端的应对方案是:设计稿切出来的图片长宽保证为偶数,并使用backgroud-size把图片缩小为原来的1/2

//例如图片宽高为:200px*200px,那么写法如下

.css{width:100pxheight:100pxbackground-size:100px 100px}

//其它元素的取值为原来的1/2,例如视觉稿40px的字体,使用样式的写法为20px

.css{font-size:20px}

initial-scale这个缩放初始值是相对于设备的idea viewport的值进行缩放的,也就是说

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

//等效于

<meta name="viewport" content="width=devive-width"

//两者各有一个bug,所以生产时最好将两个一起写上

但如果同时出现width和initial-scale

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

并不是根据先后顺序比较,而是通过谁大取谁,比如设备是iphone5,idea viewport是320px,则此时initial-scale=1(320px),所以此时viewport取width=500

关于initial-scale缩放的默认值以及其理论

visual viewport宽度 = idea viewport宽度 / 当前设置的缩放值

当前缩放值 = idea viewport宽度 / visual viewport宽度

注:这个理论不适合安卓原生浏览器

参考文章:

再聊移动端页面的适配: https://www.w3cplus.com/css/vw-for-layout.html    阅读码:475709

使用Flexible实现手淘H5页面的终端适配: https://www.w3cplus.com/mobile/lib-flexible-for-html5-layout.htm l 阅读码:487741

viewports剖析  https://www.w3cplus.com/css/viewports.html

移动web开发-理解设备像素、CSS像素、DPR - 羊先生

解惑好文:移动端H5页面高清多屏适配方案 - CocoaChina_一站式开发者成长社区