视口概念

本文阐述了视口的概念——它是什么,以及它在 CSS、SVG 和移动设备方面的影响。本文定义了初始视口和实际视口,并区分了视觉视口布局视口

什么是视口?

视口是用户代理的一项功能,用于为连续媒体建立初始包含块。

通用的视口术语通常指计算机图形学中当前正在查看的区域。在 Web 浏览器术语中,它通常与浏览器窗口相同,不包括 UI、菜单栏等。它是你正在查看的文档部分。

文档加载时,视口会经历两个阶段:

初始视口

初始视口指的是在用户代理样式、HTML <meta> 标签或 CSS 样式覆盖其大小之前,UA 的窗口或可视区域。初始视口的大小基于窗口或可视区域的大小,而不是内容。全屏用户代理的初始视口大小会因设备和方向而异,但对于同一设备在同一方向下,其大小总是相同的。

实际视口

实际视口是在处理了视口 <meta> 标签后得到的视口。为大视口设计的内容在小视口中查看时可能会出现各种错误,包括意外换行、内容被裁剪以及滚动容器大小不正确。视口元标签提供了有关视口初始大小的提示。实际视口的大小由其 content 属性定义。如果省略此标签,一些移动浏览器会使用固定的初始包含块宽度来渲染内容,通常是 980px。它们将实际视口的宽度设置为此值,然后缩小内容以适应它,使得 CSS 像素尺寸小于实际像素。

像本文这样的文档可能会很长。你的视口是当前可见的所有内容;值得注意的是,“什么是视口”部分,或许还有一些导航菜单。视口的大小取决于屏幕的大小、浏览器是否处于全屏模式,以及浏览器是否被放大。视口外的内容,比如本文档中的“参见”部分,在滚动到视图中之前可能不会在屏幕上显示。

  • 在较大的显示器上,应用程序不一定是全屏的,此时视口就是浏览器窗口的大小。
  • 在大多数移动设备上以及浏览器处于全屏模式时,视口就是整个屏幕。
  • 在全屏模式下,视口是设备屏幕,窗口是浏览器窗口(可以和视口一样大,也可以更小),而文档是网站(可能比视口高得多或宽得多)。

对于分页媒体,初始包含块基于页面区域。页面区域可以通过 @page 规则设置。

总而言之,视口基本上是文档当前可见的部分。

视口大小是可变的

视口的宽度并不总是窗口的宽度。如果你在 Chrome 或 Firefox 中查询窗口和文档的宽度或高度,你可能会得到:

js
document.documentElement.clientWidth; /* 1200 */
window.innerWidth; /* 1200 */
window.outerWidth; /* 1200 */
js
document.documentElement.clientHeight; /* 800 */
window.innerHeight; /* 800 */
window.outerHeight; /* 900 */

有几个 DOM 属性可以帮助你查询视口大小以及其他类似的长度:

  • 文档元素的 Element.clientWidth 是文档在CSS 像素中的内部宽度,包括内边距(但不包括边框、外边距或垂直滚动条,如果存在的话)。这就是视口的宽度
  • Window.innerWidth 是浏览器窗口视口的宽度(以 CSS 像素为单位),包括(如果渲染的话)垂直滚动条。
  • Window.outerWidth 是浏览器窗口外部的宽度,包括所有的窗口界面元素

在一个实验中,观察到 innerWidthouterWidth 是相同的,但 outerHeightinnerHeight 高 100px。这是因为 outerHeight 包括了浏览器界面元素:测量是在一个地址栏和书签栏总高度为 100px 的浏览器上进行的,但窗口的左侧或右侧没有界面元素。

innerHeightinnerWidth 内的区域通常被认为是布局视口。浏览器界面元素不被视为视口的一部分。

放大后,Firefox 和 Chrome 都会报告 innerWidthclientWidth 新的 CSS 像素大小。outerWidthouterHeight 返回的值取决于浏览器:Firefox 报告以 CSS 像素为单位的新值,但 Chrome 返回以默认像素大小为单位的长度。放大后你可能会得到:

js
document.documentElement.clientWidth; /* 800 */
window.innerWidth; /* 800 */
window.outerWidth; /* 800 in Firefox, 1200 in chrome */
js
document.documentElement.clientHeight; /* 533 */
window.innerHeight; /* 533 */
window.outerHeight; /* 596 in Firefox, 900 in chrome */

视口最初是 1200 x 800 像素。放大后,视口变为 800 x 533 像素。这就是布局视口。带有以下样式的粘性页眉或页脚将分别固定在布局视口的顶部和底部。

css
body > header {
  position: fixed;
  top: 0;
}
body > footer {
  position: fixed;
  bottom: 0;
}

我们使用键盘放大时得到了 800 x 533 的尺寸。页眉和页脚紧贴着窗口的顶部和底部。但如果我们在平板电脑上进行双指缩放呢?如果手机上弹出了动态键盘呢?

布局视口和视觉视口

Web 中存在两个视口,即布局视口视觉视口。视觉视口是网页在浏览器中当前可见的部分,并且可以改变。当用户双指缩放页面、弹出动态键盘,或者当一个先前隐藏的地址栏变得可见时,视觉视口会缩小,但布局视口保持不变。

