How to keep fixed elements on top of the keyboard on iOS Safari

Yes, yet another one of those reasons why every developer loves Apple.

Irony apart, you're probably here because you want an HTML element (maybe a dock) to stick just on the bottom of your screen but actually doesn't get hidden by the virtual keyboard, so let's get started.

Clean way (Chromium only)

First, let me share the clean way of achieving this. Thanks to the VirtualKeyboard API which exports a set of CSS env variables keyboard-inset-*, we can use keyboard-inset-height as the bottom value for our sticky element.

Check the demo.

.my-sticky-div {
  position: sticky;
  bottom: env(keyboard-inset-height);
}

The only negative part of this solution is that it requires JS.

if ("virtualKeyboard" in navigator) {
  navigator.virtualKeyboard.overlaysContent = true;
}

By the way, don't expect this to work on non-HTTPS websites!

Using Tailwind CSS

You could easily create new spacing values in the Tailwind config:

export default {
  theme: {
    extend: {
      spacing: {
        "kb-height": "env(keyboard-inset-height, 0)",
        "kb-width": "env(keyboard-inset-width, 0)",
      },
    },
  },
};

Available env variables

  • keyboard-inset-top
  • keyboard-inset-right
  • keyboard-inset-bottom
  • keyboard-inset-left
  • keyboard-inset-width
  • keyboard-inset-height

iOS workaround

Now let's get our hands dirty...

Basically, we're using the fact that the viewport is shifted to the top on iOS devices when the keyboard is opened.

const dock = document.getElementById('dock');
const vv = window.visualViewport;

function fixPosition() {
  const ih = window.innerHeight;

  if (dock) {
    dock.style.bottom = `${Math.max(0, ih - vv.height - vv.offsetTop)}px`;
  }
}

Not super duper fluid but it's the best we can do for now...

Conclusion

As always, building for iOS web is not straightforward. I hope this small blog article has helped you and I wish you good luck with the next iOS issue you will encounter!

Sources

Enjoyed this article?

By Arnaud Gissinger in 2024.