Notes

Issues with making mobile screens take full height `100vh`

Edit on GitHub


CSS & Sass
2 minutes
  • 100vh does not take into account the browser bar or the navigation menu.
  • On iOS Safari and Google Chrome, the viewport will not resize in response to the URL being shown or hidden. This is a compromise by design, to avoid page jarring, reflows and relayout.

100vh on Android 8.0.0 - Chrome 70.0.3538.110 100vh on iOS 12.1 - Safari 12

The workaround

Calculate the window’s innerHeight, and use that as a CSS variable instead of vh

1let vh = window.innerHeight * 0.01;
2document.documentElement.style.setProperty('--vh', `${vh}px`);
1.element {
2  height: 100vh; /* Fallback */
3  height: calc(var(--vh, 1vh) * 100);
4}
  • var(--vh, 1vh) will evaluate to var(6.67px, 1vh) on an iPhone 6/7/8 (667px high).
  • the first argument is the custom property name --vh in this case, and the second argument is the desclaration value 1vh which serves as the fallback if the first argument is invalid. So, use calculated --vh, and if it’s not available, use 1vh.
var( <custom-property-name> [, <declaration-value> ]? )

In the wild

Here is how you’d do a 100vh above the fold layout with a header, hero area and footer..

1.layout-above-the-fold {
2  height: 100vh;
3  height: calc(var(--vh, 1vh) * 100);
4}
5
6.logo { height: calc(var(--vh, 1vh) * 20); }
7.hero { height: calc(var(--vh, 1vh) * 65); }
8.footer { height: calc(var(--vh, 1vh) * 15); }

Although, instead of using fixed heights for elements, using something like Flexbox or CSS grid is a better option.