TL;DR: The safe-area-inset-bottom value doesn't update when the keyboard is visible, creating an unnecessary gap above the keyboard. Here's a CSS-only workaround (with a caveat...)

The safe and unsafe areas on iPhone X in the landscape orientation, with insets indicated.
The safe and unsafe areas on iPhone X in the landscape orientation, with insets indicated. Source: WebKit Blog.

Ever since the iPhone X (/ai·fown eks/), websites and web apps have been able to render under the system UI (just like native apps!), leveraging the CSS env( safe-area-inset-* ) values to make sure the system UI doesn't clash with our UI.

However, it turns out Cupertino (and now Mountain View) forgot about a small detail:

The safe-area-inset-bottom value doesn't update when the keyboard is visible, creating an unnecessary gap above the keyboard.

Safe-area-inset-bottom causes a gap above the keyboard
Safe-area-inset-bottom causes a gap above the keyboard, as seen on iOS Safari (simulated).

The workaround

For anyone who runs into this issue: I've come up with a workaround that covers 90% of the use-case, and only requires a bit of CSS:

.safe-area-bottom {
  :root:not( 
    :has( 
      input:focus-visible, 
      textarea:focus-visible,
      [contenteditable]:focus-visible 
    ) 
  ) & {
    padding-bottom: env( safe-area-inset-bottom, 0 );
  }
}

I'm using CSS nesting here, and there's an & in there. This roughly compiles down to something like:

:root:not( ... ) .safe-area-bottom { ... }

The gist is this: Only apply safe-area-inset-bottom if the document does not contain an input, textarea or [contenteditable] that has :focus-visible.

The caveat

There is one drawback: input elements can still have :focus-visible when the keyboard is dismissed, at least on Chrome for Android. This means that the inset will not be applied if the input is focused and the user dismissed the keyboard.

The solution

Both Chromium and WebKit should update the safe-area-inset-* values when the keyboard pops in or out of view (like how how they update the values when you change orientation of the device).

So please consider subcscribing and/or +1'ing the issues for Chromium and WebKit:

Further reading