Chrome change breaks the visual viewport

Last week I found out that as of Chrome 48 window.innerWidth/Height no longer exposes the dimensions of the visual viewport. Instead, it now exposes the dimensions of the layout viewport, and is thus a copy of document.documentElement.clientWidth/Height.

I’m not happy with this change. So it’s time for me to don my ceremonial robes as Guardian of the Viewports and ask the Chrome team to revert this change and restore the visual viewport to its rightful place.

There are three reasons why I think Chrome is making a mistake here:

  1. It breaks the web. ALL other browsers support this.
  2. It takes one simple trick for web developers to avoid problems with these properties, so the change is not necessary.
  3. It chokes innovation, in particular zoom-based layouts.

Here are the relevant documents: first the bug report that I was pointed to, then a closely related explanation of why window.scrollX/Y should be changed, and finally an Intent to Ship discussion.

Update: It seems likely that this change will be reverted in 49 or 50. Thank you, Chrome team, for listening to our feedback.

Breaking the web

The problem with the viewports is not browser support. All browsers — and when I say all I mean ALL; not just Safari, Firefox, Edge, and, until recently, Chrome, but also the ones you never heard of, some of which are based on earlier Chromium versions — support window.innerWidth/Height as the dimensions of the visual viewport. Only the proxy browsers have problems here because they aren’t equipped to track user zoom level.

Such total agreement among browser vendors is fairly rare. I don’t like it when browsers deliberately break web standards, even when they’re only de-facto ones. The Chrome team is guilty of this in this particular instance.

I spent considerable time in 2010-1 reaching out to all kinds of browser vendors and convincing them to implement window.innerWidth/Height correctly — and in the end they all did. I don’t like my work being for naught — and that’s my personal stake in this affair.

It’s true that none of this is in a specification, but that’s W3C’s fault. The mobile viewports are notoriously under-specced — the current spec addresses only some points that are unimportant to web developers. A few months back I published an overview of what the spec ought to be, based on actual browser behaviour. window.innerWidth/Height is in there because it works everywhere.

Anyway, Exhibit A: Chrome breaks the web..

What’s the problem?

Still, the Chrome team wouldn’t make such a change just to break the web. The intent to change discussion states the reasons and purpose of the change:

This particular change is about whether pinch zoom is really completely transparent to JavaScript or not. [...] We've now learned this hurts behavior on some sites when doing pinch zoom and causes a bunch of confusion when some of the CSS OM APIs reflect the visual viewport while others reflect the layout viewport (which are different only under pinch-zoom). [...]

The bottom line for compatibility here is that it's already nearly impossible to build an app that responds to pinch zoom in some custom way (especially across browsers). We see pinch zoom as really a browser UI feature for coping with legacy content, not a core part of the web platform (as evidenced by most modern mobile sites disabling pinch zoom).

Building an app that responds to pinch zoom is actually quite possible: poll the visual viewport size every 100 milliseconds, and change your layout when the dimensions turn out to have changed. Works in all browsers. Of course the app would have absolutely horrid performance, and I’m not saying this is a good idea. Still — not at all impossible. I’ll get back to this. (And we need a zoom event, so that we don’t have to poll every 100ms. I’ve been saying this for years, but nobody wants to listen.)

The core problem seems to be that web developers get confused by the visual and layout viewports, and accidentally use properties that reflect the visual viewport when they mean to use the layout viewport.

I don’t doubt that this is happening in practice, but I’d say it’s the web developers’ fault for not testing their sites on mobile at all. If we would continue this line of reasoning, we could have no properties that expose pinch-zoom-specific values since they would cause confusion. In particular, we would not have a devicePixelRatio that’s a constant on mobile but a variable on desktop.

Also, if I recall correctly the last browser started supporting window.innerWidth/Height correctly around the end of 2011. That means it has worked the way it does in ALL browsers for over four years, and it’s only now that problems were discovered. That’s a bit late.

Finally, the problems are extremely easy to solve: just swap in document.documentElement.clientWidth/Height for window.innerWidth/Height and your site works. In ALL browsers. Well, maybe you want to add 16 to the new value in order to simulate a scrollbar, but that’s it. Come to think of it, some kind of margin- or padding-based solution is probably even better.

Exhibit B: the problems window.innerWidth/Height are extremely easy to solve.

How useful is the visual viewport?

It is true that, right now, web developers don’t do a lot with the visual viewport. Whenever I give viewport workshops I spend most of my time on the layout viewport and urge web developers to carefully study it. The visual viewport is an afterthought — required for the full viewport picture, but not terribly important in practice.

However, that could change. Besides, even unimportant features could be absolutely vital in an edge case or two. The issue thread and the intent to change discussion already mentions a few of those cases, and I’d like to add a few more.

First, a simple check if users zoom in a lot on your site. Read out the visual viewport size when they leave the page, or after they’ve used the page for 30 seconds or so, and you know whether a lot of people zoom in. If they do, you should consider the possibility that your content is too small.

Second, for years now I’ve been toying with the idea of zoom-based interfaces. Six years ago I created a test case (warning: doesn’t work too well nowadays — it was written for the then-current Safari/iOS in April 2010.) It requires the visual viewport size: I decide which areas should become scrollable by seeing if they’re inside the visual viewport and take up at least 60% or so of its area.

It may be that a zoom check is a bad idea. It may be that zoom-based interfaces are a bad idea, or that, even while they’re a good idea, you don’t need the visual viewport dimensions. We don’t know yet because we haven’t experimented enough.

What I DO know, though, is that the Chrome team made an entire line of inquiry impossible. I don’t consider “web developers aren’t doing this right now” a good enough argument; by the same line of reasoning Microsoft could have removed XHR after web developers failed to notice it for years.

Sometimes, thinking up new ways to work with well-established properties take a bit of time. Give us that time. Don’t break the web underneath us while we’re thinking. Give us time to innovate.

Exhibit C: the Chrome team closes off interesting avenues of innovation with zoom-based layouts.

A new API

It seems that Google (and other browser vendors) are aiming for the creation of a new API that makes clear to web developers whether a certain property reflects the visual or the layout viewport. This is an excellent idea. I can imagine that web developers who encounter the viewports for the first time are confused, and a clearer API will help a lot here.

Still, working on a new API does not mean removing the old API. In fact, even if the new API were implemented today, we still shouldn’t remove the old one. One of the principles browsers have always adhered to is backward compatibility.

When looked at through a backward compatibility lens, window.innerWidth/Height should stay the same. I mean, originally the entire property pair was redundant, since it was the Netscape way of saying (almost) the same as document.documentElement.clientWidth/Height in IE dialect. Once the latter became a standard, the former should have been discarded entirely. But is wasn’t — because of backward compatibility.

The same principle should apply here. Like it or hate it, window.innerWidth/Height has a specific meaning on pinch-zoom devices that will remain intact forever.

What to do?

If you care about this issue, I urge you to star the bug report. Even better: if you have examples of scripts that use the visual viewport, leave a polite comment describing what you do and how it would break. Google is a data-driven company: if you provide it with data it will eventually cough up the correct solution.

Anyway, I hope I made clear that suddenly changing something that has been working for a while now is a bad idea. I hope the Chrome team reverts the change to window.innerWidth/Height.

This is the blog of Peter-Paul Koch, web developer, consultant, and trainer. You can also follow him on Twitter or Mastodon.
Atom RSS

If you like this blog, why not donate a little bit of money to help me pay my bills?