Browser compatibility — viewports

Last major update on 16 October 2016.

Here’s the inevitable compatibility table that goes with my viewport research. It treats the viewports themselves as well as some related items.

position: fixed was moved to the CSS test pages.

Definitions

See this blog post for my current viewport definitions, and A tale of two viewports for explanations of CSS and device pixels. See the visualisation for a clear idea of what the viewports are in modern browsers.

Viewport properties

This table looks into the properties that are necessary to read out useful information about the three viewports and the two types of pixels.

Test page.

[an error occurred while processing this directive] [an error occurred while processing this directive] [an error occurred while processing this directive]
screen.width and screen.height

Dimensions of the ideal layout viewport.

Por­trait Phy­sical Yes Yes Phy­sical Yes Phy­sical Yes Yes Lay­out Yes

screen.width should return the dimensions of the ideal viewport. The older implementation returns the number of physical device pixels, but that’s now seen as wrong.

Physical
Gives the physical screen dimensions.
Portrait
Always gives the portrait values even when in landscape.
Layout
Gives the layout viewport dimensions, except that the toolbars are counted as well.
window.innerWidth and window.innerHeight

Dimensions of the visual viewport in CSS pixels.

Yes Yes Yes Yes Yes No Yes
documentElement. clientWidth and documentElement. clientHeight

Dimensions of the layout viewport in CSS pixels.

Yes Yes inner Yes Yes Yes Yes
inner
Equal to window.innerWidth/Height.
devicePixelRatio

Physical screen size divided by ideal layout viewport

Yes Yes Yes Yes Yes Yes

Opera Mini’s values are weird (2.1), but correct.

window.pageX/YOffset

The visual viewport’s scrolling offset relative to the document

Yes Yes Yes Yes Yes 0 Yes

window.scrollX/Y gives exactly the same values. I think we should change one of them to the scrolling offset of the layout viewport.

Mouse/touch coordinates

Test page.

[an error occurred while processing this directive] [an error occurred while processing this directive]
clientX/Y

In CSS pixels, relative to the visual viewport

Yes Yes Yes Layout Yes L Yes Untest­able L Yes
clientX/Y = pageX/Y - window.pageX/YOffset

(visual)

clientX/Y = pageX/Y + document.documentElement.getBoundingClientRect().left/top

(layout)

In browsers that don’t have a modern layout viewport window.pageX/YOffset is equal to -getBounding().left/top, and the coordinates relative to the layout and visual viewport seem to be the same. (In fact, the document element’s offset is calculated relative to the visual viewport.)

Thus many browsers do not allow us to read out the position of the layout viewport because the layout viewport is equal to the top of the document. These browsers are counted as supporting clientX/Y relative to the visual viewport.

See this app for a visualisation of the modern layout viewport.

Layout or L
Relative to the layout viewport. New definition.
pageX/Y

In CSS pixels, relative to the document

Yes Yes Yes Yes Yes Untest­able Yes
screenX/Y

In CSS pixels, relative to the screen.

Don’t use
page client 0 Yes client Yes 0 Yes client phy­sical client Untest­able Incor­rect client
screenX/Y = (pageX/Y - window.pageX/YOffset) * 
(document.documentElement.clientWidth/Height / window.innerWidth/Height) - toolbarOffset toolbarOffset = screen.height - (window.innerHeight * (document.documentElement.clientWidth / window.innerWidth)

Toolbar offset is the offset of all toolbars, even though we should only count the top ones. Unfortunately I don’t think it’s possible to get the height of only the top ones. So this formula only works perfectly if the browser doesn’t have or removes the bottom toolbar.

And screen.height gives the wrong information in a few browsers. I’m working on that.

client
Equal to clientX/Y
page
Equal to pageX/Y
physical
In device pixels, relative to the visual viewport
  • I don’t understand IE11’s/Edge’s values.

getBoundingClientRect()

element.getBoundingClientRect().left/top returns the position of the element relative to the viewport. But WHICH viewport?

Test pages for a regular element and for the documentElement.

[an error occurred while processing this directive] [an error occurred while processing this directive]
getBoundingClientRect().left/top

Position of the element relative to the visual viewport.

Yes Yes Yes Layout Yes lay­out Yes lay­out Yes l Yes
Layout or l
Relative to the layout viewport (which in Opera Mini equals the document)

The layout definition will likely stay around, though I’m not sure what the other browsers will do.

Visual Viewport API

Chrome added a visual viewport API, but not a layout viewport API. First made public in Chrome 61. Example:

window.visualViewport.width
[an error occurred while processing this directive] [an error occurred while processing this directive]
offsetLeft/Top

Position of the visual viewport relative to the layout viewport.

No No No Yes No No No
pageLeft/Top

Position of the visual viewport relative to the document.

No No No Yes No No No
width/height

Dimensions of the visual viewport.

No No No Yes No No No
scale

Zoom level of the visual viewport relative to the layout viewport. (1 = same size)

No No No Yes No No No

Meta viewport

Below you find a series of tests aimed at changing the width of the meta viewport after page load.

There’s also the main research page for the meta viewport, which gives a lot more details.

Test page

[an error occurred while processing this directive] [an error occurred while processing this directive]
Basics

Sets the dimensions of the layout viewport.

Yes Yes Yes No Yes Yes

The Chromium WebViews always apply device-width, regardless of the content of the meta viewport tag — and even when it’s not there at all.
Firt told me it’s because native Android apps give you the opportunity to set the layout viewport size. Which kind-of makes sense, although the iOS WebView does support meta viewports normally.

Change immediately

Change the tag directly after it’s been written into the page

Yes Yes See note Yes No Yes Yes
Change later

Change the tag once the page has been loaded

Yes Yes See note Yes No Yes Yes
Remove

Remove the tag entirely

No No No No No No

Android WebKit WebView: It obeys the initial meta viewport (380px), but any change to the tag sets the layout viewport to the ideal values, even though window.innerWidth/Height and document.document­Element.clientWidth/Height show the values we just wrote into the meta viewport tag. So it’s very confused.
More importantly, this behaviour is different from the regular Android WebKit browser.

Tested browsers

[an error occurred while processing this directive]