Welcome to “Notch chat”.

I’m not sure what it is with web front-end dev, that most of the time we’re happy to hit a button in Chrome devtools and tick the box in JIRA to say that the site was checked in multiple Android devices having never considered trying a real device. But show us a non existent iPhone with a notch and we’re downloading the simulator to fix a problem for future rich people.

But here we are, and — embarrassingly — here’s my two cents on building websites for the iPhoneX. Well, you know, without having actually seen one.

The first thing to say is don’t panic. You site will not be broken. Really it won’t. Well… depending on your level of perfectionism. And if you are a perfectionist, there are options – but this article is about exercising those options pragmatically.

Let’s start with a common site pattern, a responsive layered page with a full width hero and and a constrained central content column:

In portrait

In portrait mode, the notch in the iPhone X doesn’t effect regular (ie, not saved appcache/futurePWA™) websites. The UI essentially has the same behaviour as previous iPhones, where a the full UI at the top and bottom of the screen is visible on page load, but after scrolling down, the bottom bar disappears and the URL bar minimises.

the viewport changes on an iPhone X/iOS 11.0 in portrait

Here are the measurements for an iPhone 8 vs iPhone X in iOS11.0. Note I’ve included what the adjustments for 100vh, which for some time has presented the height of the screen to CSS as that when it is scrolled — in iOS and Android, not desktop — and not when the full UI is shown (dammit).

╔══════════════╦═══════════╦═══════════╦═══════════════╦══════╗
║ Portrait ║ Window ║ Document ║ UI Chrome ║ ║
╠══════════════╬═════╦═════╬═════╦═════╬════╦════╦═════╣100vh ║
║ ║ X ║ Y ║ X ║ Y ║top ║bot ║ all ║ ║
╠══════════════╬═════╬═════╬═════╬═════╬════╬════╬═════╬══════╣
║ 8 full UI ║375px║667px║375px║553px║70px║45px║115px║-75px ║
║ 8 scrolled ║375px║667px║375px║627px║40px║0px ║40px ║ yes ║
╠══════════════╬═════╬═════╬═════╬═════╬════╬════╬═════╬══════╣
║ 8+ full UI ║414px║736px║414px║621px║70px║45px║115px║-75px ║
║ 8+ scrolled ║414px║736px║414px║696px║40px║0px ║40px ║ yes ║
╠══════════════╬═════╬═════╬═════╬═════╬════╬════╬═════╬══════╣
║ X full UI ║375px║812px║375px║634px║94px║84px║178px║-114px║
║ X scrolled ║375px║812px║375px║748px║64px║0px ║64px ║ yes ║
╚══════════════╩═════╩═════╩═════╩═════╩════╩════╩═════╩══════╝
  • Notice that the X has the same 375px viewport width as the iPhone (not the 414px of the iPhone plus).
  • That new home-bar at the bottom and the bunny ears at the top take quite a lot of screen space when the full UI is shown. Hence the iPhone X only gains 81px in usable document height over an iPhone 8, but when scrolled, this increases to 121px.
  • Despite having a narrower viewport than the iPhone 8+, it has a taller viewport in every situation. At it’s full 100vh viewport it is almost a 1:2 aspect ratio, similar to browsers on the Samsung Galaxy S8 or LG G6.

In landscape

This is where it gets interesting, because we are now in notch territory. Using a phone in landscape has often been considered on the “edge-case” side of website development, but with increasingly larger viewports it’s becoming more mainstream, and is often more popular than more commonly tested-for ‘7” tablet’ device type that fits between phones and iPads.

The full size “square” of the iPhoneX screen is accessible in theory, but the notch and the rounded corners essentially sit over the top, obscuring your hard-earned pixels. To prevent bad-things™, the Safari team at Apple made the default setting letter-box your site so that the corners and notch never cover something important:

default website dimensions on an iPhone X/iOS 11.0 in landscape

So no panic is necessary, the notch (and rounded corners) won’t break your site. If you’re willing to dig deeper, you can access those “safe areas” on the left and the right, with a specific viewport meta tag ‘viewport-fit=cover’:

<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">

You wouldn’t want to do that on it’s own, because it does exactly what it says on the tin:

website dimensions on an iPhone X/iOS 11.0 in landscape with viewport-fit=cover

We’ve got our nice full-width hero back, but the content is now starting to be obscured by the browser UI in an annoying way. The navigation is absolutely positioned, so it too is partially obscured because it’s relative to the document’s zero-zero (a point which is behind the rounded corner and almost outside the boundaries of the physical phone itself).

