So there are various ways to size any element on a webpage.
We are familiar with common CSS units px, em, pt (and uncommon one cm, mm, in) with support from the first version of CSS (https://www.w3.org/TR/REC-CSS1/#units).
With newer viewport units, first support came in 2013 with FF and Chrome being the first ones quickly followed by Safari and Opera. (yes, IE used to suck even in those days).
Now with newer viewport units and a ton on mobile devices, the browser communities don’t seem to agree on how to implement them in mobile devices.
In mobile, vh seems to consider the address bar as part of the viewport (IDK why is it named as ‘view’port then).
On mobile 100vh !== 100%
This creates weird issues with mobile viewport heights like this:
Now this is an issue and indeed a very frustrating one, but we’ll discuss a couple of solutions one by one.
1. Use 100% instead of 100vh - “DOM tree nightmare”
Now the quickest, and most CSS way is to use 100% in your page for the whole DOM tree till your target element:
This will work correctly on both mobile and desktop websites. However it is very difficult to propagate 100% through every DOM node in the branch of your element, especially if it is buried deep in the tree (however, you might not come across too many use cases like this).
2. Use JS window.innerHeight for your element - “JS hack”
The second way is to use window.innerHeight for your target element, as on mobile, it will always give you the viewable height of the viewport, but again, this again creates a problem as you will have to write this tiny JS for each of your use cases.
So can there be an easy solution, which can give you the best of both worlds?
3. Use custom vh (CSS variable) - best of both worlds
So the solution, (you might find very few solutions floating around for this typeof
fix).
Before proceeding with this solution, let's see what are the cons to this. This solution involves using CSS variables (custom properties) and here https://caniuse.com/#search=css%20var, you can see that support for CSS variables came in early 2017 for major browsers, so you might need to think if you want to use this.
Step 1
So here we’ll be creating something like this:
Now what we have to do is set CSS variable --vh using window.innerHeight
.
window.addEventListener('resize', () => {
document.querySelector(':root').style
.setProperty('--vh', window.innerHeight/100 + 'px');
})
Now you will have --vh
available in your whole app.
Here comes the second step of this
Step 2
You can now use this variable anywhere in your code
height: calc(100 * var(--vh));
This works like vh (with a little too verbose representation).
- 100vh -
height: calc(100 * var(--vh));
- 10vh -
height: calc(10 * var(--vh));
- 1vh -
height: calc(1 * var(--vh));
And you can use it anywhere in your CSS code.
Top comments (8)
Is there any solution on the market?
Esp. on IOS14/Safari we have still the same issue (as already mentioned by Leonardo).
I also tried this:
width: -moz-available; /* WebKit-based browsers will ignore this. /
width: -webkit-fill-available; / Mozilla-based browsers will ignore this. */
width: fill-available;
But I cannot get it working.
Any advice to have a real height when the address bar gets away (I urgently need to have a "holy grail" design = fixed header + fixed footer and flexible content-area in the middle)?
Thanks for any direction...
This works for me in Chrome on desktop (i.e. it adds the --vh variable to the style of html), but it doesn't add the --vh variable to the style of html in Chrome on a Google Pixel 5. Is this because the --vh variable is only added when the viewport is resized?
(window.addEventListener('resize'...)
I also added a initial window loaded event, in addition to resize.
I had to add a separate event listener for window's load event to performing the same function to get it to work on mobile.
It is even worse, when you try to adjust to an activated mobile keyboard with 100vh :D
Yeah, seems like mobile browsers are unable to do an implementation of the viewport with simplicity. And 100% height is another nightmare in itself. 🤯
None of those worked on iOS 14
Will have to check on that.