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;
}
}