コンテンツへスキップ

ボタン内にImageをネストする代わりに.labelStyle(.iconOnly)を使う

アクセシビリティを損なわず可読性を犠牲にしない、アイコンのみのボタンの適切なSwiftUIパターン。

フレームワークと戦うのをやめる

SwiftUIコードで頻繁に見かけるパターンが、Buttonのlabelクロージャ内にImageを直接配置してアイコンのみのボタンを手動で作成するものです。見た目は機能しますが、アクセシビリティ情報が失われ、SwiftUIの設計思想に反しています。

間違ったやり方

Button {
   toggleSidebar()
} label: {
   Image(systemName: "sidebar.left")
}

これはタップ可能なアイコンをレンダリングしますが、VoiceOverが読み上げるための意味のあるラベルがありません。ユーザーには「ボタン」や生のSF Symbol名のようなものが聞こえ、役に立ちません。

正しいやり方

Button("Toggle Sidebar", systemImage: "sidebar.left") {
   toggleSidebar()
}
.labelStyle(.iconOnly)

またはLabelを明示的に使用します:

Button(action: toggleSidebar) {
   Label("Toggle Sidebar", systemImage: "sidebar.left")
}
.labelStyle(.iconOnly)

Code comparison showing the wrong way versus the right way

なぜ重要なのか

Labelビューはタイトルとアイコンの両方を保持します。.labelStyle(.iconOnly)を適用すると、SwiftUIは視覚的にはタイトルを非表示にしますが、アクセシビリティツリーには保持します。VoiceOverは「Toggle Sidebar、ボタン」と読み上げます。これはまさにユーザーが聞く必要がある内容です。

このパターンはコードの適応性も向上させます。後でアイコンの横にテキストを表示することにした場合(例えばiPadのツールバーで)、ラベルスタイルを.titleAndIconに変更するだけです。構造の変更は不要です。

ボタン以外への応用

同じ原則はLabelを受け取るすべてのビューに適用されます:NavigationLinkTogglePicker、メニューアイテム。単独のImageを使いたくなったときは、スタイルモディファイア付きのLabelの方が適切ではないかを自問してください。ほとんどの場合、そちらの方が適切です。

参考になりましたか?BlueskyMastodonでフォローして、Swiftのヒントやインディー開発の最新情報をチェックしてください。