The Android Keyboard causes the viewport and elements to shrink when using the vh unit in CSS

I am encountering a peculiar and unusual problem.

All my pages are designed with vh and vw CSS units instead of pixels for this specific project.

The issue at hand is that on Android tablets, when the input field is touched, the default keyboard pushes the viewport causing the page and all its elements to shrink.

Interestingly, on iPads, this issue does not occur as the keyboard overlaps the screen rather than pushing it.

I am seeking a solution to prevent the Android keyboard from resizing the viewport of the browser and maintaining the original size.

It's worth noting that changing the CSS units or using XML and manifest files are not viable options. These issues are only present on web pages experiencing this specific problem.

Answer №1

This question may be old, but I recently faced the same issue in my application. After some trial and error, I discovered a straightforward solution. (I implemented this in the ngOnInit function of my Angular app.component, but using document.ready() or any other initialization callback should yield similar results with some tweaking)

setTimeout(function () {
        let viewheight = $(window).height();
        let viewwidth = $(window).width();
        let viewport = document.querySelector("meta[name=viewport]");
        viewport.setAttribute("content", "height=" + viewheight + "px, width=" + viewwidth + "px, initial-scale=1.0");
    }, 300);

This code snippet ensures that the viewport meta tag explicitly defines the viewport height, as opposed to hardcoding it like so:

<meta name="viewport" 
content="width=device-width, height=device-height, initial-scale=1">

The hardcoded version fails to account for changes in device-width and device-height when Android's soft keyboard is activated.

Answer №2

After considering Tyler's inquiry, here is a simplified version of the script that appears to be more streamlined:

addEventListener("load", function() {
    var viewport = document.querySelector("meta[name=viewport]");
    viewport.setAttribute("content", viewport.content + ", height=" + window.innerHeight);
})

If you insert it following the meta tag declaration, you can even eliminate the need for that addEventListener:

var viewport = document.querySelector("meta[name=viewport]");
viewport.setAttribute("content", viewport.content + ", height=" + window.innerHeight);

Answer №3

Here's a comprehensive solution that considers changes in screen orientation:

// Updated viewport definition with an "id" for later modification:
<meta name="viewport" id="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>

<script>
// Global boolean variable to track current orientation
var pageInPortraitMode;

// Listen for window resize events to detect orientation changes
window.addEventListener("resize", windowSizeChanged);

// Set the orientation variable when the page loads
addEventListener("load", function() {
  pageInPortraitMode = window.innerHeight > window.innerWidth;
  document.getElementById("viewport").setAttribute("content", "width=" + window.innerWidth + ", height=" + window.innerHeight + ", initial-scale=1.0, maximum-scale=1.0, user-scalable=0");
})

// Update viewport values only on orientation change
function windowSizeChanged() {
  if (((pageInPortraitMode === true) && (window.innerHeight < window.innerWidth)) || ((pageInPortraitMode === false) && (window.innerHeight > window.innerWidth))) {
    pageInPortraitMode = window.innerHeight > window.innerWidth;
    document.getElementById("viewport").setAttribute("content", "width=" + window.innerWidth + ", height=" + window.innerHeight + ", initial-scale=1.0, maximum-scale=1.0, user-scalable=0");
  }
}
</script>

Answer №4

Recently, I encountered a similar issue and spent some time finding a satisfactory solution. In developing a cordova app with html5, css3, and angularjs, my goal was to ensure that the app would be responsive across all screen sizes without resorting to excessive media queries and convoluted css. Despite starting off with viewport and vh units, I found that the keyboard functionality disrupted everything.

The key is to incorporate a simple snippet of javascript (using jquery in this case) like so:

$("html").css({"font-size": ($(window).height()/100)+"px"});

By implementing this code, you can now utilize "rem" in the same manner as "vh", while keeping the font-size unaffected by viewport changes. The "rem" unit is solely based on the root font-size of html, which we set to 1% of the screen height using jquery.

I hope this explanation proves helpful!

UPDATE 1: Upon encountering a new challenge, I wanted to share my workaround here. It's worth noting that most smartphones have a minimum font-size limit. To address this, adjust all rem values by dividing them by 3 or 4 accordingly. Furthermore, modify the javascript as follows:

$("html").css({"font-size": ($(window).height()/25)+"px"}); /*(assuming division by 4)*/

If you utilize SASS, creating a custom rem function can simplify this process by handling the division automatically.

Answer №5

Although it's been almost a year since this issue was raised, I feel compelled to share my solution to this increasingly pressing problem.

I devised a simple JS function called SET that loads after the completion of the DOM.

Any element assigned to a specific class (such as ".pheight") will not be resized when the viewport height decreases. It will only resize if the viewport height increases or if the viewport width changes.

