Control the Viewport Resize Behavior on mobile with interactive-widget

by Bramus published on

Viewports units on mobile have been a problem for a long time. Using 100vh is most likely not exactly what you initially expected it to be. To fix this, the CSS Working Group came up with more units over time for you to use. The dynamic viewport units got introduced, which include svh and lvh which represent 1% of the small and large viewport height respectively.

Two mobile browser visualizations positioned next to each other. One has an element sized to be 100svh (left, green) and the other 100lvh (right, blue). The blue red line represents the Layout Viewport.

While these units are fairly interoperable at the time of writing – there are still some interop issues, mainly related to webviews – there is one big gripe that a lot of people have with it: when the Virtual Keyboard gets shown, these units do not take the presence of that Virtual Keyboard into account. Depending on what you are building, you might want to have these units get resized when the Virtual Keyboard is shown.

The default viewport resize behavior

When the Virtual Keyboard gets shown on mobile, it gets laid over the content. As a result, the Visual Viewport gets resized but the Layout Viewport - the one that is used to position out position: fixed elements – remains unchanged.

Visualization of a mobile browser with the virtual keyboard opened. The elements that have a height of 100svh and 100lvh are not affected by the virtual keyboard’s presence.

Because the Layout Viewport does not change, the Viewport Units also don’t change. The only thing that changes is the size of the Visual Viewport, wich represents only the visual part that you see on screen.

Note: Prior to Chrome 108, Chrome on Android used to resize the Layout Viewport when the Virtual Keyboard was shown. To align with MobileSafari, Chrome adjusted its behavior to resize only the Visual Viewport instead. Firefox did the same with the release of Firefox 132.

What sometimes also happens is that browsers shift the Layout Viewport upwards (or the Visual Viewport downwards depending on how you look at it) in order to keep the focused input at the center of the screen.

Visualization of the Visual Viewport (orange dotted outline) on a page with the Virtual Keyboard shown. On the right, the Layout Viewport (blue dashed outline) got shifted up so that the focused input is centered on the screen.

Intermezzo

If you want to know all the details about Viewports, check out this HTTP 203 episode:

The relevant part for you to know here is that the size of the Initial Containing Block (ICB) is based on the Layout Viewport – more specifically the Small Layout Viewport – and that the Viewport Units are based on the size of the ICB.

Visualization of the Initial Containing Block or ICB for short (red dashed outline). It’s size is taken from the Small Layout Viewport.

If you prefer reading, there are also a bunch of explainers for you to review.

The interactive-widget keyword in the viewport meta tag

To control the viewport's size and shape there is the viewport meta tag. Most likely you have used the following before:

<meta name="viewport" content="width=device-width, initial-scale=1" />

In the content there are two properties listed, each with their own value:

  • width: Sizes the width of the ICB. The value device-width indicates that it should be size in relation to the device’s width.
  • initial-scale: Sets the zoom level when the page is first loaded. It is set to 1, which is also the default (in most cases).

Other keywords that you might have used before include height, minimum-scale, maximum-scale, and user-scalable.

A fairly new keyword that you can use in the viewport meta tag is interactive-widget. It allows you to specify how the various viewports should behave when “interative widgets” such as the Virtual Keyboard get shown.

  • resizes-visual: Resize only the Visual Viewport but not the Layout Viewport.
  • resizes-content: Resize both the Visual Viewport and Layout Viewport.
  • overlays-content: Do not resize any viewport. This is similar to using the Virtual Keyboard API with overlaysContent set to true.
The impact of the various values for interactive-widget. The orange dotted box is the Visual Viewport. The blue one is the Layout Viewport. Both resize differently depending on the value of interactive-widget.

By setting interactive-widget to resizes-content, you can have the Layout Viewport resize. As a result the ICB will also resize, and therefore the Viewport units will also yield different values.

Visualization of the impact of setting interactive-widget to resizes-content. When that’s the case and the Virtual Keyboard is shown, the ICB resizes and the Viewport Units get adjusted.

interactive-widget is supported in Chrome 108+ and Firefox 132+. If you would like to see this become available in WebKit/Safari, please go give https://github.com/WebKit/standards-positions/issues/65 a thumbs up.

Summary

Use the interactive-widget keyword in the viewport meta tag to control the viewport resize behavior when the Virtual Keyboard gets shown. By default the Visual Viewport resizes. To also have the Layout Viewport resize, set the value of interactive-widget to resizes-content.

<meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content">

To not resize any of those viewports, set its value to overlays-content.

The interactive-widget keyword is supported in Chrome 108+ and Firefox 132+.

Further Reading

About Bramus

Bramus is a web developer from Belgium. He’s part of the Chrome Developer Relations team at Google, focusing on CSS, Web UI, and DevTools. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since.

Blog: bram.us
Bramus on Mastodon: @bramus@front-end.social
Bramus on X: @bramus