How to access the real 100vh on iOS in CSS
Asked Answered
O

3

3

This is a self Q&A

If you've ever tried to use 100vh in CSS on iOS you will have found that it isn't actually 100vh when the browser chrome is expanded. It's a well documented bug that Apple decided was actually a feature! This is a good read to explain the bug.

So what is the best way to get around this "feature"? Ideally the answer requires no JavaScript (but that seems unlikely), should be clean, not require a bunch of inline styles, and ideally can be opted into in CSS (sometimes you might want the default 100vh).

Ostensive answered 16/11, 2019 at 1:45 Comment(0)
O
5

Set a root CSS var like so in your stylesheet:

// CSS vars
:root {
    --real100vh: 100vh;
}

Then in JavaScript, on load (or jQuery ready event) and on also on resize, you want to run this code:

    set100vhVar() {
        // If less than most tablets, set CSS var to window height.
        let value = "100vh"

        // If window size is iPad or smaller, then use JS to set screen height.
        if (window.innerWidth && window.innerWidth <= 1024) {
            value = `${window.innerHeight}px`
        }
        document.documentElement.style.setProperty("--real100vh", value)
    }

Now you can simply use the CSS: height: var(--real100vh); wherever you want 100vh to actually be the real 100vh on mobile, and this will simply work!

It looks better if you also add a transition: height 0.4s ease-in-out; on the same element, so it doesn't snap when you scroll down on mobile.

The advantage of using a CSS var to do this is that you can override this whenever you like, for example you might want certain breakpoints to be height: 500px, and this is hard to do if you use an inline style. You can also use this inside calc(), like height: calc(var(real100vh) - 100px); which is useful for fixed headers.

If you use Vue/Nuxt, take a look at how we have implemented that here.

UPDATE IN DEC 2022

You can achieve this without JS now, using CSS vars and media queries. Like so:

:root {
    --unit-100vh: 100vh;
}
@supports (height: 100dvh) {
    :root {
        --unit-100vh: 100dvh;
    }
}
Ostensive answered 16/11, 2019 at 1:45 Comment(1)
A demo would be nice!Tother
M
1

Depending on the needed browser support, the newest iteration of relative viewport units, for example dvh (dynamic viewport height) might be an option too.

When you want the viewport to be automatically sized in response to browser interfaces dynamically expanding or retracting, you can use the dynamic viewport size. The dynamic viewport size allows the content you design to fit exactly within the viewport, irrespective of the presence of dynamic browser interfaces.

Mohammedanism answered 28/11, 2022 at 15:6 Comment(2)
Yes, this 100dvh is the new correct answer to this problem! But it's not supported in all the major mobile browsers yet, but hopefully son it will be!Ostensive
Yes, in maybe a year it might be more practical. I would appreciate a +1. Still thanks for your QA, it helped me twice. :)Mohammedanism
V
-1

CSS Grid is the solution.

.grid-container {
  height: 100vh;
  grid-template-columns: 1fr;
  grid-template-rows: 30px 1fr 30px
}
Vilhelmina answered 31/5, 2020 at 10:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.