Skip to content

Latest commit

 

History

History
154 lines (105 loc) · 7.3 KB

visual-viewport.md

File metadata and controls

154 lines (105 loc) · 7.3 KB

The Visual Viewport

Definition

From the CSSOM Specification

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 may also apply 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.

From MDN:

The portion of the viewport that is currently visible is called the visual viewport

The Visual Viewport can be smaller than the layout viewport, such as when the user has pinched-zoomed

Visualization

To visualize it, authors can get sizing and positioning info of the Visual Viewport through the Visual Viewport API

let {
    width,
    height,
    scale,
    offsetTop,
    offsetLeft,
    pageLeft,
    pageTop,
} = window.visualViewport;

These values are:

  • width / height = Width and Height of the Visual Viewport
  • offsetTop / offsetLeft = Distance from edges of the Visual Viewport to edges of the Layout Viewport
  • pageTop / pageLeft = Distance from edges of the Visual Viewport to edges of the ICB
  • scale = The scale factor (default: 1)

Using a tab more JS, these values can be synced to Custom Properties which you can use to position an element that outlines this Visual Viewport

document.documentElement.style.setProperty('--vvw', `${vvv.width}px`);
document.documentElement.style.setProperty('--vvh', `${vvv.height}px`);
document.documentElement.style.setProperty('--vvpt', `${vvv.pageTop}px`);
document.documentElement.style.setProperty('--vvpl', `${vvv.pageLeft}px`);
document.documentElement.style.setProperty('--vvot', `${vvv.offsetTop}px`);
document.documentElement.style.setProperty('--vvol', `${vvv.offsetLeft}px`);
document.documentElement.style.setProperty('--vvz', vvv.scale);

Depending on wether you are using position: absolute or position: fixed, you need to use these values differently:

#visualviewport {
    box-sizing: border-box;
	border: 8px solid;
	border-image: repeating-linear-gradient(45deg, orange, orange 10px, transparent 10px, transparent 20px) 10;
}

#visualviewport {
	position: absolute;
	top: var(--vvpt, 0px);
	left: var(--vvpl, 0px);
	width: var(--vvw, 100%);
	height: var(--vvh, 100vh);
}
#visualviewport {
    box-sizing: border-box;
	border: 8px solid;
	border-image: repeating-linear-gradient(45deg, orange, orange 10px, transparent 10px, transparent 20px) 10;
}

#visualviewport {
	position: fixed;
	top: var(--vvot, 0px);
	left: var(--vvol, 0px);
	width: var(--vvw, 100%);
	height: var(--vvh, 100vh);
	right: var(--vvol, 0px) + var(--vvw, 0px);
	bottom: var(--vvol, 0px) + var(--vvh, 0px);
}

👉 Try it out: Visual Viewport

Findings

💡 These findings are a textual representation of the test results table.

Size

As mentioned above, the Visual Viewport API can be used for this. Note that the size of Visual Viewport will be equal to or less than the Layout Viewport

Illustration Illustration Illustration

Effect of scrolling

The Visual Viewport updates nicely as you scroll and shifts down with the scroll position.

Illustration

When UA UI Elements expand/contract is also updates accordingly, except in Edge on Android where there’s a few pixels missing. This bug is corrected as soon as you stop the gesture (i.e. lift up your finger), then the correct values are flushed.

Illustration Illustration

Effect of scrollbars

The presence of Classic Scrollbars take away space from the Visual Viewport

Effect of pinch-zoom

The Visual Viewport updates nicely as you pinch zoom

Illustration

In Safari on Desktop the values do not update immediately as you pinch-zoom, but are only updated when the gesture is finished (i.e. lifting up your fingers).

When you over pinch-zooming out in browsers that allow this (i.e. all based on WebKit) something funky happens with the position and dimensions of the Visual Viewport:

  • Its position gets anchored to 0,0 of the canvas. This origin moves between the top-left edge of the Large and Small Viewport as you move around.
  • The width/height is measured from that 0,0 origin (which can move) to the right/bottom edge of the Layout Viewport

👀 See Screenshot 1 of Safari on iOS and Screenshot 2 of Safari on iOS

👀 See Recording of Safari on iOS

Effect of the Virtual Keyboard

See Virtual Keyboard: Findings.

Effect of Overscrolling / Bouncy Scroll

When overscrolling, WebKit allows negative values for window.scrollX and window.scrollY. This is the only engine to expose this. While doing so, the values for the Visual Viewport’s pageTop and pageLeft also become negative, while its height and width remain the same size. Because of this, the visualization of the Visual Viewport can get clipped by the ICB which does bounce with the rubber banding effect

👀 See Recording of Safari on Desktop and Recording of Safari on iOS

Other engines that do not allow negative values for window.scrollX and window.scrollY as it has a rubber banding effect going on – i.e. Chrome on macOS and Firefox on macOS – follow the same behavior as the ICB: the bounce with the effect. The values for the height and width remain the same as it rubber bands.

👀 See Recording of Firefox on Desktop and Recording of Chrome on Desktop

In engines that keep the Layout Viewport in place as the browser rubber bands the values for offsetTop and offsetLeft remain 0.

👀 See Recording of Firefox on Desktop and Recording of Chrome with flag on Desktop

Issues

We are tracking issues using the label Visual Viewport