The Safari webkit team have got us covered with a new concept that is implemented here and submitted to the W3C — safe-area constants (We’ll see how this plays out with Google’s submissions for shaped screens that was meant to deal with round Android watches).

But god-almighty I don’t want to tweak every element for this brave new world. I’m a perfectionist, not a masochist. I also want a solution that plays nicely with everything that’s gone before, and won’t need constant maintenance in the future when new content or blocks come along. Yes I want cake, but I want to eat it without looking over my shoulder, too.

The pragmatic approach

In essence I want everything to function like the iPhoneX default — where I never need to panic about obscured content — but then opt-out of that with specific use cases like the hero or the navigation.

This is the our solution so far:

And this is the CSS code (view it here on CodePen):

body {
padding: 0;
padding: 0
constant(safe-area-inset-right)
0
constant(safe-area-inset-left);
}
.hero {
margin: 0;
margin: 0
calc(0px - constant(safe-area-inset-right))
0
calc(0px - constant(safe-area-inset-left));
}
.nav {
left: 15px;
left: calc(15px + constant(safe-area-inset-left));
}

Note that each property is specified twice — one of the beauties of CSS is that if the browser comes across a line it doesn’t understand, it just ignores it and falls back to the last instruction it can read. This redundancy can help make it safe to play with advanced features and preserve older behaviours.

This solution works because, even thought the viewport is now stretched the full width of the phone;

  1. The body has a left and right padding on it that kind of restores the default phone behaviour, adding the “safe-area” bars left and right.
  2. But now the full width of the screen is accessible to us. We can control a few specific items and position them more precisely, for instance the full width hero that has negative margins left and right to expand it out.
  3. Items that are absolutely positioned relative to the document also need to be dealt with.

Now we’ve got a quick solution that preserves the look of your website on the “iPhone of the future™” but by a method that means you don’t have to lose sleep about whether you’ve escaped every damned element in the CSS.

Here are the dimensions of the landscape world in an iPhone 6–8/+ and iPhone X both with and without viewport-fit=cover.

╔══════════════╦═══════════╦═══════════╦══════════════╦═════╗
║ Landscape ║ Window ║ Document ║ UI Chrome ║ ║
╠══════════════╬═════╦═════╬═════╦═════╬════╦════╦════╣100vh║
║ ║ X ║ Y ║ X ║ Y ║top ║bot ║all ║ ║
╠══════════════╬═════╬═════╬═════╬═════╬════╬════╬════╬═════╣
║ 8 full UI ║667px║375px║667px║325px║50px║0px ║50px║-50px║
║ 8 scrolled ║667px║375px║667px║375px║0px ║0px ║0px ║ yes ║
╠══════════════╬═════╬═════╬═════╬═════╬════╬════╬════╬═════╣
║ 8+ full UI ║736px║414px║736px║364px║50px║0px ║50px║-50px║
║ 8+ scrolled ║736px║414px║736px║414px║0px ║0px ║0px ║ yes ║
╠══════════════╬═════╬═════╬═════╬═════╬════╬════╬════╬═════╣
║ X full UI ║724px║375px║724px║325px║50px║0px ║50px║-50px║
║ X scrolled ║724px║375px║724px║375px║0px ║0px ║0px ║ yes ║
╚══════════════╩═════╩═════╩═════╩═════╩════╩════╩════╩═════╝
╔═══════════════════════════════════════════════════════════╗
║ with viewport-fit=cover ║
╠══════════════╦═════╦═════╦═════╦═════╦════╦════╦════╦═════╣
║ X full UI ║812px║375px║812px║325px║50px║0px ║50px║-50px║
║ X scrolled ║812px║375px║812px║375px║0px ║0px ║0px ║ yes ║
╚══════════════╩═════╩═════╩═════╩═════╩════╩════╩════╩═════╝
  • Note that this time, the height of the browser UI is exactly the same between all the phones.
  • Note that the viewport width of the iPhone X is above the viewport width of a portrait iPad. It’s definitely time to drop the unconscious assumption that a device in the 700–1000px width range is probably portrait, this phone is wider than an iPad but only 325px high at page-load time!

Of course, no battle plan survives meeting the enemy, so we’ll see what happens when the real phone starts appearing in our visitor logs. But I think we’re ready for them…