Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浅说移动前端中 Viewport 和 Viewport units #69

Open
dwqs opened this issue Jul 29, 2018 · 4 comments
Open

浅说移动前端中 Viewport 和 Viewport units #69

dwqs opened this issue Jul 29, 2018 · 4 comments

Comments

@dwqs
Copy link
Owner

dwqs commented Jul 29, 2018

Viewport units

Viewport units(视口单位)是一系列 CSS 长度单位的统称,主要包含 vhvwvminvmax 等四个 CSS3 中新增的长度单位,在CSS:7个你可能不认识的单位一文中有对其作了简单的介绍:

  • vh:视口高度的1%
  • vw:视口宽度的1%
  • vminvwvh 中的较小值
  • vmaxvwvh 中的较大值

兼容性

对于新属性,在使用之前都需要提前了解一下其兼容性。caniuse 提供的兼容性数据如下:

caniuse

数据截止:2018/07/29

从兼容性来上看,目前并不是所有的 Viewport units 被现代浏览器所支持:

  • IE9 不支持 vmin
  • IE10+、Edge 15-、Safari 6、 iOS Safari 7.1- 以及 Chrome 25- 不支持 vmax

但从图表数据来看,无论是桌面端还是移动端,浏览器对 vhvw 的支持都很好。

微信内置浏览器的内核是 X5。X5 对 viewport units 的支持如下:

x5

截图来自:http://res.imtt.qq.com/tbs/incoming20160419/home.html

什么是Viewport(视口)

Viewport 的作用是限制网站的初始包含块元素,即 html 元素。

通常情况下,所有的块元素的宽度都是父元素宽度的100%,因而 body 元素和它的父元素(html 元素)一样宽。那 html 元素的宽度是多少?在实际开发中我们会发现,其宽度总是和浏览器窗口的宽度保持一致。从理论上来讲,html 元素的宽度是受限于 Viewport 的,其宽度总是 Viewport 宽度的 100%。

因而,Viewport 就是浏览器窗口,它不是一个 HTML 结构,因而不能通过 CSS 去改变它的形态。在桌面浏览器中,Viewport 仅表示浏览器窗口的大小(即窗口的可视区域),但在移动端,它要复杂很多,这涉及到三个视口。

视觉视口

视觉视口(visual viewport)是指网页在物理屏幕上的可视区域。用户可以通过滚动来改变网页在可视区域显示的部分,或者通过缩放改变显示部分的大小。

visual viewport

在现代浏览器中,如果要获取视觉视口的大小,可以通过 window.innerHeightwindow.innerWidth,其返回值分别包含了水平滚动条的高度和垂直滚动条的宽度。

布局视口

如果网页的大小超出了设备屏幕的大小,视觉视口仅能显示网页中的某一部分。在移动端,CSS 的布局,HTML 元素宽度的百分比则均是相对于布局视口(layout viewport)进行计算的。通常而言,布局视口的宽度要大于或等于可视视口的宽度。

layout viewport

html 元素的宽度则等于布局视口的初始宽度,而布局视口的宽度则和设备的浏览器有关,如 iOS Safari 是 980px,Android WebKit 则是 800px。

在现代浏览器中,如果要获取布局视口的大小,可以通过 document.documentElement.clientWidth/clientHeight 来得到对应的宽高值(不含滚动条),这两个属性始终返回布局视口的宽高。如果要获取 html 元素的宽高,则可以通过 document.documentElement.offsetWidth/offsetHeight 来得到对应的宽高值(含滚动条)。

一般情况下,二者返回的对应属性值是一致的。但如果给 html 元素设置了高宽值,则返回就不一样了:

diffrent

理想视口

理想视口(ideal viewport)即通常所说的屏幕分辨率,给出了网页在移动设备上的理想大小。理想视口没有一个固定的尺寸,不同的设备拥有不同的理想视口,可以在 viewportsizes 上查询不同设备的理想视口宽度。

理想视口是最适合移动设备的视口,其宽度等于移动设备的屏幕宽度。只要在 CSS 中把某一元素的宽度设为理想视口的宽度(单位用px),那么这个元素的宽度就是设备屏幕的宽度了,也就是宽度为100%的效果。理想视口的意义在于,无论在何种分辨率的屏幕下,那些针对理想视口而设计的网站,不需要用户手动缩放,也不需要出现横向滚动条,都可以完美的呈现给用户。

另外,需要注意的是:

  • 通过 viewport 的 meta 标签,布局视口可被设置成理想视口的值:
<meta name="viewport" content="width=device-width,initial-scale=1">

设置 meta 标签之后,则可以通过 document.documentElement.clientWidth/Height 来获取理想视口的大小;如果没设置,部分机型(如 iPhone 7)提供了 screen.width/height 来获取其大小。需要注意的是有的机型虽提供了 screen.width/height 的值,但这个值并不一定等于设备的物理像素。

  • 在 viewport 的 meta 标签中,所有的 scale 指令都是相对于理想视口而不是布局视口。

Viewport units 中的视口

根据上文,1vw1vh 分别是视口宽度和高度的 1%。在桌面端,视口指的就是浏览器的可视区域:

1vw = window.innerWidth / 100
1vh = window.innerHeight / 100

那在移动端,这里的「视口」则是指布局视口。

viewport

在布局视口中,1vw1vh 的值是不固定的,这跟设备的放置方向有关:

vw/vh

100vh 的问题

根据上文,如果给元素设置 height: 100vh,那元素的高度应该会刚好铺满整个可视区域,但事实并非如此。

准备一个简单 demo 如下:

// demo.html
<html>
  <head>
  	<meta name="viewport" content="width=device-width,initial-scale=1">
  	<style>
  	  body {
  	  	 height: 100vh
  	  }
  	</style>
  </head>
  <body>
    内容区域
  </body>
</html>
  • 在桌面端浏览器访问 demo.html,会发现会出现垂直滚动条。这是由于 body 有默认的 margin 值,因而解决该问题的方式也很简单,将 body 元素的 margin 值设置成 0 就行:
body {
  height: 100vh;
  margin: 0
}
  • 在移动端的浏览器访问 demo.html,也会出现垂直滚动条。但这跟body 有默认的 margin 值并无多大关系,而是浏览器「刻意为之」,具体可见 CSS3 100vh not constant in mobile browser。如果要避免滚动条,可尝试如下方式:
body {
  height: 100%;
}

参考资料

@nanhupatar
Copy link

您好,我想转载您的这篇文章到公众号 前端指南中,我会注明出处,请问可以么

@dwqs
Copy link
Owner Author

dwqs commented Sep 4, 2018

@nanhupatar 可以

@nanhupatar
Copy link

非常感谢

@YangPengFe1
Copy link

兄弟 我必须关注你了。太溜了。学到了。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants