Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent iOS keyboard from pushing the view off screen with CSS or JS

I have a responsive web page that opens a modal when you tap a button. When the modal opens, it is set to take up the full width and height of the page using fixed positioning. The modal also has an input field in it.

On iOS devices, when the input field is focused, the keyboard opens. However, when it opens, it actually pushes the full document up out of the way such that half of my page goes above the top of the viewport. I can confirm that the actual html tag itself has been pushed up to compensate for the keyboard and that it has not happened via CSS or JavaScript.

Has anyone seen this before and, if so, is there a way to prevent it, or reposition things after the keyboard has opened? It's a problem because I need users to be able to see content at the top of the modal while, simultaneously, I'd like to auto-focus the input field.

like image 220
rescuecreative Avatar asked Jul 27 '16 17:07

rescuecreative


People also ask

How to stop the onscreen keyboard from popping up on iPad?

While the following setting is typically associated with using a mouse with your iPad, you can try turning off the 'Show Onscreen Keyboard' setting in Settings > Accessibility > Touch > Assistive Touch.

How do I keep the onscreen keyboard on my Iphone?

Go to Settings > Accessibility > Keyboards, tap Full Keyboard Access, then turn on Full Keyboard Access.


3 Answers

first

<script type="text/javascript">  $(document).ready(function() {      document.ontouchmove = function(e){           e.preventDefault();           }  }); 

then this

input.onfocus = function () {     window.scrollTo(0, 0);     document.body.scrollTop = 0; } 
like image 105
ankurJos Avatar answered Oct 13 '22 00:10

ankurJos


For anyone stumbling into this in React, I've managed to fix it adapting @ankurJos solution like this:

const inputElement = useRef(null);  useEffect(() => {   inputElement.current.onfocus = () => {     window.scrollTo(0, 0);     document.body.scrollTop = 0;   }; });  <input ref={inputElement} /> 
like image 38
lewislbr Avatar answered Oct 13 '22 00:10

lewislbr


I struggled with this for awhile, I couldn't find something that worked well for me.

I ended up doing some JavaScript hackery to make it work.

What I found was that Safari wouldn't push the viewport if the input element was in the top half of the screen. That was the key to my little hack:

I intercept the focus event on the input object and instead redirect the focus to a invisible (by transform: translateX(-9999px)). Then once the keyboard is on screen (usually 200ms or so) I trigger the focus event on the original element which has since animated on screen.

It's a kind of complicated interaction, but it works really well.

function ensureOffScreenInput() {
  let elem = document.querySelector("#__fake_input");
  if (!elem) {
    elem = document.createElement("input");
    elem.style.position = "fixed";
    elem.style.top = "0px";
    elem.style.opacity = "0.1";
    elem.style.width = "10px";
    elem.style.height = "10px";
    elem.style.transform = "translateX(-1000px)";
    elem.type = "text";
    elem.id = "__fake_input";
    document.body.appendChild(elem);
  }
  return elem;
}

var node = document.querySelector('#real-input')
var fakeInput = ensureOffScreenInput();

function handleFocus(event) {
  fakeInput.focus();

  let last = event.target.getBoundingClientRect().top;

  setTimeout(() => {
    function detectMovement() {
      const now = event.target.getBoundingClientRect().top;
      const dist = Math.abs(last - now);

      // Once any animations have stabilized, do your thing
      if (dist > 0.01) {
        requestAnimationFrame(detectMovement);
        last = now;
      } else {
        event.target.focus();
        event.target.addEventListener("focus", handleFocus, { once: true });
      }
    }
    requestAnimationFrame(detectMovement);
  }, 50);
}

node.addEventListener("focus", handleFocus, { once: true });

Personally I use this code in a Svelte action and it works really well in my Svelte PWA clone of Apple Maps.

Video of it working in a PWA clone of Apple Maps

You'll notice in the video that the auto-complete changes after the animation of the input into the top half of the viewport stabilizes. That's the focus switch back happening.

The only downside of this hack is that the focus handler on your original implementation will run twice, but there are ways to account for that with metadata.

like image 23
Thomas Millar Avatar answered Oct 12 '22 23:10

Thomas Millar