Fortunately, in my applications, this method works flawlessly!

  var docwidth = window.innerWidth;
  var docheight = window.innerHeight;
  function pheigt_init() {    
    pheigt_set_prevent_height();
    window.onresize = function() {
        if (docwidth !== window.innerWidth || docheight < window.innerHeight) {
            pheigt_upd_prevent_height();
        }
    };
  }
  function pheigt_set_prevent_height() {
    document.querySelectorAll('.pheight').forEach(function(node) {
     node.style.height = node.offsetHeight + 'px';
    });
  }
  function pheigt_upd_prevent_height() {
    document.querySelectorAll('.pheight').forEach(function(node) {
        node.style.removeProperty('height');
    }); 
    setTimeout(function(){ pheigt_set_prevent_height(); }, 100);
    docheight = window.innerHeight;
    docwidth = window.innerWidth;
  }
  document.addEventListener('DOMContentLoaded', pheigt_init());

Answer №6

If you are working with Angular 4 or newer,

import {Meta} from "@angular/platform-browser";


constructor(private metaService: Meta){}

ngOnInit() {
  this.metaService.updateTag({
    name: 'viewport',
    content: `height=${this.height}px, width=${this.width}px, initial-scale=1.0`
  },
  `name='viewport'`
);
}

Answer №7

One possible solution is to utilize the % unit, which appears to be unaffected by this particular issue. Another option could be using vw for width (since it's not affected for obvious reasons) or even for height as well.

Answer №8

It might be necessary to update the viewport height (or just height) using a function.

const reference = useRef();

function adjustKeyboard(){
    setTimeout(
        ()=>{reference.current.querySelector("#win").style.height = "calc(100vh)"}
    ,2000)
}

return (
    <ref={reference} div>
       <input type="text" id="win" onFocus={adjustKeyboard} onBlur={adjustKeyboard}/>
    </div>
)

Answer №9

In my PWA, I have disabled scrolling and zooming to create a specific layout using viewport units. However, I encountered an issue where the window.onresize event is triggered when the android keyboard pops up. To address this, I check if the keyboard is active by verifying if document.activeElement is a textarea or input field.

An inconvenience arises when the user changes screen orientation while the keyboard is in use, causing the viewport resizing to fail. As a workaround, I blur the element to close the keyboard before any layout issues occur. While not ideal for user experience, this scenario is considered a rare edge-case.

Below is the final code snippet:

window.onresize = () => {
    if(document.activeElement.tagName !== 'TEXTAREA' && document.activeElement.tagName !== 'INPUT'){
        setViewportSize();
    }
}

window.onorientationchange = () => {
    // check if keyboard is used
    if(document.activeElement.tagName === 'TEXTAREA' || document.activeElement.tagName === 'INPUT'){
        document.activeElement.blur();
    }
    setViewportSize();
}

function setViewportSize(){
    document.documentElement.style.setProperty('--screen-width', `${window.innerWidth}px`);
    document.documentElement.style.setProperty('--screen-height', `${window.innerHeight}px`);
}

Note: The use of window.onorientationchange is deprecated and may become ineffective in the future.

Answer №10

A setback threw me off course. I couldn't find a CSS solution or workaround to fix the issue.

However, if you're able to use JQuery (or JavaScript), I have some code that might help you resolve it.

var viewportHeight = $(window).height();
var viewportWidth = $(window).width();
$('body,html').css("height",viewportHeight); // adjust if vh used in body/html too
$('.someClass').css("height",viewportHeight*0.12);// or any other percentage based on vh
$('#someId').css("width",viewportWidth*0.12);

This is just an example; feel free to customize it with the percentages and jQuery selectors you require.

PS: Here's a helpful hint. Place the code at the end of your HTML document or inside $(document).ready(function() { });. For responsive design, include it within the orientationchange event like this:

$(window).on("orientationchange",function(event){ window.setTimeout(function(){
var viewportHeight = $(window).height();
var viewportWidth = $(window).width();
$('body,html').css("height",viewportHeight);
$('.someClass').css("height",viewportHeight*0.12);
$('.someClass').css("width",viewportWidth*0.09);
$('#someId').css("height",viewportHeight*0.1);
}}, 450);});

I added a 450ms delay timer above to account for device orientation change delays.

Apologies for any language errors, Cheers

Answer №11

simply adding 'shrink-to-fit=no' in the meta tag as shown below:

<head>
   <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
 </head>

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

Is it possible to update the value of Select2 as you type?

In my country, the majority of people do not have a Cyrillic keyboard on their devices. To address this issue, I created a function that converts Latin characters to Cyrillic in Select2's dropdown for easier city selection. However, I noticed that the ...

