The problem can be solved with a media query and some math. Here's a solution for a portait orientation:
@media (max-device-aspect-ratio: 3/4) {
height: calc(100vw * 1.333 - 9%);
}
@media (max-device-aspect-ratio: 2/3) {
height: calc(100vw * 1.5 - 9%);
}
@media (max-device-aspect-ratio: 10/16) {
height: calc(100vw * 1.6 - 9%);
}
@media (max-device-aspect-ratio: 9/16) {
height: calc(100vw * 1.778 - 9%);
}
Since vh will change when the url bar dissapears, you need to determine the height another way. Thankfully, the width of the viewport is constant and mobile devices only come in a few different aspect ratios; if you can determine the width and the aspect ratio, a little math will give you the viewport height exactly as vh should work. Here's the process
1) Create a series of media queries for aspect ratios you want to target.
use device-aspect-ratio instead of aspect-ratio because the latter will resize when the url bar dissapears
I added 'max' to the device-aspect-ratio to target any aspect ratios that happen to follow in between the most popular. THey won't be as precise, but they will be only for a minority of users and will still be pretty close to the proper vh.
remember the media query using horizontal/vertical , so for portait you'll need to flip the numbers
2) for each media query multiply whatever percentage of vertical height you want the element to be in vw by the reverse of the aspect ratio.
- Since you know the width and the ratio of width to height, you just multiply the % you want (100% in your case) by the ratio of height/width.
3) You have to determine the url bar height, and then minus that from the height. I haven't found exact measurements, but I use 9% for mobile devices in landscape and that seems to work fairly well.
This isn't a very elegant solution, but the other options aren't very good either, considering they are:
Having your website seem buggy to the user,
having improperly sized elements, or
Using javascript for some basic styling,
The drawback is some devices may have different url bar heights or aspect ratios than the most popular. However, using this method if only a small number of devices suffer the addition/subtraction of a few pixels, that seems much better to me than everyone having a website resize when swiping.
To make it easier, I also created a SASS mixin:
@mixin vh-fix {
@media (max-device-aspect-ratio: 3/4) {
height: calc(100vw * 1.333 - 9%);
}
@media (max-device-aspect-ratio: 2/3) {
height: calc(100vw * 1.5 - 9%);
}
@media (max-device-aspect-ratio: 10/16) {
height: calc(100vw * 1.6 - 9%);
}
@media (max-device-aspect-ratio: 9/16) {
height: calc(100vw * 1.778 - 9%);
}
}