This feature is well established and works across many devices and browser versions. It’s been available across browsers since August 2021.
* Some parts of this feature may have varying levels of support.
The VisualViewport interface of the Visual Viewport API represents the visual viewport for a given window. For a page containing iframes, each iframe, as well as the containing page, will have a unique window object. Each window on a page will have a unique VisualViewport representing the properties associated with that window.
You can get a window's visual viewport using Window.visualViewport.
Note: Only the top-level window has a visual viewport that's distinct from the layout viewport. Therefore, it's generally only the VisualViewport object of the top-level window that's useful. For an <iframe>, visual viewport metrics like VisualViewport.width always correspond to layout viewport metrics like document.documentElement.clientWidth.
Also inherits properties from its parent interface, EventTarget.
VisualViewport.offsetLeft Read only
Returns the offset of the left edge of the visual viewport from the left edge of the layout viewport in CSS pixels.
VisualViewport.offsetTop Read only
Returns the offset of the top edge of the visual viewport from the top edge of the layout viewport in CSS pixels.
VisualViewport.pageLeft Read only
Returns the x coordinate of the visual viewport relative to the initial containing block origin of the top edge in CSS pixels.
VisualViewport.pageTop Read only
Returns the y coordinate of the visual viewport relative to the initial containing block origin of the top edge in CSS pixels.
VisualViewport.width Read only
Returns the width of the visual viewport in CSS pixels.
VisualViewport.height Read only
Returns the height of the visual viewport in CSS pixels.
VisualViewport.scale Read only
Returns the pinch-zoom scaling factor applied to the visual viewport.
Also inherits methods from its parent interface, EventTarget.
Listen to these events using addEventListener() or by assigning an event listener to the relevant oneventname property of this interface.
resizeFired when the visual viewport is resized. Also available via the onresize property.
scrollFired when the visual viewport is scrolled. Also available via the onscroll property.
scrollendFired when a scrolling operation on the visual viewport ends. Also available via the onscrollend property.
This example, taken from the Visual Viewport README, shows how to write a bit of code that will hide an overlaid box (which might contain an advert, say) when the user zooms in. This is a nice way to improve the user experience when zooming in on pages. A live sample is also available.
const bottomBar = document.getElementById("bottom-bar");
const viewport = window.visualViewport;
function resizeHandler() {
bottomBar.style.display = viewport.scale > 1.3 ? "none" : "block";
}
window.visualViewport.addEventListener("resize", resizeHandler);
This example, also taken from the Visual Viewport README, shows how to use this API to simulate position: device-fixed, which fixes elements to the visual viewport. A live sample is also available.
const bottomBar = document.getElementById("bottom-bar");
const viewport = window.visualViewport;
function viewportHandler() {
const layoutViewport = document.getElementById("layoutViewport");
// Since the bar is position: fixed we need to offset it by the visual
// viewport's offset from the layout viewport origin.
const offsetLeft = viewport.offsetLeft;
const offsetTop =
viewport.height -
layoutViewport.getBoundingClientRect().height +
viewport.offsetTop;
// You could also do this by setting style.left and style.top if you
// use width: 100% instead.
bottomBar.style.transform = `translate(${offsetLeft}px, ${offsetTop}px) scale(${
1 / viewport.scale
})`;
}
window.visualViewport.addEventListener("scroll", viewportHandler);
window.visualViewport.addEventListener("resize", viewportHandler);
Note: This technique should be used with care; emulating position: device-fixed in this way can result in the fixed element flickering during scrolling.
| Specification |
|---|
| CSSOM View Module> # the-visualviewport-interface> |
| Desktop | Mobile | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari on IOS | Samsung Internet | WebView Android | WebView on iOS | |
VisualViewport |
61 | 79 | 91 | 48 | 13 | 61 | 68 | 45 | 13 | 8.0 | 61 | 13 |
height |
61 | 79 | 91 | 48 | 13 | 61 | 68 | 45 | 13 | 8.0 | 61 | 13 |
offsetLeft |
61 | 79 | 91 | 48 | 13 | 61 | 68 | 45 | 13 | 8.0 | 61 | 13 |
offsetTop |
61 | 79 | 91 | 48 | 13 | 61 | 68 | 45 | 13 | 8.0 | 61 | 13 |
pageLeft |
61 | 79 | 91 | 48 | 13 | 61 | 68 | 45 | 13 | 8.0 | 61 | 13 |
pageTop |
61 | 79 | 91 | 48 | 13 | 61 | 68 | 45 | 13 | 8.0 | 61 | 13 |
resize_event |
6261–62Theonresize event handler property is not supported. |
79 | 91 | 4948–49Theonresize event handler property is not supported. |
13 | 6261–62Theonresize event handler property is not supported. |
68 | 4645–46Theonresize event handler property is not supported. |
13 | 8.0 | 6261–62Theonresize event handler property is not supported. |
13 |
scale |
61 | 79 | 91 | 48 | 13 | 61 | 68 | 45 | 13 | 8.0 | 61 | 13 |
scroll_event |
6261–62Theonscroll event handler property is not supported. |
79 | 91 | 4948–49Theonscroll event handler property is not supported. |
13 | 6261–62Theonscroll event handler property is not supported. |
68 | 4645–46Theonscroll event handler property is not supported. |
13 | 8.0 | 6261–62Theonscroll event handler property is not supported. |
13 |
scrollend_event |
126 | 126 | No | 112 | No | 126 | No | 83 | No | 28.0 | 126 | No |
width |
61 | 79 | 91 | 48 | 13 | 61 | 68 | 45 | 13 | 8.0 | 61 | 13 |
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/VisualViewport