Error retrieving JSON data nested in another object in Android application

I am currently developing an Android app that interacts with a server through API calls and retrieves JSON data. However, I am facing an issue where I can successfully parse the JSON information up to the first array, but encounter an error mentioning that ...

A scenario in a Jasmine test where a function is invoked within an if statement

My coding dilemma involves a function: function retrieveNames() { var identifiers = []; var verifyAttribute = function (array, attr, value) { for (var i = 0; i < array.length; i++) { if (array[i][attr] === va ...

Rendering with ReactDom in a SharePoint Framework application

Our current project requires us to generate a PDF file using the <div></div> elements. Most of the code I've seen renders from ReactDom.Render() instead of the render class: Take for instance React-pdf: import React from 'react&apo ...

MUI Error: Incorrect prop provided to menu item

I am encountering an issue with a React component that generates a list of elements, each containing a button to open a menu. The problem is that the props being passed to each menu are incorrect; they always reflect the props of the last element in the ...

What is the iOS counterpart of AsyncTask in Android?

Just dipping my toes into the world of iOS programming. Can anyone tell me what the equivalent of AsyncTask in Android is in iOS? ...

Capture information from a text box on an asp.net webpage and showcase it on a different webpage

I am a beginner in ASP.net and I am experimenting with basic web forms. I have created code that collects the first name and last name from the user. After the user clicks on submit, I want the data to be shown on a different page. Can someone create the n ...

Prevent inspection of elements in Angular 2

Is there a way to prevent users from using inspect element on my website? I have disabled text selection, but users are still able to copy content through inspect element. ...

The `next()` function is successfully invoking all remaining middleware without skipping any

As a complete beginner to express routing logic (and node and js in general), I'm facing a problem that I can't seem to figure out. Despite my attempt to understand the context, it's still not clear to me. Let me try to explain. I am experi ...

Issue encountered while initializing session_start() in PHP REACTJS AXIOS

https://i.sstatic.net/bSelX.pngWhen attempting to log in to my web application, I encountered an issue where the session is not opening after entering the correct email and password. Strangely, there is no PHPSESSID present in the console > application. ...

What is the best strategy to prevent reflow and flickering when loading images on a website?

My website displays an image on the left with text on the right, but when the server is busy or the connection is slow, the page flickers. It initially shows the text on the left and then suddenly moves it to the right once the image loads. This issue see ...

Using JavaScript to replace a radio button with the term "selected"

I am currently in the process of developing a quiz that is powered by jQuery and possibly JSON, with data being stored in a database. Everything is functioning correctly at this point, but I would like to enhance the user interface by hiding the radio butt ...

Dynamic calendar with flexible pricing options displayed within each cell

I've been wracking my brain over this issue for quite some time now, but still can't seem to find a solution! Is there a React Calendar out there that allows for adding prices within the cells? I simply want to show a basic calendar where each c ...

``Error: GraphQL server unable to initiate due to a failure in the module.exports

While learning GraphQL, I encountered an error when attempting to start a server. const graphql = require('graphql'); const _ = require('lodash'); const { GraphQLObjectType, GraphQLString, GraphQLInt, GraphQLSchema } ...

What is the best way to invoke an AngularJS function from within a regular JavaScript function

Exploring the world of AngularJS for the first time and seeking guidance on calling a function to retrieve items in different controllers. Incorporating CSV file loading using AngularJS. var Mymodule = angular.module('Mymodule', []); Mymodule.f ...

What are the steps to implement actions or scrolling functionality within a Java application?

Looking for alternative method as TouchAction is now deprecated. Any suggestions on how to implement vertical scrolling? The following code was previously used but is no longer effective due to the deprecation of TouchAction. Dimension dimension =driver ...

Switch between different stylesheets effortlessly with just one button click

I'm interested in creating a button that can switch between two stylesheets with a single click. Here is the current code I am using: <link id="style1" rel="stylesheet" type="text/css" href="style.css" /> <link id="style2" rel="stylesheet" t ...

Interfacing Android applications with PHP scripts built using the CodeIgniter framework

I am in the process of creating an android application. Our website is built with PHP/MYSQL and is currently hosted on a server. I'm looking to establish communication between my app and the server to access the MYSQL database. The PHP files are coded ...

I am experiencing difficulties in generating a React application using "create-react-app"

Here is the error message from the console: > <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="04676b7661296e7744362a322a35">[protected email]</a> postinstall G:\mernbootcamp\testfront\my-app\node ...

What is the expected result of running this Javascript program with asynchronous tasks?

My expectation with this code is that it will run, then after a 2-second delay, the execution stack will become empty with one callback in the setTimeout function. Since the promise is not resolved yet, I anticipate both the message queue and job queue to ...