While the new CSS viewport units like svh, dvh, and lvh bring good improvements for developers for determining viewport size with or without dynamic toolbars on mobile devices, I noticed they sometimes cause issues on iOS devices. In this article, I will delve into several bugs I found, and propose simple solutions utilizing both JavaScript and CSS techniques.
Two years ago, around the time iOS 15 was released, the UI of many mobile browser stated to change – some browsers started to move the address bar to the bottom. Not sure when this happened on Android phones, but for iPhones, it was autumn 2021 with the launch of iOS 15. I think one of the reasons behind this idea was that phones screens were getting larger over time and it forced UI designers to rethink their UIs, as having the address bar at the bottom in mobile browsers is easier to reach and type. On the other hand, this reminds me that Steve Jobs was wrong with his prediction about 3.5″ being the perfect size for a smartphone. When first iPhone arrived in 2007, he had said:
“We’ve designed something wonderful for your hand, just wonderful.”
He also insisted on the iPhone not being bigger than 3.5″ so that it can be easily operated with one hand. While I agree with him that being able to use your phone with one hand is “handy”, I can’t imagine going back to my old iPhone SE 2 after getting the iPhone 13. It just does not work this way. Once you move to a bigger phone, you can’t really go back. For me having a bigger screen is a better even if it means you can’t use it with one hand.
Anyway, Android and iOS both now allow user to move the address bar at the bottom to make it easier to operate with one hand. However, this led to some strange CSS issues for web designers and developers. Elements like hero images, hamburger menus, or popups that normally need to span 100% height were becoming too tall or glitchy while scrolling down. This is because the 100vh rule now includes the bar at the bottom, so if you set a div to 100vh, it will end up being taller that the actual viewport height. To be frank, I am not sure how this works on Android, but on iOS many things related to 100vh started to break.
New CSS units: dvh, svh and lvh
Yes, I am aware that currently you can use the new CSS units: dvh, svh and lvh. But there is one problem – since my clients care about how their websites look like in messenger apps, I realized that these new units not necessarily work as they should in those built-in browsers. For example, the most popular communicator app in Taiwan is Line, which on iOS should be running Safari under the hood, but still – dvh, svh and lvh were simply being ignored when I was testing my websites in those browsers/apps. For example, everything was working good in Safari, but a browser built-in in the Line communicator the new unites were being ignored. This is weird since on iOS everything runs in Safari under the hood, and according to caniuse website, Safari on iOS fully supports these new units since 2022. Interestingly, third party browsers like Kagi were also not respecting these units. For example, on the video below, I uploaded a simple website with a hero image and a block of text. The wrapper of the hero section is 100svh, so the size of the hero should stay the same while scrolling down as svh stands for “small vh”. Although, when I scrolled down, the whole layout shifted as it does with dvh (“dynamic vh”):
I know that this is isn’t a common issue, but for me, I really needed the hero section to be the right size when opening my websites in various communicator apps. My customers often use Line and other communicators to share links to their websites. I think if you are not concerned about communicator apps, then you should be fine with svh, dvh, lvh.
Interestingly, navigator.userAgent will spit out the name of the app if you open a link in that app. For example, for Line it looks like this:
Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X)
AppleWebKit/605.1.15 (KHTML, like Gecko)
Mobile/15E148 Safari Line/14.1.1
So currently, to fix this issue I have came up with a hacky Javascript code that overrides the height of the hero for the Line browser:
const hero = document.querySelector(".hero");
if (navigator.userAgent.includes("Line") && hero) {
hero.style.setProperty("height", `${window.innerHeight}px`, "important");
}
This should not cause any CLS as long as you make it 100svh on load, because svh works good on the first load:
.hero {
height: 100svh;
}
It's not the most elegant solution, but it should work until the support of dvh, svh and lvh improves in the messenger apps and other alternative browsers. Let me know in the comments section what you think about this, perhaps there is a better way to fix this.