With the iPhone X’s notch came viewport-fit=cover
and safe-area-inset
, as explained here. It turns out that safe-area-inset
is 0 on iOS11 devices that are not the iPhone X. This may sound logical, but I wonder if it is. Also, the value remains static, even when you zoom in.
Note: testing for this article was done exclusively on Apple’s simulator.
To recap briefly:
viewport-fit=cover
, when added to the meta viewport, ensures the site takes over the entire screen, even the space below the notch, if applicable.safe-area-inset-dir
(where dir is left, right, top, or bottom) gives the safe areas you should apply if you want enough margin or padding to prevent your site from being obscured by the notch.Let’s treat viewport-fit=cover
first. When applied on the iPhone X, your sites now stretches into the space below the notch, as advertised. When applied on any other device with iOS11, nothing happens. That’s logical: the viewport is already stretched to its maximum and there is no notch to avoid or stretch under.
In other words, viewport-fit=cover
can be added to any site and will fire only when applicable. Keep that in mind.
safe-area-inset
should be added as a padding (or, I suppose, a margin) to elements or the entire page. Its value on the iPhone X, in case you’re wondering, is 44px. This value could conceivably be different on future models where the notch is larger or smaller, so using a constant that may change from model to model is a good idea.
But what is its value on iOS11 devices that are not the iPhone X and have no notch? It turns out it’s 0px. This may sound logical as well, since there is no notch and thus no safe area, but is it?
My problem is the following. Suppose I have this:
element { padding-left: 10px; padding-left: constant(safe-area-inset-left); }
What I want to do here is give the element a padding-left of 10px, except when a notch is present, then I want to give it a pading-left equal to the safe area (44px). This works absolutely fine on the iPhone X and in non-iOS browsers. In the former the initial 10px values is overwritten by the safe area, while the latter don’t understand the safe area and ignore the second rule.
Problem is: on iOS11 devices other than the iPhone X this misfires and gives the element a padding-left of 0. Thus, safe-area-inset
fires even when it’s not applicable. I do not find this logical at all. As far as I can see, safe-area-inset
should simply be absent when there is no safe area to describe. And 0 is not the same as absent.
As far as I’m concerned Apple should remove safe-area-inset
entirely from devices that do not need it. Thus we web developers do not need to worry about the notch. We write a tiny bit of CSS for the notch, and can rest assured that the CSS will not fire when it’s absent.
The official post notes that you should use the following instead, but also notes that max()
is not supported by the current Safari/iOS version, which makes the advice a bit pointless:
element { padding-left: max(10px,constant(safe-area-inset-left)); }
So they kind-of admit there might be a problem, but offer an as-yet-unavailable solution. Also, as far as I’m concerned this tip-toes around the fundamental problem of having a safe area of 0 where none is needed.
There’s another problem as well: safe-area-inset
is not adjusted when the user zooms, even though, at high zoom levels, the safe area becomes comically large. Even when I’m zoomed in to the maximum level on an iPhone X, the safe area is still 44px, though that now means about one-third of the screen.
I can understand why Apple did this. If safe-area-inset
would become zoom-dependent, the browser would have to run re-layouts every time the user zooms, changing the calculated padding-left on every applicable element. This is likely to be a costly operation.
Still, the conclusion must be that safe-area-inset
also misfires whenever the user zooms in.
So we have to write a notch detection script. Fortunately it’s quite simple: create a test element, apply the safe-area-inset
and see if its value is larger than 0. If so, a notch is present.
function hasNotch() { if (CSS.supports('padding-left: constant(safe-area-inset-left)')) { var div = document.createElement('div'); div.style.paddingLeft = 'constant(safe-area-inset-left)'; document.body.appendChild(div); var calculatedPadding = parseInt(window.getComputedStyle(div).paddingLeft); document.body.removeChild(div); if (calculatedPadding > 0) { return true; } } return false; }
Still, I would argue that the very need for such a script means safe-area-inset
has not been implemented quite properly.
This is the blog of Peter-Paul Koch, web developer, consultant, and trainer.
You can also follow
him on Twitter or Mastodon.
Atom
RSS
If you like this blog, why not donate a little bit of money to help me pay my bills?
Categories: