How can I stop the body from scrolling to 100% height when the virtual keyboard is displayed?

My chat app has sticky header and footer elements. To handle the mobile virtual keyboard opening, I adjust the document's height using window.visualViewport.height. For example, if the browser's height is 1000px and the virtual keyboard takes up 400px, then window.visualViewport.height will be 600px, setting both <html> and <body> to that height. This allows the header and footer to display correctly within the 600px viewport.

However, there is an issue where users can still scroll the entire page up by 400px, revealing empty space at the bottom. How can I prevent this empty space from showing while maintaining the sticky header/footer functionality?

I've attempted various solutions:

  1. Listening for scroll events, but they are not triggered
  2. Using an IntersectionObserver on an element below the viewport, which never triggers
  3. Applying position: fixed to the footer, but it does not remain fixed when scrolling
  4. The document's scroll Y position always remains at 0
  5. Setting
    navigator.virtualKeyboard.overlaysContent
    has no effect

This issue persists in Android + Chrome, as well as iOS + Safari.

View a video demonstration showcasing the initial white space caused by the keyboard:

Edit

I discovered a workaround involving

window.visualViewport.addEventListener('scroll', ...)
. On scroll, I dynamically add padding to the top of the page matching window.visualViewport.offsetTop. However, there is some delay where users can scroll before the scroll handler kicks in. In iOS Safari, this delay can exceed 1 second. Is there a more effective solution to address this issue?

Answer №1

To ensure the position remains unchanged when the keyboard pops up, consider utilizing the virtualkeyboard event and modifying the parent div to hide scrolling while it is active, and enabling scrolling once it disappears:

Check out the code snippet below for guidance:

if ("virtualKeyboard" in navigator) {
  navigator.virtualKeyboard.addEventListener("geometrychange", (event) => {
    const { x, y, width, height } = event.target.boundingRect;
    // Determine if the keyboard is open (you need to create this logic yourself)
    // For example:
    let keyboardOpen = height > 0;
    if (keyboardOpen) {
        // Disable scrolling on the parent element by setting overflow to hidden
        document.getElementById("parent-div").style.overflow = "hidden";
    } else {
        // Re-enable scrolling on the parent element
        document.getElementById("parent-div").style.overflow = "scroll";
    }

  });
}

Make sure to replace the correct div ID in the document query and assign an ID to the div within its HTML tag.

Additional Resources:

Mozilla virtual keyboard API

Virtual Keyboard API

Answer №2

Here is a solution that combines various techniques for optimal results.

Source: Get viewport height when soft keyboard is on

JSBin code: https://jsbin.com/nayigetido/1/edit?html,css,js,output

JSBin Output: https://jsbin.com/nayigetido/1/edit?output

HTML:

<head>
  <!-- Remember to include the meta tag -->
  <meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content">
</head>
<body>
  <div id="chat">
    <div class="messages">Messages</div>
    <input type="text"/>
  </div>
</body>

CSS:

#chat{
  height:100%;
  width:100%;
  display:flex;
  flex-direction:column;
  padding:3em;
  box-sizing:border-box;
}
.messages{
  height:100%;
  flex:1 1 auto;
}
input{
  width:100%;
}

html,body{
  margin:0;
  height:100%;
}

JS:

window.addEventListener('resize', () => {
  const chat = document.getElementById('chat');
  chat.style.height = window.visualViewport.height + 'px';
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Determining the offsetWidth and scrollWidth for option elements within a select field containing the multiple attribute on Internet Explorer 11

My select input element has multiple attributes and a fixed width set. Unfortunately, due to the fixed width, the overflowing content in the x-direction is not visible. To address this issue, I have created a JavaScript function that uses the title attribu ...

Using the onreadystatechange method is the preferred way to activate a XMLHttpRequest, as I am unable to trigger it using other methods

I have a table in my HTML that contains names, and I want to implement a feature where clicking on a name will trigger an 'Alert' popup with additional details about the person. To achieve this, I am planning to use XMLHttpRequest to send the nam ...

Advantages of using individual CSS files for components in React.js

As someone diving into the world of Web Development, I am currently honing my skills in React.js. I have grasped the concept of creating Components in React and applying styles to them. I'm curious, would separating CSS files for each React Component ...

Having trouble aligning the image to the center

After researching and trying various solutions suggested for aligning an image, I am still unable to get it to align as desired. Here is the HTML code snippet: <section> <img class="seattle" src="img/Seattle Pier.jpg" alt="Seattle docks"> ...

Tips for achieving uniform spacing between three buttons in a horizontal alignment using bootstrap 3

Is there a way to make buttons enclosed in a <div> with class="row" and each button having class="span4" only as wide as the text it contains, centered at 25%, 50%, and 75% of the width of the screen? [aaa] [bbb] [ccc] not [ aaa ][ bbb ][ ccc ] ...

Is it possible to eliminate jagged edges in CSS 2D rasterization by applying anti-aliasing to subpixels?

It appears that the HTML/CSS engine automatically rounds values to the nearest whole px unit. It would be interesting to see non-discrete sizing options (floats). A closer look reveals that in Chrome, widths/heights are rounded to the nearest physical pix ...

Unable to manipulate JQuery lightSlider slides using element index

I've been working on a new page design at this link: The code is still a work in progress, so bear with me as I test out some functions and scripts. At the end of the first section, there are 4 logos that, when clicked, will trigger a modal to pop u ...

Fill in according to the options selected in the dropdown menu

Recently delving into the world of React, I encountered a design challenge that needs solving. My goal is to have a selection field with various choice values, each offering different sets of KPIs and UOMs. Depending on the chosen value, I should be able t ...

Sending an array with a specific identifier through JQuery ajax

I'm facing an issue where I am sending an array of values via jQuery AJAX to my servlet. However, the servlet is only picking up the first value in the array, even though there are more elements present. $.ajax({ type: "POST", url: "mySer ...

Is it feasible to verify for vacant dates with a single click?

Is there a way to determine if a date value is empty, and if it is, display a popup indicating so? After some research, I stumbled upon a similar issue where the date value was always filled with a default "mm/dd/yyyy" value. The solution provided involv ...

JS Implementation of the Coin Change Algorithm

I've been grappling with this algorithm for the past few days, but unfortunately I haven't been able to come up with a successful solution yet. The available solutions seem to be too advanced for my current level of understanding. This problem mu ...

Increase the spacing between the dropdown menu and the first option

I am attempting to create some space between the select box and the dropdown list. An example image can be seen below: https://i.sstatic.net/CovTn.png In the top example, a div was used. Despite trying padding and margins, I did not achieve the desired ...

Ways to showcase a standalone identifier from iTunes RSS

I have a script below that fetches iTunes charts directly from the RSS and displays it. However, I am looking to only display the information for a specific ID from the RSS entry. Any suggestions on how this can be achieved? <script> jQuery(functi ...

The display of data attributes is not being rendered correctly

Check out the fiddle I'm currently working on: http://jsfiddle.net/7Z8wY/9/ The HTML section looks like this: <div class="container"> <div class="right"> <div id="cityList" class="inner-table"></div> </div> ...

Issues with Dependency Injection in Angular.js

I've been working on Dependency Injection and trying to make my code more modular in Angular.js. After researching some tutorials, I decided to try and rewrite it. Here's what I initially planned (although I may have misunderstood some concepts, ...

Display the current language in the Vue language dropdown

My component is called DropdownLanguage.vue Goal: I need to show the current active language by default in the :text="selectedOptionDropdown" attribute. For example, it should display "English" which corresponds to languages.name. I'm struggling with ...

Confirm that the Time sequence is accurate using JavaScript Selenium

I am working with a list of time intervals that includes 'a day ago, 10 days ago, 3 months ago, and 6 months ago.' How can I verify that these dates are in ascending order using JavaScript and Selenium? I am unsure of how to approach this proble ...

Exploring Material UI: Customizing the styling of components within TablePagination

Is it possible to customize the styling of buttons within the actions panel of the TablePagination component? import { withStyles } from '@material-ui/core'; import MuiTablePagination from '@material-ui/core/TablePagination'; const st ...

Morris.js is throwing an error message, stating "Uncaught TypeError: Unable to access the 'label' property as it

I have successfully implemented a bar chart along with a date picker using Bootstrap. The bar chart loads data accurately when selecting a specific day. However, upon inspecting the developer tools, I encounter the following errors: Uncaught Type Error: C ...

Issues with properly functioning collapse button in Bootstrap 5.1.3 Navigation Bar

When I initially click on the collapsed nav-bar button, it expands to show the nav-bar contents. However, upon clicking the button again, it fails to collapse. Below is the corresponding HTML code snippet. *<!-- CSS Stylesheet -->* <link href= ...