如上所述,固定的粘性页眉或页脚会粘在布局视口的顶部和底部,因此当我们用键盘放大时,它们仍然在视图中。如果你进行双指缩放,布局视口可能不会完全可见。如果你从布局视口的中间放大,内容会向四个方向扩展。如果你有粘性页眉或页脚,它们仍然会粘在布局视口的顶部或底部,但它们可能不会在设备屏幕的顶部和底部可见——而设备屏幕就是视觉视口。视觉视口是布局视口当前可见的部分。如果你向下滚动,你正在改变视觉视口的内容,并将布局视口的底部带入视图,从而显示粘性页脚,然后它将保持粘在底部。

视觉视口是屏幕的可视部分,不包括屏幕键盘、双指缩放区域之外的区域,或其他不随页面尺寸缩放的功能。视觉视口的大小与布局视口相同或更小。

对于包含 iframe、object 或外部 SVG 的页面,包含页面和每个被包含的文件都有其自己独特的窗口对象。只有顶层窗口有一个可能与布局视口不同的视觉视口。对于被包含的文档,视觉视口和布局视口是相同的。

CSS

上面描述的布局视口和视觉视口并不是你将遇到的唯二的视口。任何在布局视口内完全或部分显示的子视口都被视为视觉视口。

我们通常认为 widthheight 媒体查询是相对于浏览器窗口的宽度和高度的。它们实际上是相对于视口的,在主文档中视口是窗口,但在像 object、iframe 和 SVG 这样的嵌套浏览上下文中,它是元素父级的固有大小。在 CSS 中,我们也有基于视口大小的长度单位。一个 vh 单位是布局视口高度的 1%。同样,vw 单位是布局视口宽度的 1%。

<iframe>

<iframe> 内部,视觉视口是 iframe 的内部宽度和高度的大小,而不是父文档的大小。你可以为 iframe 设置任何高度和宽度,但整个文档可能不会都可见。

如果你在 iframe 文档的 CSS 中使用视口长度单位1vh 将是 iframe 高度的 1%,1vw 将是 iframe 文档宽度的 1%。

css
iframe {
  width: 50vw;
}

如果 iframe 被设置为 50vw,它将是我们上面例子中 1200px 父文档宽度的 50%,即 600px,其中 1vw6px。放大后,iframe 缩小到 400px1vw 变为 4px

iframe 文档中基于宽度的媒体查询是相对于 iframe 的视口的。

css
@media screen and (width >= 500px) {
  p {
    color: red;
  }
}

如果上述 CSS 包含在 iframe 中,当用户放大时,段落将变为红色,但此样式在未放大状态下不适用。

SVG

SVG 文档中,视口是 SVG 图像的可见区域。你可以为 <svg> 设置任何高度和宽度,但整个图像可能不会都可见。可见的区域称为视口。视口的大小可以使用 <svg> 元素的 width 和 height 属性来定义。

html
<svg height="300" width="400"></svg>

在这个例子中,视口的宽高比为 3:4,默认情况下是 400x300 单位,一个单位通常是一个 CSS 像素。

SVG 还有一个通过 viewBox 属性定义的内部坐标系统,这与本次视口的讨论无关。

如果你在 HTML 中包含一个 SVG 文件,SVG 的视口是初始包含块,即 SVG 容器的宽度和高度。在 SVG 的 CSS 中使用 @media 查询是相对于该容器的,而不是浏览器。

css
@media screen and (400px <= width <= 500px) {
  /* CSS goes here */
}

通常,当你编写上述媒体查询时,如果视口(通常是浏览器窗口)在 400px 和 500px 之间(含),则应用样式。SVG 中的宽度媒体查询是基于 SVG 所在的元素——如果源是 SVG 文件,则是 <img>;如果 SVG 直接包含在 HTML 中,则是 SVG 本身;或者如果父元素被分配了宽度,则是父元素——而不是视口的宽度。由于上述媒体查询在我们的 SVG 文件中,如果 SVG 容器在 400px 和 500px 之间,则应用 CSS。

JavaScript

Visual Viewport API 提供了一种查询和修改视觉视口属性的机制。

Viewport API 提供了一种查询和修改视觉视口属性的机制。

移动端视口

移动设备有各种形状和大小,屏幕具有不同的设备像素比。移动浏览器的视口是可以看到 Web 内容的窗口区域,它不一定与渲染页面的大小相同。移动浏览器在一个虚拟窗口或视口中渲染页面,通常为 980px,这通常比屏幕更宽,然后将渲染结果缩小以便可以一次性看到全部内容。然后用户可以平移和缩放以查看页面的不同区域。例如,如果一个移动屏幕的宽度为 320px,一个网站可能会以 980px 的虚拟视口进行渲染,然后它将被缩小以适应 320px 的空间,这取决于设计,对许多人(如果不是所有人)来说都是难以辨认的。为了告诉移动浏览器使用视口宽度而不是默认的 980px 作为屏幕宽度,开发者可以包含一个视口元标签,如下所示:

html
<meta name="viewport" content="width=device-width" />

width 属性控制视口的大小。最好将其设置为 device-width,即屏幕在 100% 缩放比例下的 CSS 像素宽度。还有其他属性,包括 maximum-scaleminimum-scaleuser-scalable,它们控制用户是否可以放大或缩小页面,但默认值对可访问性和用户体验是最好的,因此可以省略这些属性。

另见