Convert vh units to px in JS
Asked Answered
U

2

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.

Umbilical answered 8/12, 2015 at 21:27 Comment(1)
Why do you need to get the pixel equivalent of 100vh anyway?Sandwich
P
3

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
Peltast answered 8/12, 2015 at 21:48 Comment(2)
Wrong, innerHeight is not 100vh on iOS output.jsbin.com/diwoyevive/quietCitronella
@Citronella you are right, but it could be useful to solve this problem : medium.com/@susiekim9/… ; thus, replacing 100vh with innerHeight it is the solution used by react-div-100vh componentAdaptable
S
-1

The difference comes from the 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

Sandwich answered 12/7, 2019 at 2:49 Comment(3)
There are a variety of other browser features in addition to scroll bars that cause 100vh to differ significantly from 100% height.Umbilical
what else is there?Sandwich
I covered a couple in the question. Particularly the iPhone location and navigation bars which make 100% height smaller, but do not affect 100vh.Umbilical

© 2022 - 2024 — McMap. All rights reserved.