(Translated by https://www.hiragana.jp/)
Visual Viewport API

The APIs introduced by this document provide authors with a way to determine and interact with the properties of the visual viewport.

Introduction

Some user agents have split their viewport into two conceptual viewports, colloquially known as the visual and layout viewports. This separation is useful in enabling a user agent (UA) with a small screen to allow the user to zoom in on parts of the page without causing the page to respond, for example, by obscuring the user's view with position: fixed elements. As another example, mobile UAs often provide an on-screen keyboard (OSK) for user input. Without the visual/layout split, a position: fixed element would be pushed up when the OSK is shown, obscuring the user's view. Informally, the layout viewport is what the web page uses when laying out its UI while the visual viewport is the box on the page that the user can currently see, accounting for transient UI features like pinch-zoom and the OSK.

The existing APIs provided by UAs are ambiguous about which viewport they're relative to. For example, document.scrollingElement.scrollLeft returns the scroll position of the visual viewport while document.scrollingElement.clientWidth returns the width of the layout viewport. getBoundingClientRect returns the rect relative to the layout viewport while positioning non-fixed elements relative to the layout viewport is difficult. This makes building UI that responds to scrolls across mobile and desktop UAs difficult. Worse still, there's no way for the developer to be notified when the visual viewport changes. For example, the only way to know when the user has zoomed is to poll or listen to touch events and continually check window.innerWidth.

The Visual Viewport API is designed to provide an explicit mechanism for developers to query and potentially modify the properties of the visual viewport. It also introduces events that allow the page to listen for changes in the visual viewport, allowing UX that explicitly wants to react to these changes to do so. For example, the page could keep a small text-formatting bar above the OSK.

Description

Definition of the visual viewport

The visual viewport is a kind of viewport whose scrolling area is another viewport, called the layout viewport.

In addition to scrolling, the visual viewport also allows applying a scale transform to its layout viewport. This transform is applied to the canvas of the layout viewport and does not affect its internal coordinate space.

The scale transform on the visual viewport is sometimes referred to as "pinch-zoom". Conceptually, this transform changes the size of the CSS reference pixel but changes the size of the layout viewport proportionally so that it acts like a magnifying glass, without causing reflow of the page's contents.

The magnitude of the scale transform is known as the visual viewport's scale factor

The window object has an associated visual viewport which is a VisualViewport object. Every visual viewport is associated with exactly one window object that never changes. The associated document of a visual viewport is the associated document of its associated window.

Extensions to the Window interface

This document extends the Window interface defined by [[HTML]].

            partial interface Window {
              [SameObject, Replaceable] readonly attribute VisualViewport? visualViewport;
            };
          
visualViewport
If the associated document is fully active, return the VisualViewport object associated with the window. Otherwise, return null.

Intuitively, the VisualViewport object is only returned and useful for a window whose Document is currently being presented. If a reference is retained to a VisualViewport whose associated Document is not being currently presented, the values in that VisualViewport must not reveal any information about the browsing context.

The VisualViewport interface

A VisualViewport object represents the visual viewport a document is being presented in if it is fully active. Each window in a page has its own distinct VisualViewport object.

A document being presented in any browsing context, including a nested browsing context, will have its own visual viewport. However, most user agents modify the visual viewport only on a top-level browsing context. The visual viewport in a nested browsing context is provided for ergonomic reasons.

For example: if a script retains a reference to a VisualViewport for an iframe, then navigates the iframe to another location, reading the integral values from the VisualViewport reference will return 0 because its window's Document is no longer being presented in a browsing content; it is no longer fully-active.

Unless otherwise stated, all returned values in this section are defined in CSS pixels.

            [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

If the visual viewport's associated document is not fully active, return 0.

Otherwise, return the offset of the left edge of the visual viewport from the left edge of the layout viewport.

offsetTop

If the visual viewport's associated document is not fully active, return 0.

Otherwise, return the offset of the top edge of the visual viewport from the top edge of the layout viewport.

pageLeft

If the visual viewport's associated document is not fully active, return 0.

Otherwise, return the offset of the left edge of the visual viewport from the left edge of the initial containing block of the layout viewport's document.

pageTop

If the visual viewport's associated document is not fully active, return 0.

Otherwise, return the offset of the top edge of the visual viewport from the top edge of the initial containing block of the layout viewport's document.

width

If the visual viewport's associated document is not fully active, return 0.

Otherwise, return the width of the visual viewport in CSS pixels. This value excludes the width of any rendered classic scrollbar that is fixed to the visual viewport.

A scrollbar that is fixed to the visual viewport is one that does not change size or location as the visual viewport is zoomed and panned. Because this value is in CSS pixels, when excluding the scrollbar width the UA must account for how large the scrollbar is in CSS pixels. That is, the amount excluded is lessened if the viewport is zoomed in and the scrollbars don't change size to the user.

height

If the visual viewport's associated document is not fully active, return 0.

Otherwise, return the height of the visual viewport in CSS pixels. This value excludes the height of any rendered classic scrollbar that is fixed to the visual viewport.

Because both the width and height attributes are expressed in CSS pixels, increasing either page-zoom or pinch-zoom will cause these values to shrink.

scale
Returns the visual viewport's scale factor. It can be computed using the following algorithm:
Although often referred to as the pinch-zoom scale factor, it can be affected through means other than pinch-zooming. e.g. When the user agent centers and zooms in on a focused input element.
  1. If the visual viewport's associated document is not fully active, return 0 and abort these steps.

  2. If there is no output device, return 1 and abort these steps.

  3. Let CSS pixel size be the size of a CSS reference pixel scaled by the current page zoom and the scale factor of the visual viewport associated with this window

  4. Let device pixel size be the size of a device pixel of the output device.

  5. Let device independent pixel size be the product of device pixel size and the devicePixelRatio

    Visual viewport scale (e.g. pinch-zoom) does not affect the devicePixelRatio.

  6. Return the result of dividing the CSS pixel size by the device independent pixel size.

segments
The viewport segments property is currently in development and considered experimental.

Returns an array of DOMRects that represent the dimensions of each existing viewport segment.

A viewport segment represents the region of the visual viewport that resides on a separate display or logical display region. When the visual viewport spans across some number of physical features of a device, these features in turn convey a logical separation of the space available for content.

segments is null when there is only a single viewport segment. Returns null when called from within an iframe context.

Based on the data returned for each viewport segment, developers will be able to infer the number of hinges available as well as the hinge orientation. The browser window can be moved/resized such that the number of segments and/or their dimensions change. In these cases, resize events will fire at which point authors should re-query this property, as the returned FrozenArray is just a snapshot of the current state.
onresize
Event handler attribute for the resize event.
onscroll
Event handler attribute for the scroll event.

Additions to the CSSOM-VIEW Events section

Append following step as the last step of run the resize steps:

  1. If doc's associated Window's VisualViewport's scale, width, or height properties have changed since the last time these steps were run, [=fire an event=] named resize at the doc's associated Window's VisualViewport.

Replace step 1.1 of run the scroll steps with:

  1. If target is a Document, fire an event named scroll that bubbles at target.

    If target is a Document, [=fire an event=] named scroll that bubbles at target. Then, [=fire an event=] named scroll at the VisualViewport of the Document's associated Window.