10

Unfortunately 100vh is not always the same as 100% browser height as can be shown in the following example.

html,
body {
    height: 100%;
}

body {
    overflow: scroll;
}

.vh {
    background-color: blue;
    float: left;
    height: 50vh;
    width: 100px;
}

.pc {
    background-color: green;
    float: left;
    height: 50%;
    width: 100px;
}
<div class="vh"></div>
<div class="pc"></div>

The issue is more pronounced on iPhone 6+ with how the upper location bar and lower navigation bar expand and contract on scroll, but are not included in the calculation for 100vh.

The actual value of 100% height can be acquired by using window.innerHeight in JS.

Is there a convenient way to calculate the current conversion of 100vh to pixels in JS?

I'm trying to avoid needing to generate dummy elements with inline styles just to calculate 100vh.

For purposes of this question, assume a hostile environment where max-width or max-height may be producing incorrect values, and there isn't an existing element with 100vh anywhere on the page. Basically, assume that anything that can go wrong has with the exception of native browser functions, which are guaranteed to be clean.

The best I've come up with so far is:

function vh() {
    var div,
        h;
    div = document.createElement('div');
    div.style.height = '100vh';
    div.style.maxHeight = 'none';
    div.style.boxSizing = 'content-box';
    document.body.appendChild(div);
    h = div.clientHeight;
    document.body.removeChild(div);
    return h;
}

but it seems far too verbose for calculating the current value for 100vh, and I'm not sure if there are other issues with it.

zzzzBov
  • 174,988
  • 54
  • 320
  • 367

2 Answers2

4

How about:

function viewportToPixels(value) {
  var parts = value.match(/([0-9\.]+)(vh|vw)/)
  var q = Number(parts[1])
  var side = window[['innerHeight', 'innerWidth'][['vh', 'vw'].indexOf(parts[2])]]
  return side * (q/100)
}

Usage:

viewportToPixels('100vh') // window.innerHeight
viewportToPixels('50vw') // window.innerWidth / 2
fixmycode
  • 8,220
  • 2
  • 28
  • 43
  • 2
    Wrong, `innerHeight` is not `100vh` on iOS http://output.jsbin.com/diwoyevive/quiet – yckart May 30 '16 at 16:42
  • 1
    @yckart you are right, but it could be useful to solve this problem : https://medium.com/@susiekim9/how-to-compensate-for-the-ios-viewport-unit-bug-46e78d54af0d ; thus, replacing `100vh` with `innerHeight` it is the solution used by react-div-100vh component – Marcel Falliere Mar 13 '19 at 10:38
0

The difference comes from the scrollbar scrollbar.

You'll need to add the height of the scrollbar to the window.innerHeight. There doesn't seem to be a super solid way of doing this, per this other question:

Getting scroll bar width using JavaScript

Charlie
  • 8,530
  • 2
  • 55
  • 53
  • There are a variety of other browser features in addition to scroll bars that cause 100vh to differ significantly from 100% height. – zzzzBov Jul 12 '19 at 04:42
  • what else is there? – Charlie Jul 12 '19 at 14:35
  • I covered a couple in the question. Particularly the iPhone location and navigation bars which make 100% height smaller, but do not affect 100vh. – zzzzBov Jul 12 '19 at 14:48