javascript – Android Keyboard shrinking the viewport and elements using unit vh in CSS-ThrowExceptions

Exception or error:

I am experiencing a very strange and unique issue.

All my pages are using vh and vw CSS units instead of px due to the nature of the project.

Issue: On Android tablets, when you touch the input field the default keyboard pushes the view port which is causing the page and all the elements in the page to shrink.

On ipad this issue does not exist since the keyboard overlaps the screen and does not push the screen.

Looking for any solution to avoid the Android keyboard not to push the viewport of the browser and keep the original size.

Note: The only option i am left with is to avoid keyboard to push viewport, i won’t be able to change the CSS units or use xml, manifest. These are web pages which experiencing this issue.

How to solve:

I know this is an old question, but I had the exact same problem in my app. The solution I found was fairly simple. (My app is in Angular so I put this in the app.component’s ngOnInit function, but document.ready() or any other “initialization complete” callback should work just fine with the proper experimentation)

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 forces the viewport meta to explicitly set viewport height, whereas hardcoding

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

doesn’t work because the device-width and device-height change when Android’s soft keyboard is opened.

###

I faced the same problem recently, and it took me time to find a nice solution.
I am designing a cordova app using html5, css3 and angularjs. But moreover, I want my app to fit every screen without writing tones of media queries and finally unreadable css. I started with viewport and vh, but the keyboard broke eveything.

So what you have to use is just a little javascript (here is jquery) like this :

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

Here you go, now you can use “rem” exactly the same way you are using “vh”, except that the viewport will not affect font-size. “Rem” is set on html root font-size only and we just set it with jquery to 1% of the screen height.

Hope this will help!

EDIT 1 :
I just faced a new problem, so I give my solution here. Most of the time, smartphones have a minimum limit for font-size.
You have to change all your rem value, and divide it by 3 or 4.
Then, you have to change the javascript with :

$("html").css({"font-size": ($(window).height()/25)+"px"}); /*(this is if you divide with 4)*/

It is even easier if you are using SASS, you can create a rem function which will do division for you.

###

Nearly a year to late, but I want also to share my solution to this more and more important problem.

I created a small JS function SET which is loaded after the DOM is completed.

Every Element assigned to a special class (In this case “.pheight”) doesn’t resized when the viewport height decreases. It is only allowed to resize if the viewport height increases or the viewport width changes.

So in my Applications it works perfectly!

  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());

###

In Angular 4+

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'`
);
}

###

You could use % which doesn’t seems to be affected by this issue or vw (not affected for obvious reason) even for height.

###

The same problem put me off my stride. I don’t found any css solution or workaround in order to solve the problem.

However, if you can use JQuery (or almost JavaScript), I have some code you can use to resolve it.

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

Well, this is just an example, you can use the percentage, jQuery identifiers you need to.

PD: there’s one tip for your info. put the code at the final of your html or inside $(document).ready(function() { }); , and if you need responsive design, put it also inside orientationchange event; this way.

$(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 put a 450ms Timer above because of the delay of devices doing the orientationchange.

Sorry for my english,
cheers

Leave a Reply

Your email address will not be published. Required fields are marked *