When a MobileSafari keyboard-receing input (e.g. an input[type=text]
) receives focus in Safari, the system will try to verify whether there is ample room to bring up the soft keyboard without needing to scroll. The amount of wiggle room needed for Safari to consider available scroll height "ample" seems to increase with every major iOS release (surely to work around the very real problem of focus being granted to inputs that are subsequently oscured by the keyboard).
However, for "app-ey" web sites that carefully place each text input in a relatively fixed layout, this can be a maddening arms of scooching up my content more and more with each iOS release to avoid awkward jutters every time the keyboard is shown (example video here. In practice, it seems like the input's scrollHeight
can only really be about the equivalent of 15vh
before you're likely to get an automated scrolling whiplash from the soft keyboard, which isn't much space at all.
With iOS 12, my various hacks that took the input
out of flow by dynamically changing it to position: absolute
or position: fixed
stopped working. So, in order to prevent MobileSafari's keyboard from scrolling the page content when it thinks there isn't room, this approach uses CSS transform
to make the input
so far above the top of the page that Safari can't even try to scroll to it. (video of it working)
const focusKeyboardWithoutPushingPage = (el) => {
el.style.transform = 'TranslateY(-8000px)'
el.focus()
setTimeout(() => {
el.style.transform = 'none'
}, 0)
}
Then, I can programmatically focus on an input with:
focusKeyboardWithoutPushingPage(document.querySelector('#something'))
And even with a timeout of 0
milliseconds, MobileSafari will bring the keyboard up without attempting to scroll.
For user-initiated focus events, you can just bind to ontouchstart
and:
document.querySelector('#something').addEventListener('ontouchstart', (e) => { focusKeyboardWithoutPushingPage(e.target) })
Even though the ontouchstart
handler is invoking focus()
itself, everything works fine (as of iOS 12.1.2)
This is a good solution when the input is at the top of the page but, if you are at a different page height (as a result of a scroll, for example), at the focus of the field the page is brought back to the top in scroll position 0, moving the user from the point of the page where he was.