The safe area API introduced at WWDC 2017 seemed at the time like a lot of work to accommodate the status bar, so I happily ignored it right until the introduction of iPhone X with its notch (ahem, “sensor housing”) and home indicator.

Since then, I’ve updated a whole bunch of projects for iPhone X, and this post compiles a few of the techniques I’ve been using across the board.

It’s going to take a while to adjust to the new constraints of an edge-to-edge display, rounded corners, and a much taller aspect ratio, and for new patterns to emerge from those. But in the meantime, I hope this post helps you in updating your existing designs to work on iPhone X.

Backwards Compatibility

One of the biggest issues when getting starting with using the new safe area API was backwards compatibility. Initially my code was littered with if #available(iOS 11, *) statements, and massive, mostly illegible lines such as:

controlsView.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -Constants.bottomPadding).isActive = true

Eventually I found a solution that solves both issues. Since I was just pinning to the normal anchors1 instead of safe area anchors for iOS <11, it made sense to use a unified anchor which handled that fallback case automatically.

Additionally, it simplified the syntax quite a bit, and now instead of calling view.safeAreaLayoutGuide.bottomAnchor, I can just use view.safeBottomAnchor and have the iOS <11 fallback case automatically covered as well.

All this was achieved with the following 30 line UIView extension:

//
//  UIView+SafeAnchors.swift
//

import UIKit

extension UIView {
	
	var safeTopAnchor: NSLayoutYAxisAnchor { return optionalSafeAreaLayoutGuide?.topAnchor ?? topAnchor }
	var safeBottomAnchor: NSLayoutYAxisAnchor { return optionalSafeAreaLayoutGuide?.bottomAnchor ?? bottomAnchor }
	
	var safeLeftAnchor: NSLayoutXAxisAnchor { return optionalSafeAreaLayoutGuide?.leftAnchor ?? leftAnchor }
	var safeRightAnchor: NSLayoutXAxisAnchor { return optionalSafeAreaLayoutGuide?.rightAnchor ?? rightAnchor }
	
	var safeLeadingAnchor: NSLayoutXAxisAnchor { return optionalSafeAreaLayoutGuide?.leadingAnchor ?? leadingAnchor }
	var safeTrailingAnchor: NSLayoutXAxisAnchor { return optionalSafeAreaLayoutGuide?.trailingAnchor ?? trailingAnchor }
	
	var safeCenterXAnchor: NSLayoutXAxisAnchor { return optionalSafeAreaLayoutGuide?.centerXAnchor ?? centerXAnchor }
	var safeCenterYAnchor: NSLayoutYAxisAnchor { return optionalSafeAreaLayoutGuide?.centerYAnchor ?? centerYAnchor }
	
	var safeWidthAnchor: NSLayoutDimension { return optionalSafeAreaLayoutGuide?.widthAnchor ?? widthAnchor }
	var safeHeightAnchor: NSLayoutDimension { return optionalSafeAreaLayoutGuide?.heightAnchor ?? heightAnchor }
	
	private var optionalSafeAreaLayoutGuide: UILayoutGuide? {
		if #available(iOS 11, *) {
			return safeAreaLayoutGuide
		} else {
			return nil
		}
	}
}

To .safeAreaLayoutGuide or not

Ok, now that the how is sorted out, on to deciding when the safe area anchors should be used instead of the normal ones.

It’s best to think that your actual app exists within the safe area; the parts of the display on either side of the notch and around home indicator are just meant to extend the appearance by blurring overscrolled content or showing a flat background color.

The easiest case is for static elements i.e. those which do not scroll. These should always be pinned to the safe area anchors. UIScrollView instances, however, should be pinned to the normal anchors.

Views within cells should be pinned to the normal anchors along the direction of scrolling, and to the safe area anchors otherwise. So for a vertical scrolling table/collection view, you’d pin the leading, trailing, left, right, width, and centerX anchors using safe area anchors, and the top, bottom, height, and centerY anchors using normal anchors.

Conclusion

This was a super brief post only meant to cover some techniques I’ve been using in updating my apps for iOS 11 and iPhone X.

For those looking for more, I’d recommend the following pieces:


  1. This is a weird name, but since I can’t think of a better or official one, I’m gonna be using it throughout this post. Let me know if you have any better ideas