视觉视口 API

**视觉视口 API** 提供了一种明确的机制来查询和修改窗口视觉视口的属性。视觉视口是屏幕的视觉部分,不包括屏幕键盘、捏合缩放区域之外的区域或任何其他不随页面尺寸缩放的屏幕构件。

概念和用法

移动 Web 包含两个视口,布局视口和视觉视口。布局视口覆盖页面上的所有元素,而视觉视口是屏幕上实际可见的部分。当用户捏合缩放页面时,视觉视口会缩小,但布局视口保持不变。屏幕键盘 (OSK) 等用户界面功能可能会缩小视觉视口,而不会影响布局视口。

当网页元素需要在屏幕上可见,而不管网页的可见部分如何时会发生什么?例如,如果您需要一组图像控件始终保持在屏幕上,而不管设备的捏合缩放级别如何?当前浏览器在处理此问题的方式各不相同。视觉视口允许 Web 开发人员通过相对于屏幕上显示的内容定位元素来解决此问题。

要访问窗口的视觉视口,您可以从window.visualViewport属性获取VisualViewport对象。该对象包含一组描述视口的属性。它还添加了三个事件,resizescrollscrollend,分别在视觉视口调整大小、滚动和完成滚动操作时触发。

前两个事件允许您相对于视觉视口滚动或缩放时定位元素,这些元素通常固定到布局视口。scrollend事件允许您在滚动操作完成后更新元素。例如,您可以使用这些事件将元素固定到视觉视口中,因为它被捏合缩放和滚动,并在滚动结束时更新它。

接口

VisualViewport

表示给定窗口的视觉视口。窗口的VisualViewport对象提供有关视口位置和大小的信息,并接收resizescrollscrollend事件。

对其他接口的扩展

Window.visualViewport 只读

对窗口VisualViewport对象的只读引用。如果此属性不存在,则表示 API 不受支持。

示例

我们的视觉视口 API示例提供了一个关于不同视觉视口功能(包括三种事件类型)如何工作的基本演示。在支持的桌面和移动浏览器中加载页面,然后尝试在页面上滚动和捏合缩放。在resizescroll时,信息框会重新定位以保持相对于视觉视口的相同位置,并且它显示的视口和滚动信息也会更新。此外,在resizescroll时,我们更改框的颜色以指示正在发生某些事情,并在scrollend时将其更改回。

您会发现,在桌面浏览器上,当窗口滚动时,Window.scrollXWindow.scrollY的值会更新——视觉视口位置不会改变。但在移动浏览器上,VisualViewport.offsetLeftVisualViewport.offsetTop的值通常会更新——通常是视觉视口发生变化,而不是窗口位置。

示例 HTML 如下所示。信息框由一个带有idoutput<div>表示。

html
<p id="instructions">
  Try scrolling around and pinch-zooming to see how the reported values change.
</p>
<div id="output">
  <p id="visual-info"></p>
  <hr />
  <p id="window-info"></p>
</div>

为了简洁起见,我们不会解释示例的 CSS——它对于理解演示并不重要。您可以在上面的示例链接中查看它。

在 JavaScript 中,我们首先获取对信息框的引用,这些信息框将在页面缩放和滚动时更新,以及其中包含的两个段落。第一个将包含报告的VisualViewport.offsetLeftVisualViewport.offsetTop值,而第二个将包含报告的Window.scrollXWindow.scrollY值。

js
const output = document.getElementById("output");
const visualInfo = document.getElementById("visual-info");
const windowInfo = document.getElementById("window-info");

接下来,我们定义事件触发时将运行的两个关键函数

  • scrollUpdater()将在resizescroll时触发:此函数通过查询VisualViewport.offsetTopVisualViewport.offsetLeft属性并将它们的值用于更新相关内嵌属性的值来更新信息框相对于视觉视口的位置。我们还更改信息框的背景颜色以指示正在发生某些事情,并运行updateText()函数以更新框中显示的值。
  • scrollEndUpdater()函数将在scrollend时触发:这会将信息框恢复到其原始颜色,并运行updateText()函数以确保在scrollend时显示最新值。
js
const scrollUpdater = () => {
  output.style.top = `${visualViewport.offsetTop + 10}px`;
  output.style.left = `${visualViewport.offsetLeft + 10}px`;
  output.style.background = "yellow";
  updateText();
};

const scrollendUpdater = () => {
  output.style.background = "lime";
  updateText();
};

updateText()函数如下所示——它将第一个段落的HTMLElement.innerText设置为显示当前的VisualViewport.offsetLeftVisualViewport.offsetTop值,并将第二个段落的HTMLElement.innerText设置为显示当前的Window.scrollXWindow.scrollY值。在定义updateText()后,我们立即调用它,以便信息框在页面加载时正确显示。

js
function updateText() {
  visualInfo.innerText = `Visual viewport left: ${visualViewport.offsetLeft.toFixed(2)}
    top: ${visualViewport.offsetTop.toFixed(2)}`;
  windowInfo.innerText = `Window scrollX: ${window.scrollX.toFixed(2)}
    scrollY: ${window.scrollY.toFixed(2)}`;
}

updateText();

**注意:**我们使用Number.toFixed()方法将所有值截断为两位小数,因为某些浏览器将它们显示为子像素值,可能包含大量小数位。

现在,我们在视觉视口和Window对象上设置事件处理程序属性,以便在移动设备和桌面设备上在适当的时间运行关键函数

  • 我们在window上设置处理程序,以便信息框位置和内容在常规窗口滚动操作中更新,例如在桌面浏览器上滚动页面时。
  • 我们在visualViewport上设置处理程序,以便信息框位置和内容在视觉视口滚动/缩放操作中更新,例如在移动浏览器上滚动和捏合缩放页面时。
js
visualViewport.onresize = scrollUpdater;
visualViewport.onscroll = scrollUpdater;
visualViewport.onscrollend = scrollendUpdater;
window.onresize = scrollUpdater;
window.onscroll = scrollUpdater;
window.onscrollend = scrollendUpdater;

scrollUpdater()将在resizescroll时触发,而scrollEndUpdater()将在scrollend时触发。

规范

规范
CSSOM 视图模块
# visualViewport

浏览器兼容性

api.VisualViewport

BCD 表格仅在启用 JavaScript 的浏览器中加载。

api.Window.visualViewport

BCD 表格仅在启用 JavaScript 的浏览器中加载。