開発者向け
iPhone Duo のセーフエリアとコンテンツマージン:開発者ガイド
iPhone Duo ではコントロールが画面の横に並ぶため、セーフエリアとマージンが左右で異なります。水平方向のインセットへの対応と、iOS 27.1 の .contentMargins(for: .container) を解説します。
AppleDuo 編集部公開 13分で読めます
このページの内容
長年、iPhone のセーフエリアは主に上下の問題でした。上にはノッチや Dynamic Island、下にはホームインジケータがあるだけでした。iPhone Duo のセーフエリアは違います。ナビゲーション、ツールバー項目、ステータス情報、Live Activities がディスプレイの横に沿った1本の縦のバーに同居することがあるため、左右のインセットが等しくないことがよくあります。このガイドでは、何が変わったのか、SwiftUI と UIKit でどの API を使うべきか、そしてリリース前にレイアウトをどう確認するかを解説します。
ここに書いた内容はすべて、Apple の iPhone Duo の Tech Talk、Apple のドキュメントと開発者フォーラムでの回答、そして iOS 開発者 @sarunw の投稿に基づいています。私たちはこれらの API を実機でテストしていません。ほとんどは iOS 27.1 と Xcode 27.1 で登場したものなので、リリース間で詳細が変わる可能性があります。
iPhone Duo のセーフエリアが左右で不均等なのはなぜ?
iPhone Duo では、多くのコントロールが画面の上下から横へ移動します。Apple の Tech Talk「Design for iPhone Duo」でははっきりと、コントロールはデバイスの横に沿って配置され、ほとんどのコンテンツはコントロールの後ろに隠れないようオフセットが必要だと説明されています。縦のバーについては、iPhone Duo の縦型ツールバーのガイドで詳しく解説しています。
このオフセットが水平方向のセーフエリアのインセットです。Apple は「Prepare your app for iPhone Duo」で、セーフエリアは「多くの場合非対称」だと述べています。特に iPhone Duo では、横向きのときや Split View のマルチタスク中に、縦に並んだボタンが左側に現れることがあります。Split View では反対側の端にも別のアプリのコントロールが来ることがあるので、両側に注意が必要です。
縦のバーは読む方向ではなくハードウェアに従います。右から左に書く言語でもデバイスの同じ側に留まるので、「バーのある側」を leading や trailing に対応させないでください。各辺の実際のインセットを読み取ってください。
水平方向のセーフエリアのインセットにはどう対応する?
Apple のルールは短く、反対側の辺のインセットが等しいと想定しないこと、です。前景のコンテンツはセーフエリア内にレイアウトし、背景はその下まで広げ、サイズは片側からではなくインセットした矩形から計算します。
SwiftUI はデフォルトでコンテンツをセーフエリア内に配置します。UIKit については、Apple の Tech Talk でよくある間違いとその修正方法が示されています。
// 避ける:左右のインセットが等しいと想定している
let width = view.bounds.width - view.safeAreaInsets.left * 2
// 各辺を個別に扱う
let width = view.bounds.inset(by: view.safeAreaInsets).width
1行目は左のインセットを2倍にしているので、バーが片側にしかない場合は常に誤りになります。2行目は各辺を個別に差し引くので、どのデバイスでもどの姿勢でも正しく動作します。
背景については、Apple は SwiftUI では .ignoresSafeArea() を、UIKit では背景ビューを view.bounds のサイズにすることを推奨しています。「Design for iPhone Duo」の講演では組み合わせも提案されています。インタラクティブな要素がすべてインセットした領域内に収まっている限り、画面幅いっぱいの背景画像やヘッダーと、インセットしたスクロール可能な前景コンテンツを組み合わせてもよい、というものです。
縦のバーの下のスクロールコンテンツはクリップする必要がある?
いいえ。開発者フォーラムで Apple のエンジニアは、バーのある側のセーフエリアのインセットは自動的にスクロールビューのコンテンツインセットになるので、すべてのコンテンツに届くままだと説明しています。手動でクリップしないでください。
iPhone Duo の不均等なマージンとは?
セーフエリアはシステムの UI がどこにあるかを教えてくれます。マージンは、コンテンツをコンテナの端からどれだけ離すべきかを教えてくれます。iPhone Duo では、どちらも左右で異なることがあります。
@sarunw によると、iPhone Duo のマージンは片側が 20 ポイント、バーの隣が 0 です。これは新しいコンテナのマージンガイドについての Apple のドキュメントとも一致しています。そこでは、システムのレイアウトマージンは iPhone で 16〜20 ポイントの範囲であり、iPhone Duo では縦のバーの隣にあるとき、デバイスの左右で異なる値を適用する非対称なマージンになることもあると説明されています。Apple の Tech Talk はその理由を、非対称なマージンによって前景のコンテンツが縦のボタンやステータスバーに近づきつつ、反対側のマージンは保たれるからだと説明しています。
正確なポイント値は開発者の観察によるもので、Apple の仕様ではありません。Apple のガイダンスは、これらの値をレイアウトに書き込むのではなく、ガイドを読み取るか適用することです。
| 概念 | 何を測るか | iPhone Duo では |
|---|---|---|
| セーフエリアのインセット | バーやカメラなどのシステム UI が占めるスペース | 縦のバーがある側で大きくなる |
| レイアウトマージン(UIKit) | ビューの端とコンテンツの間の推奨スペース | 非対称。iOS 27.1 では UIView のデフォルトはゼロ |
| コンテナのコンテンツマージン(SwiftUI) | ビューが置かれているコンテナのシステムマージン | iPhone では 16〜20 ポイント。バーの隣では不均等になることがある |
SwiftUI で .contentMargins(for: .container) を使うには?
iOS 27.1 では、ContentMarginGuide の分だけビューをインセットするモディファイア contentMargins(for:edges:alignment:) が追加されました。SwiftUI が提供するガイドは container の1つで、「ビューが置かれているコンテナのマージン」と説明されています。edges パラメータのデフォルトはすべての辺で、alignment は省略可能です。
以下は Apple のドキュメントにある例です。グリッドを水平方向のシステムマージンに揃えています。
NavigationStack {
AlbumGrid()
.contentMargins(for: .container, edges: .horizontal)
}
指定しなかった辺は、ガイドにその辺の値があっても変わりません。そのため、水平方向のマージンが変化する iPhone Duo には .horizontal がよく合います。
ビューが提案されたサイズを埋めない場合、alignment によってマージン内での位置が決まります。Apple のドキュメントでは、コンテナのマージンの右下(bottom-trailing)の角に置かれる作成ボタンを例にしています。
ZStack {
MessageList()
ComposeButton()
.contentMargins(
for: .container, alignment: .bottomTrailing)
}
これは、スクロールコンテンツなどの配置に固定の長さを設定する、従来の contentMargins(_:for:) や contentMargins(_:_:for:) とは別のモディファイアです。新しいほうは数値ではなくガイドを受け取るので、値がデバイス、コンテナ、姿勢に応じて変わることができます。
GeometryProxy からマージンを読み取る
ビューを手動でレイアウトする場合、GeometryProxy に EdgeInsets を返す contentMargins(for:edges:) が追加されています。これは既存の safeAreaInsets と並んで使えます。
GeometryReader { proxy in
let margins = proxy.contentMargins(for: .container, edges: .horizontal)
let safeArea = proxy.safeAreaInsets
// iPhone Duo では margins.leading と margins.trailing が異なることがある。
CustomCanvas(leading: margins.leading, trailing: margins.trailing)
}
CustomCanvas はあなた自身のビューのプレースホルダーです。ポイントは、1つの値を想定するのではなく、両方の辺を別々に読み取ることです。
iPhone Duo の UIKit でレイアウトマージンはどう動く?
UIKit にはすでにレイアウトマージンとして layoutMargins、directionalLayoutMargins、layoutMarginsGuide があります。Apple の Tech Talk によると、iPhone Duo ではこれらもセーフエリアと同様に非対称になります。ビューコントローラのルートビューのマージンガイドにコンテンツを固定すれば、これらの値を自動的に反映できます。
知っておくべき変更が1つあります。マージンが壊れているように見えるというフォーラムのスレッドで、Apple のエンジニアは、iOS 27.1 では iPhone Duo で UIView のデフォルトのレイアウトマージンがゼロになり、この変更は iOS 27.2 でほかのデバイスにも適用されると説明しています。ビューコントローラは引き続き、ルートビューに systemMinimumLayoutMargins を与えます。サブビューでそれを継承するには、preservesSuperviewLayoutMargins を true に設定します。
NSLayoutConstraint.activate([
titleLabel.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
titleLabel.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor)
])
// ビューコントローラのマージンを継承させたいカスタムのサブビュー
cardView.preservesSuperviewLayoutMargins = true
カスタムのセルのコンテンツについて、同じエンジニアは UIView のデフォルトに頼るのではなく、UIListContentConfiguration.cell() から推奨される directionalLayoutMargins を読み取ることを提案しています。iPhone Duo でセルのパディングが突然なくなった場合は、まずここを確認してください。
縦のバーは古い SDK でビルドしたアプリにどう影響する?
アプリがディスプレイをどれだけ使えるかは、ビルドに使う SDK によって決まります。Apple は3つの段階を説明しています。
| ビルドに使ったもの | iPhone Duo での動作 |
|---|---|
| Xcode 26 以前 | アプリは見慣れたサイズとアスペクト比で動作し、ステータスバーやカメラの下には広がりません。閉じた状態では、ステータスバーとカメラの左側のスペースを使います。 |
| iOS 27 SDK | 内側ディスプレイで、アプリがステータスバー領域の左側まで広がります。 |
| iOS 27.1 SDK(Xcode 27.1) | アプリが画面の端まで広がります。標準のナビゲーションボタンとツールバーボタンは、ステータスバーの下に縦に並びます。 |
古いアプリも動作し続けますが、フル体験は得られません。iOS 27.1 SDK でビルドすると、コンテンツがバーの隣の端まで届くようになるため、ここから不均等なインセットとマージンが問題になり始めます。Apple はまた、iPhone Duo は UIRequiresFullScreen を尊重するものの、ユーザーがデバイスを開閉するとアプリはリサイズされると補足しています。
カメラは別のケースです。開発者フォーラムで Apple は、画面幅いっぱいのコンテンツを表示したい場合、セーフエリア全体を無視するのではなく occlusion 領域をクエリすることを提案しています。これらの API については、予約領域と折り目のガイドで解説しています。
リリース前に何を確認すべき?
Apple のデザインガイダンスは、レイアウトマージンと水平方向のセーフエリアのインセットを使ってレイアウトを構築し、固定幅、ブレークポイント、特定の画面に結び付いた指標を避けることです。そこから短いチェックリストが作れます。
- Xcode 27.1 と iOS 27.1 SDK でビルドし、iPhone Duo シミュレータで、閉じた状態、開いた状態、縦向き、横向きのすべての姿勢でアプリを実行する。
- コード内の
safeAreaInsets.left * 2のような計算を探し、bounds.inset(by:)や辺ごとの値に置き換える。 - 16 や 20 ポイントをハードコードしない。SwiftUI では
.contentMargins(for: .container, edges: .horizontal)を適用し、UIKit ではlayoutMarginsGuideに固定する。 - iPhone Duo では UIView のデフォルトのマージンがゼロになったため、パディングを失った UIKit のビューやセルがないか確認する。
- すべてのボタンとテキストフィールドをセーフエリア内に収める。端から端まで広げるのは背景と装飾的な画像だけにする。
- 別のアプリのコントロールが反対側の端に来ることがある Split View のマルチタスクをテストする。
- 右から左に書く言語をテストする。バーはデバイスの同じ側に留まる。
アプリ全体を対応させるなら、iPhone Duo 対応準備チェックリストで、この内容をサイズクラス、シート、ヒンジとあわせて確認できます。
まとめ:押さえておくべきポイントは?
- iPhone Duo ではコントロールが横に配置されることがあるため、水平方向のセーフエリアのインセットも上下と同じくらい重要です。
- 左右のインセットが一致すると決して想定しないでください。
bounds.inset(by: safeAreaInsets)を使うか、各辺を読み取ります。 - iOS 27.1 では、縦のバーの隣で不均等になりうるシステムマージンのために、
.contentMargins(for: .container, edges: .horizontal)とGeometryProxy.contentMargins(for:edges:)が追加されました。 - UIKit では
layoutMarginsGuideに固定し、iOS 27.1 の iPhone Duo では UIView のデフォルトのマージンがゼロであることに注意してください。 - 画面の端まで使うには iOS 27.1 SDK でビルドし、すべての姿勢、Split View、右から左のレイアウトをテストしてください。
次は、縦型ツールバーのガイドでシステムがバーを横に移動させる仕組みを読むか、Built for the Fold でディスプレイを最大限に活用しているアプリを見てみてください。
よくある質問
iPhone Duo でセーフエリアの左右のインセットが異なるのはなぜですか?
iPhone Duo では、縦のバー、ステータス情報、外側カメラなどのシステムのコントロールがディスプレイの片側に沿って配置されることがあります。その側のインセットはもう一方より大きくなるため、両側のインセットが等しいと想定したコードではコンテンツの位置がずれます。
.contentMargins(for: .container, edges: .horizontal) は何をしますか?
選んだ辺について、ビューが置かれているコンテナのシステムマージン分だけビューをインセットします。iOS 27.1 の SwiftUI で追加されたもので、iPhone Duo ではビューが縦のバーの隣にあるとき、左右でマージンが異なることがあります。
iPhone Duo で UIView のデフォルトのレイアウトマージンは変わりましたか?
はい。開発者フォーラムでの Apple のエンジニアの説明によると、iOS 27.1 では iPhone Duo で UIView のデフォルトのレイアウトマージンがゼロになり、同じ変更が iOS 27.2 でほかのデバイスにも適用されます。ビューコントローラは引き続き、ルートビューにシステムの最小マージンを与えます。
縦のバーの下に入り込むスクロールコンテンツはクリップする必要がありますか?
いいえ。Apple のエンジニアによると、その側のセーフエリアのインセットは自動的にスクロールビューのコンテンツインセットになるので、すべての項目に届くままです。手動でクリップすることは推奨されていません。
古い SDK でビルドしたアプリは iPhone Duo でどうなりますか?
引き続き動作します。Xcode 26 以前でビルドしたアプリは見慣れたサイズのままで、ステータスバーやカメラの下には広がりません。iOS 27.1 SDK でビルドすると、アプリは縦のバーがある状態で画面の端まで広がります。
出典
- Prepare your app for iPhone Duo · Apple Developer (Tech Talk)
- Design for iPhone Duo · Apple Developer (Tech Talk)
- Raise the bar with iPhone Duo · Apple Developer (Tech Talk)
- contentMargins(for:edges:alignment:) · Apple Developer Documentation
- ContentMarginGuide.container · Apple Developer Documentation
- GeometryProxy · Apple Developer Documentation
- Layout margins guides are still broken the iPhone Duo (sim) and 27.1 RC · Apple Developer Forums
- Horizontal scroll below tab bar · Apple Developer Forums
- iPhone Duo and the Safe-Area · Apple Developer Forums
- iPhone Duo has uneven margins: 20 points on one side, 0 next to the bar · @sarunw on X
- Safe areas aren't just at the top and bottom on iPhone Duo · @sarunw on X
- Safe area insets and content margins for iPhone Duo · @sarunw on X
- The vertical bar brings together Live Activities, status information, navigation and toolbar items · @sarunw on X
- Start with size classes, layout margins, and safe area insets · @sarunw on X
折りたたみを、アプリの一部に。
AppleDuo は iPhone Duo を本当に活かしたアプリとゲームを紹介しています。App Store へのリンクを添えて送ってください。ほかの開発者の作品も見られます。