What are layout margins, how do they differ from the safe area, and what changes in a right-to-left language?
Predict first
What do the margins read, and what does a guide-pinned child get in left-to-right and right-to-left?
import UIKit
let host = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 400))
let c = UIView(); c.translatesAutoresizingMaskIntoConstraints = false; host.addSubview(c)
let g = host.layoutMarginsGuide
NSLayoutConstraint.activate([c.leadingAnchor.constraint(equalTo: g.leadingAnchor), c.trailingAnchor.constraint(equalTo: g.trailingAnchor),
c.topAnchor.constraint(equalTo: g.topAnchor), c.bottomAnchor.constraint(equalTo: g.bottomAnchor)])
print(host.layoutMargins.left, host.insetsLayoutMarginsFromSafeArea, host.preservesSuperviewLayoutMargins)
host.layoutIfNeeded(); print(c.frame)
host.directionalLayoutMargins = NSDirectionalEdgeInsets(top: 20, leading: 30, bottom: 0, trailing: 10)
host.semanticContentAttribute = .forceRightToLeft
host.layoutIfNeeded(); print(c.frame)
- 8.0 true false, (8, 8, 284, 384), then (10, 20, 260, 380)
- 16.0 true false, (16, 16, 268, 368), then (30, 20, 260, 380)
- 8.0 false true, (8, 8, 284, 384), then (30, 20, 260, 380)
Mental model. The margin is the picture frame’s mat; the safe area is the part of the wall the cabinet does not cover. Content sits inside both.
Every UIView has layout margins: an inset (default 8 points on all sides for a plain view) that says how much breathing room content should keep from the edges. layoutMarginsGuide is a layout guide for the rectangle inside them, so you pin content to it instead of to the edges. The safe area is a different thing: the part of the view not covered by system chrome (safeAreaInsets, read-only, zero until the view is in a window). The two combine: with insetsLayoutMarginsFromSafeArea true (the default) the effective margins are at least the safe-area insets. A child view does not inherit its parent’s margins unless preservesSuperviewLayoutMargins is true (default false); readableContentGuide is a further guide that limits line length for text on wide screens.
Set margins with directionalLayoutMargins (leading and trailing), not layoutMargins (left and right): the directional version flips automatically in a right-to-left layout, as the check below shows with the same numbers landing on opposite sides. Margins are cheap, theme-able, and the UIKit-native way to give a container padding that children respect, which is why stack views and table cells use them. Adjusting them from a view controller is done with viewLayoutMarginsDidChange() or by setting them on view and on child containers, not by hard-coding constants in every constraint.
The default margin is 8 on every side, a view does not preserve its superview’s margins, and in right-to-left the 30-point leading margin lands on the right, so the child starts at x = 10.
Common traps
- Using
layoutMargins(left/right) in code that must support Arabic or Hebrew. Use the directional version so leading and trailing flip. - Expecting a child to inherit a parent’s margins. It only does if you set
preservesSuperviewLayoutMargins.
They might follow up with
- Why is
safeAreaInsetszero in a unit test? The view is not in a window yet. - How do margins relate to the safe area? With
insetsLayoutMarginsFromSafeAreathe margins grow to clear it.
Related questions
- 7.7.2 What is the safe area, and how do you keep content clear of the notch, home indicator and keyboard?
- 24.3.1 How do you support right-to-left languages: leading and trailing, semantic content attributes, flipping…
- 9.1.1 How does Auto Layout work, and what are intrinsic size, content hugging, compression resistance, priorities…
What rules does UIStackView follow: hidden views, distribution, who… →