Safari 13, Mobile Keyboards, And The VisualViewport API.

Suppose you want to keep a menu present at all times at the bottom of the screen on a mobile device. Usually this is fairly trivial and can be solved with just CSS:

.menu {
    position: fixed;
    bottom: 0;
}

Most mobile browsers will work just fine. When the keyboard or other UI elements become visible on the screen, the layout viewport will be resized, events (resize, sometimes scroll) will trigger, and the page will rerender. Our fixed menu will move up so that it's still sitting on top of the keyboard.

There is one glaring exception to this which is Safari on mobile devices. Prior to iOS 8.2 the layout viewport would resize when the keyboard opened. However Apple developers believed this resize to be a performance concern since the page layout may change on a resize (issue #141832). Their solution was to implement another layer on top of the layout viewport and make the keyboard opening completely invisible to both CSS and JavaScript. Seriously,

I spent more than a day in research, but had to concede defeat: it’s undetectable. Viewport changes, media queries, aspect ratios, other events such as blur, nothing gives any clue that the software keyboard has been opened on Safari.

Instead of the page resizing, the layout viewport slides up to make room for the keyboard. The visual viewport (the part of the layout viewport that is actually visible on the screen) gets updated, but until recently there has been no way to detect this change and react to it. Until...

The Visual Viewport API

The solution to these woes is the Visual Viewport API, an experimental standard that allows you to both query and react to changes in the visual viewport. While it's marked as an experiment on MDN, support for it is actually fairly widespread. Safari/iOS 13 added full support for the Visual Viewport API, which means every major browser but old-Edge and IE11 now support it.

Added support for the Visual Viewport API for adjusting web content to avoid overlays, such as the onscreen keyboard.

Don't worry, the compatibility chart may say it's not supported on Safari but that is because I only just addded it and MDN has not yet updated. It's there, it works, I promise.

We can make our fixed menu work on iOS Safari by using the resize and scroll events provided by the new API on the window.visualViewport object.

Since the CSS solution is so much cleaner and renders smoothly as you scroll, you probably only want to use this solution when you have no other choice.

Further Reading