41

I want to get the exact viewport size when the soft keyboard is up. I am currently using the following code on the header in order for the site to be responsive:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>

What I realized is that when the soft keyboard comes up, it uses the device height as the viewport height and pushes the rest of the site upwards - which makes me assume that it's getting its height from the width=device-width option.

Using the following code after initiating the soft keyboard:

setTimeout(function() {  
    viewport = document.querySelector("meta[name=viewport]");
    viewport.setAttribute('content', 'height=auto');
}, 300)

And then getting the height using jquery shows CORRECT results on Android - aka the visible viewport size WITHOUT the virtual keyboard, but not on iOS. I am getting a random number, which I assume stems from the rest of the meta tag not existing, so I am getting a zoomed-in version of the website along with a number like 75 or 100 (on iphone 4s)

I also tried creating a fixed element after bringing the keyboard up, making it use the viewport height with top:0; and bottom:0; attributes, but I still get the original height.

What comes closer to this, is setting the viewport meta tag height to a fixed value, that can be picked up by jquery's $(window).height(), which means that the meta tag actually makes a difference after initiating the keyboard, but there is no true value for a fixed height.

I've seen lots of topics around this, but none with a solution. Anyone that has a solution for this?

danronmoon
  • 3,814
  • 5
  • 34
  • 56
scooterlord
  • 15,124
  • 11
  • 49
  • 68

10 Answers10

13

2022

You can now combine a window resize listener with the window.visualViewport.height property (which has a very good compatibility):

window.addEventListener('resize', () => {
  // For the rare legacy browsers that don't support it
  if (!window.visualViewport) {
    return
  }

  console.log(window.visualViewport.height)
})

Ivan Gabriele
  • 6,433
  • 5
  • 39
  • 60
7

In the view I wanted to take the height of the remaining screen after the virtual keyboard was on, I was using an absolutely overflown element that covered the whole screen using screen height and the content of the whole page was inside of it. As a result, the virtual keyboard was opening on TOP of the overflown element, without changing its dimensions.

To fix the specific problem, all I had was change the position of this element to static and remove the overflow when the virtual keyboard was opened - actually ios changes to THIS behaviour by default when issuing he virtual keyboard (changes elements to static position) and this is why the fixed elements become static.

I hope this helps.

Community
  • 1
  • 1
scooterlord
  • 15,124
  • 11
  • 49
  • 68
7

2023

New feature from 2022. Works great on Chrome and Firefox:
Add "interactive-widget=resizes-content" to your meta tag viewport

    <meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content">

Really suitable for my purpose

link

shA.t
  • 16,580
  • 5
  • 54
  • 111
5

The viewport dimensions come from the size of the UIWebView element.

As mentioned in the previous answer there are two ways to handle adapting to the on screen keyboard. You can resize the view or adjust the content insets.

The dimensions of the viewport on iOS are reporting the size of the view so resizing would adjust the viewport. Safari adjusts the insets and keeps the view the same size so the viewport does not change.

If you were to make assumptions that touch devices generally utilize on screen input rather than external keyboards you can programmatically adjust the size on your own by taking the device height or width depending on orientation and factor in a multiplier for portion of the screen consumed by the on screen keyboard.

I utilize a viewport class to act as a proxy to give me most likely real viewport dimensions rather than browser reported and binds to input elements to track state of input elements and orientation changes to dynamically modify the multiplier applied when requesting the viewport dimensions.

Community
  • 1
  • 1
Steve Buzonas
  • 5,300
  • 1
  • 33
  • 55
  • 1
    ..the problem is that there are different kinds of keyboard heights.. what if someone has jailbroken their device?.. but I guess in the end I'll go the 'manual' way, and just subtract the keyboard height – scooterlord Apr 29 '14 at 19:21
  • The input presentation is simply fundamentally different from android devices. This difference I believe is in attempt for a consistent user experience. I can see a UX nightmare if you have something responsive hiding elements on smaller viewports which would cause the site you were just viewing to completely change layout whenever you perform user input. There are two ways to handle cross browser support: 1) try to force everything your way. or 2) provide alternative presentations consistent with the standard user experience of that device/browser. IMO the latter is easier to handle. – Steve Buzonas Apr 29 '14 at 20:32
  • The contents of this answer are dated with the release of `iOS 8`. I'll try to remember to post another answer once I begin working with 3rd party keyboard support and Safari. – Steve Buzonas Nov 12 '14 at 21:38
  • @SteveBuzonas - you forgot? – ashleedawg Mar 16 '22 at 04:35
3

As of March 2021, window.innerHeight reflects the presence of a soft keyboard on iPad in chrome, firefox, safari browsers running IOS 14.4.1

den232
  • 682
  • 6
  • 14
  • 1
    I was excited to see this, but it didn't work for me, I get the same value whether or not the keyboard is shown when I run `window.innerHeight` in the console using my iPhone 12 simulator with iOS 14.5 – Nathan Manousos Sep 02 '21 at 18:03
  • 9
    Oh, but `window.visualViewport.height` works, however it changes when you zoom, which might not be desired. – Nathan Manousos Sep 02 '21 at 18:07
2

I've found myself with the same problem and after a while mixing CSS and a little bit of javascript, I found a solution.

Notes:

  • I used jQuery and SCSS
  • I preferred to hide the element instead of changing its position (simple and effective)
  • The element is shown if the virtual keyboard is closed but the input is still on focus. For this I wrapped the css rule in a media query @media screen and (min-aspect-ratio: 11/16). 11/16 because it's less than the common 9/16 ratio (the presence of the virtual keyboard increases this ratio then the rule is applied)

The solution:

First, the script (using jQuery):

$(document).on('focus', 'input, textarea', function(){
    $('body').addClass("fixfixed");
});

$(document).on('blur', 'input, textarea', function(){
    $('body').removeClass("fixfixed");
});

So, while the user focuses on a text input and the virtual keyboard is open, the body has a 'fixfixed' class.

