8

I have a simple web app with a few text inputs and the inputs toward the bottom of the page get covered up by the iPhone keyboard. This is a terrible user experience making it difficult for the user to see what text they are entering as well as selecting other elements on the page after they are done entering text.

Apple documents the behavior here: https://developer.apple.com/library/archive/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html

I've seen several posts about this problem and there are multiple solutions for iOS app development but no real solutions for web apps.

I don't have the resources to test on multiple devices and I don't have an android device so I don't know if this problem even occurs there.

Is there a cross platform solution for detecting when a keyboard is covering the UI, how much of the UI is being covered, and an approach to ensure the input is visible?

Scott Boring
  • 2,601
  • 1
  • 25
  • 31
  • Interestingly, this only happens in iOS, android is working fine. But scrolling on the focus event (like written in my answer) works within my app. – dannybucks Feb 13 '19 at 09:10

6 Answers6

3

This answer is a hack; but it's the best solution I have come up with.

Adding a padding to the bottom of the page that is large enough for the keyboard enables content to be displayed as desired when the keyboard is visible.

Using some javascript listeners and a CSS class, this padding can be added only when the keyboard is displayed.

body.keyboard {
    height: calc(100% + 500px); /* add padding for keyboard */
}

The following javascript will add and remove the CSS class when an input has focus, which is the closest I can get to figuring out when the keyboard is displayed.

// focus events don't bubble, must use capture phase
document.body.addEventListener("focus", event => {
    const target = event.target;
    switch (target.tagName) {
        case "INPUT":
        case "TEXTAREA":
        case "SELECT":
            document.body.classList.add("keyboard");
    }
}, true); 
document.body.addEventListener("blur", () => {
    document.body.classList.remove("keyboard");
}, true); 

It's also worth noting that iOS performs an annoying zoom if the input font size is less that 16px so this is also important.

input {
    font-size: 16px !important;
}

Please let me know if you have a better solution.

Scott Boring
  • 2,601
  • 1
  • 25
  • 31
  • You also want to check the screen size, likely by CSS and then not use your `.keyboard` class. – Avatar May 30 '22 at 12:43
0

What you can do is hide the keyboard on any click event. So, figure out when you don't want to display a keyboard and when do you really want to show it.

So once figured, you can hide the keyboard like:

InputMethodManager manager = getSystemService(INPUT_METHOD_SERVICE);
manager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS);
Sagar Balyan
  • 620
  • 6
  • 20
  • Thanks Sagar; but, I don't feel that solves my problem. I want the input visible while the user is using the keyboard so they can see the text they are entering. – Scott Boring Feb 07 '19 at 14:35
0

Here's an answer that might help you: Scroll textfield up when keyboard popsup

In summary, you can make use of the visual viewport api and update the next render accordingly.

Yosef Bernal
  • 1,006
  • 9
  • 20
Bru
  • 1
0

What I did is to scroll the elements into view when focused by touch.

There is no exact api or anything to know if the keyboard is open at all, or how much the keyboard covers (in chrome actually the keyboard reduces the viewport, not overlays on top), but looking at average mobiles, it covers roughly half of it.

As for the implementation, I use a kind of simple heuristic. You can go all-in if the device is a touch device see mobile device detection section here, but this doesn't necessarily cover laptops with touch screens. (and doing it based on resolution is a bad idea also)

I took this "touch device" approach one step forward, and listen on the touchstart event on form elements and set a variable something like hasTouchKeyboard, and then scroll element to top of page (or at least first half that is likely not covered) when focused if this variable is true.

The idea behind it is that the touchstart usually fires before the focused event, plus the real differentiator is that if the user touched the input field, then it is 100% that it is using a touch device AND actually used touch on it (that will likely trigger the keyboard), and not just focused it with mouse on a hybrid device.

It is definitely not bulletproof, but fairly simple and works well without any user agent magic or other crazy stuff.

0

For www.lokilist.com I needed a solution that worked without javascript for the text input used to enter a Session ID.

On the server, I used the "isMobileDevice()" PHP function found here:

https://stackoverflow.com/a/23874239/20094562

Then attached a css class with onfocus css only if the requesting browser was "mobile" (that function considers tablets as mobile, which is all the better for this purpose since we actually care about touch screens).

To summarize:

  1. Detect touch screens based on user agent with isMobileDevice()

  2. In your css, include a placeholder class like ".mobileTextInput".

  3. Also include in your css the onfocus property of that class like ".mobileTextInput:focus". This is what will reposition your text input when selected.

  4. If the user agent is a mobile device, add the mobileTextInput class to the text elements you want to move above the virtual keyboard.

babytazer
  • 1
  • 1
-2

To prevent the mobile keyboard from covering HTML inputs, you can use a combination of CSS and JavaScript. Here's an approach that can help you achieve this:

  1. Detect the keyboard height: Since different devices and platforms may have different keyboard heights, you need to detect the height dynamically. You can achieve this by listening to the resize event and measuring the viewport height before and after the resize. The difference will give you the keyboard height. Here's an example in JavaScript:
var keyboardHeight = 0;

window.addEventListener('resize', function() {
  var viewportHeight = window.innerHeight;
  var newKeyboardHeight = document.documentElement.clientHeight - viewportHeight;
  keyboardHeight = newKeyboardHeight > 0 ? newKeyboardHeight : 0;
});
  1. Adjust the layout: Once you have the keyboard height, you can adjust the layout to ensure the input remains visible. One common technique is to use the vh (viewport height) CSS unit to set the height of your container element that holds the input fields. By subtracting the keyboard height from the viewport height, you can ensure the container remains visible above the keyboard. Here's an example:
.container {
  height: calc(100vh - ${keyboardHeight}px);
  overflow-y: auto;
}

This CSS code will make the container scrollable if its content exceeds the available height.

  1. Scroll to the focused input: When an input field receives focus, you can scroll the container to ensure the input is visible above the keyboard. This can be done by adjusting the scroll position of the container element. Here's an example in JavaScript:
var inputs = document.querySelectorAll('input');

Array.from(inputs).forEach(function(input) {
  input.addEventListener('focus', function() {
    var scrollOffset = input.getBoundingClientRect().top - keyboardHeight;
    if (scrollOffset > 0) {
      document.querySelector('.container').scrollBy({
        top: scrollOffset,
        behavior: 'smooth'
      });
    }
  });
});

This code listens to the focus event on all input fields and calculates the scroll offset needed to bring the focused input into view. It then scrolls the container element using the scrollBy method.

By combining these steps, you can dynamically adjust your layout and ensure that the input fields remain visible above the keyboard on mobile devices.

  • 4
    This answer looks like ChatGPT – DavidW Jul 13 '23 at 06:31
  • 1
    This answer has a high probability of being AI generated. This is **not tolerated** on this site. Read the guidelines of AI content here: https://stackoverflow.com/help/gpt-policy –  Jul 15 '23 at 12:57