本文档引入的 API 为开发者提供了一种方法,用于确定和交互视觉视口的属性。

已停止使用的文档

本文档的工作已停止。本规范中描述的功能已合并到 [[CSSOM-View]] 规范中。

介绍

一些用户代理将其视口分为两个概念性视口,通常称为视觉视口布局视口。这种分离对于使具有小屏幕的用户代理(UA)能够允许用户放大页面的部分而不导致页面响应非常有用,例如,通过固定定位的元素遮挡用户的视图。另一个例子是,移动 UA 通常为用户输入提供一个屏幕键盘(OSK)。如果没有视觉/布局分离,当显示 OSK 时,position: fixed 元素会被推上去,从而遮挡用户的视图。非正式地,布局视口是网页在布局其 UI 时使用的,而视觉视口是用户当前可以看到的页面框,考虑到诸如捏合缩放和 OSK 等临时 UI 特性。

用户代理提供的现有 API 对它们相对于哪个视口是模糊的。例如,document.scrollingElement.scrollLeft 返回视觉视口的滚动位置,而 document.scrollingElement.clientWidth 返回布局视口的宽度。getBoundingClientRect 返回相对于布局视口的矩形,而相对于布局视口定位非固定元素则很困难。这使得构建能够响应移动和桌面 UA 滚动的 UI 变得困难。更糟糕的是,当视觉视口发生变化时,开发者无法收到通知。例如,知道用户何时缩放的唯一方法是轮询或监听触摸事件并不断检查 window.innerWidth

视觉视口 API 旨在为开发者提供一种明确的机制,用于查询和可能修改视觉视口的属性。它还引入了允许页面监听视觉视口变化的事件,从而使明确希望对这些变化做出反应的用户体验成为可能。例如,页面可以在 OSK 上方保持一个小的文本格式化栏。

描述

视觉视口的定义

视觉视口 是一种 视口,其 滚动区域 是另一个 视口,称为 布局视口

除了滚动之外,视觉视口 还允许对其 布局视口 应用缩放变换。此变换应用于 布局视口 的画布,并且不会影响其内部坐标空间。

视觉视口上的缩放变换有时被称为“捏合缩放”。从概念上讲,此变换改变了 CSS 参考像素 的大小,但会按比例改变 布局视口 的大小,使其像放大镜一样工作,而不会导致页面内容的重排。

缩放变换的大小称为视觉视口的 缩放因子

窗口 对象有一个 关联的 视觉视口,它是一个 VisualViewport 对象。每个 视觉视口 都与一个永不改变的 窗口 对象关联。视觉视口关联文档 是其 关联的 窗口的 关联文档

Window 接口的扩展

本文档扩展了 [[HTML]] 中定义的 Window 接口。

            partial interface Window {
              [SameObject, Replaceable] readonly attribute VisualViewport? visualViewport;
            };
          
visualViewport
如果 关联文档完全活动的,则返回与 窗口 关联的 VisualViewport 对象。否则,返回 null。

直观地说,VisualViewport 对象仅在其 窗口文档当前正在呈现时返回并有用。如果保留了对 VisualViewport 的引用,而其 关联文档当前未被呈现,则该 VisualViewport 中的值不得透露任何关于 浏览上下文的信息。

VisualViewport 接口

一个 VisualViewport 对象表示一个 文档正在被呈现的 视觉视口,如果它是 完全活动的。页面中的每个 窗口都有其独特的 VisualViewport 对象。

在任何浏览上下文中呈现的文档,包括嵌套的浏览上下文,都将拥有其自己的视觉视口。然而,大多数用户代理仅在顶级浏览上下文中修改视觉视口。在嵌套浏览上下文中的视觉视口是为了方便而提供的。

例如:如果脚本保留了对 iframe 的 VisualViewport 的引用,然后将 iframe 导航到另一个位置,从该 VisualViewport 引用读取的值将返回 0,因为其窗口的文档不再在浏览内容中呈现;它不再是完全活动的。

除非另有说明,本节中返回的所有值均以 CSS 像素 定义。

            [Exposed=Window]
            interface VisualViewport : EventTarget {
              readonly attribute double offsetLeft;
              readonly attribute double offsetTop;

              readonly attribute double pageLeft;
              readonly attribute double pageTop;

              readonly attribute double width;
              readonly attribute double height;

              readonly attribute double scale;

              readonly attribute FrozenArray<DOMRect>? segments;

              attribute EventHandler onresize;
              attribute EventHandler onscroll;
            };
          
