How to Stop My Fixed Navigation from Moving Like This When the Virtual Keyboard Opens in Mobile Safari

How to fix viewport in place when virtual keyboard opens in mobile Safari?

With the help of JMathew, I found a solution for this problem.

See a working codesandbox example here.

  1. Put your navbar, message list, and input into container divs.
  2. Add refs to those container divs. For example:
  const messageListContainerRef = useRef(null);

//...

return (
//...



//...
)

  1. When the virtual keyboard opens (when the dummy input is focused), add an event listener for the touchmove event to the inputContainerRef and navbarContainerRef. Use that to preventDefault() on the touch move event, which will prevent the User from being able to slide the input and navbar up and down. For example:
if (inputContainerRef.current) {
inputContainerRef.current.addEventListener('touchmove', (e) => {
e.preventDefault();
});
}

  1. You will still want to be able to scroll through the message list, so you can't just preventDefault() on it. Instead, use this solution (link now dead) to prevent the User from scrolling past the bottom (and top) of the page by setting the scrollTop value:
if (messageListContainerRef.current) {
messageListContainerRef.current.addEventListener('touchmove', (e: any) => {
if (!e.currentTarget) {
return;
}
if (e.currentTarget.scrollTop === 0) {
e.currentTarget.scrollTop = 1;
} else if (e.currentTarget.scrollHeight === e.currentTarget.scrollTop +
e.currentTarget.offsetHeight) {
e.currentTarget.scrollTop -= 1;
}
});
}

Depending on your want/need, you could set those touchmove event listeners on component mount, rather than on input focus. You could even set them for the whole document.body, if that works for you.

iOS iPad Fixed position breaks when keyboard is opened

I really like this solution (http://dansajin.com/2012/12/07/fix-position-fixed/). I packaged it up into a little jQuery plugin so I could:

  • Set which parent gets the class
  • Set which elements this applies to (don't forget "textarea" and "select").
  • Set what the parent class name is
  • Allow it to be chained
  • Allow it to be used multiple times

Code example:

$.fn.mobileFix = function (options) {
var $parent = $(this),

$(document)
.on('focus', options.inputElements, function(e) {
$parent.addClass(options.addClass);
})
.on('blur', options.inputElements, function(e) {
$parent.removeClass(options.addClass);

// Fix for some scenarios where you need to start scrolling
setTimeout(function() {
$(document).scrollTop($(document).scrollTop())
}, 1);
});

return this; // Allowing chaining
};

// Only on touch devices
if (Modernizr.touch) {
$("body").mobileFix({ // Pass parent to apply to
inputElements: "input,textarea,select", // Pass activation child elements
addClass: "fixfixed" // Pass class name
});
}

EDIT: Removed unnecessary element

Prevent virtual keyboard from pushing content up

You can take a look at this StackOverflow post, but I'll summarize the most useful parts for you:

Start off with the input's CSS as position: fixed;. When in focus, change it to absolute. Here is an example with JS:

if (document.getElementById("fixed") == document.activeElement) {
document.getElementById("fixed").class += "absolute"
}

Of course, that relies on CSS:

#fixed {
...
position: fixed;
}
#fixed.absolute {
position: absolute;
}

I hope this helps!



Related Topics



Leave a reply



Submit