Then, the CSS (I'm using SCSS):

.fixfixed{
  @media screen and (min-aspect-ratio: 11/16) {
    .bottomThingToHideWhenVirtualKeyboardIsShown{
      opacity: 0;
      pointer-events: none;
    }
  }
}

And that's it!

Hope it helps someone!

CamoNunez
  • 90
  • 6
  • i can see why this might work in portrait orientation, but can't see it working in landscape. Interesting idea nevertheless. – Teodor Sandu Feb 06 '18 at 16:05
  • This is the most reasonable solution I could find, having a specific JavaScript code to change the CSS and remove/add the fixed property upon focus/blur, enabled only for iOS app access (not browser). Thank you for sharing! – Eduardo Sztokbant Apr 04 '22 at 02:00
1

I came up with this hack:

var storedWidth = 0;
var storedHheight = 0;

function onResize() {

  var windowWidth = $(window).width();
  var windowHeight = $(window).height();
  var screenWidth = screen.width || windowWidth;
  var screenHeight = screen.height || windowHeight;
  var width, height;

  if(screenWidth < screenHeight) {
    if(windowWidth > storedWidth) storedWidth = windowWidth;
    if(windowHeight > storedHeight) storedHeight = windowHeight;
    width = storedWidth;
    height = storedHeight;
  }else {
    width = windowWidth;
    height = windowHeight;
  }

  //use width and height from here

}

Now this would fail in two cases:

  • screen.width/screen.height not being supported; it would fallback to the erroneous jquery dimensions. In my case, the soft keyboard made the height smaller than the width while in portrait mode, so the jQuery dimensions resulted in a false landscape mode and thus showing the 'rotate your device' message.

  • the page is opened with the soft keyboard opened, which I think is moot. Also after hiding it, the largest height is stored so things will be fixed after that.

Note:

  • window.innerWidth/window.innerHeight could be used to ditch the jQuery dependency

  • above code is to fix the keyboard issue in portrait mode, but same solution could be used for landscape mode

Will Kru
  • 5,164
  • 3
  • 28
  • 41
0

Just to give you an idea, when the keyboard appears on iOS by default it does nothing on the underlying scrollview.

If your content is shown in a custom UIWebView, it is up to the programmer to either:

  • Resize the scrollview to avoid getting unreachable content under the keyboard.

  • Adjust the scrollview's content insets (recommended). The scrollview size stays the same but a "border" is added to the bottom so the user can scroll all to all the contents.

I am not sure how either solution affects the viewport, but your could try both.

If your web content is being presented by Safari however, Apple adjusts the insets for you.

Rivera
  • 10,792
  • 3
  • 58
  • 102
  • 4
    Thanks for the reply, but I am talking about a website project, not an app, so it's meant for all devices. What I am looking for is a way to calculate the remaining height - which would be fairly easy to do if it was an app meant for specific devices, but this is not the case. I don't know about this border thing, but from the looks of it all the content if shifted UPWARDS than the keyboard being OVER it. – scooterlord Apr 24 '14 at 11:55
  • Maybe that's because the contents were scrolled all the way to the bottom before the keyboard showed up? – Rivera Apr 25 '14 at 00:59
  • ....although it seems like it, what I see is this. Currently using an overflown element that has the same height as the screen. So, when I tap on an input, it is centered and when I scroll up it moves UP to a point, after which, you have to stop scrolling to stop the bouncing and then it re-scrolls to the upper-most part. Scrolling at the bottom reaches the end of the document, so this leads me to believe that there's more space at the top of the screen, outside of it equal to the height of the soft keyboard.. I hope I am getting this across, kinda difficult to explain... – scooterlord Apr 25 '14 at 02:19
0

This solution is a bit convoluted, but it might work...

  1. Detect whether or not the keyboard is active.
  2. Grab the viewport width/height
  3. Subtract the height of the keyboard.
Community
  • 1
  • 1
James Hafner
  • 478
  • 2
  • 6
-1

Piece attempts to return approximate window.innerWidth, window.innerHeight values at ios6 ua; jquery utilized for selectors and .on(). Not certain about detecting ios device keyboard events portion; see resources links

Try

css

html {
    height : 100vh;
    width : 100vw;
}

js

$(function() {    
    if (/ipad|iphone/gi.test(window.navigator.userAgent)) {
    var events = "abort blur focus input scroll submit touchstart touchmove";
    $("form, input").on(events, function(e) {
      return (function(window, elem, w, h) {
               var vh = window.getComputedStyle(elem,null).getPropertyValue(h);
               var vw = window.getComputedStyle(elem,null).getPropertyValue(w);
               var vwh = { 
                           "documentWidth": vw, 
                           "documentHeight": vh, 
                           "windowInnerWidth": window.innerWidth, 
                           "windowInnerHeight": window.innerHeight
                         };
               console.log(vwh);
               var _vwh = document.getElementById("vwh");
               _vwh.innerHTML = JSON.stringify(vwh)
               return vwh 
              }(window, document.documentElement, "width", "height"));
    }).focus();
    };
})

jsfiddle http://jsfiddle.net/guest271314/Pv3N2/

resources

https://developer.mozilla.org/en-US/docs/Web/API/Window.innerHeight

http://www.w3.org/TR/2013/CR-css3-values-20130730/#vh-unit

how to handle key events in iphone

https://coderwall.com/p/xuawww Responding to Keyboard Events on iOS

http://looksok.wordpress.com/2013/02/02/ios-tutorial-hide-keyboard-after-return-done-key-press-in-uitextfield/ iOS tutorial: hide keyboard after return / done key press in UITextField

https://developer.apple.com/library/safari/documentation/InternetWeb/Conceptual/SafariVisualEffectsProgGuide/InteractiveControl/InteractiveControl.html#//apple_ref/doc/uid/TP40008032-CH16

http://www.quirksmode.org/mobile/viewports2.html

Community
  • 1
  • 1
guest271314
  • 1
  • 15
  • 104
  • 177
  • 3
    If you are looking to receive the bounty for this question, I suggest you describe what you are doing and why it works. – Fred Apr 27 '14 at 20:30
  • @Fred If interpret correctly, requirement include retrieving `viewport` region of `window` ? Piece at post should return array, , or string, including `window.innerHeight`, and `window.innerWidth` see https://developer.mozilla.org/en-US/docs/Web/API/Window.innerHeight , Tried at ff different viewport resolutions, returned (device) viewport resolutions , e.g (`[480, 320]`). At chromium ios (device) enabled, appeared to return `document.height` at same html ? Perhaps try piece ? Thanks – guest271314 Apr 28 '14 at 00:35
  • I recommend editing your answer to include the information you just commented, and try to be as logical as possible. – Fred Apr 28 '14 at 00:41
  • ..the issue is specifically for the iOS window height after soft keyboard is on – scooterlord Apr 28 '14 at 22:54
  • 1
    ..all of the above provides useful information, however, nothing I did not already know, nor do it helps me in any way to my problem. I still cannot measure accurately viewport height when soft keyboard is on, while there is width=device-width on the meta tag and an overflown scrolled element is used for the website. – scooterlord Apr 30 '14 at 23:02
  • 1
    This does not return the correct viewport height (indeed nothing I've found so far does) in iOS 9.2 with the software keyboard showing (it is ignored). – Michael Heilemann Jan 28 '16 at 20:15