offsetLeft

如果 视觉视口关联文档不是 完全活动的,返回 0。

否则,返回 视觉视口左边缘与 布局视口左边缘的偏移量。

offsetTop

如果 视觉视口关联文档不是 完全活动的,返回 0。

否则,返回视觉视口顶部边缘与 布局视口顶部边缘的偏移量。

pageLeft

如果 视觉视口关联文档不是 完全活动的,返回 0。

否则,返回视觉视口左边缘与 布局视口初始包含块左边缘的偏移量。

pageTop

如果 视觉视口关联文档不是 完全活动的,返回 0。

否则,返回视觉视口顶部边缘与 布局视口初始包含块顶部边缘的偏移量。

width

如果 视觉视口关联文档不是 完全活动的,返回 0。

否则,返回视觉视口的宽度(以 CSS 像素为单位)。此值不包括固定到视觉视口的任何渲染的 经典滚动条 的宽度。

固定到视觉视口的滚动条是指在视觉视口缩放和平移时,其大小或位置不会改变的滚动条。 由于此值以 CSS 像素为单位,因此在排除滚动条宽度时,用户代理必须考虑滚动条在 CSS 像素中的大小。也就是说,如果视口被放大且滚动条对用户的大小未改变,则排除的量会减少。

height

如果 视觉视口关联文档不是 完全活动的,返回 0。

否则,返回视觉视口的高度(以 CSS 像素为单位)。此值不包括固定到视觉视口的任何渲染的经典滚动条的高度。

由于宽度和高度属性均以 CSS 像素表示,增加页面缩放或捏合缩放都会导致这些值缩小。

scale
返回 视觉视口缩放因子。可以使用以下算法计算:
虽然通常被称为捏合缩放因子,但它也可以通过其他方式影响,例如当用户代理居中并放大一个聚焦的输入元素时。
  1. 如果 视觉视口关联文档不是 完全活动的,返回 0 并中止这些步骤。

  2. 如果没有输出设备,返回 1 并中止这些步骤。

  3. CSS 像素大小 为 CSS 参考像素 的大小,按当前 页面缩放和与此 窗口关联的 视觉视口缩放因子 缩放。

  4. 设备像素大小 为输出设备的设备像素大小。

  5. 设备无关像素大小设备像素大小devicePixelRatio 的乘积。

    视觉视口缩放(例如捏合缩放)不会影响 devicePixelRatio。

  6. 返回 CSS 像素大小 除以 设备无关像素大小 的结果。

segments
视口段属性目前正在开发中,并被认为是实验性的。

返回一个 DOMRects 数组,表示每个现有视口段的尺寸。

视口段表示视觉视口中位于单独显示器或逻辑显示区域的区域。 当视觉视口跨越设备的一些物理特性时,这些特性反过来传达了可用于内容的空间的逻辑分离。

当只有一个视口段时,segments 为 null。从 iframe 上下文中调用时返回 null。

根据每个视口段返回的数据,开发者可以推断可用的铰链数量以及铰链方向。 浏览器窗口可以移动/调整大小,从而改变段的数量和/或其尺寸。在这些情况下,将触发 resize 事件,此时作者应重新查询此属性,因为返回的 FrozenArray 只是当前状态的快照。
onresize
用于 resize 事件的事件处理程序属性。
onscroll
用于 scroll 事件的事件处理程序属性。

对 CSSOM-VIEW Events 部分的补充

将以下步骤追加为 运行调整大小步骤 的最后一步:

  1. 如果文档的关联 WindowVisualViewportscalewidthheight 属性自上次运行这些步骤以来发生了变化,则在文档的关联 WindowVisualViewport 上 [=触发一个事件=],事件名称为 resize

运行滚动步骤 的第 1.1 步替换为:

  1. 如果目标是一个文档,则在目标上触发一个冒泡的名为 scroll 的事件。

    如果 target 是一个 Document,则在 target 上 [=触发一个事件=],事件名称为 scroll,并冒泡。然后,在文档的关联 WindowVisualViewport 上 [=触发一个事件=],事件名称为 scroll