axiom-hig-ref by charleswiltgen/axiom
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-hig-ref人机界面指南(HIG)定义了 Apple 的设计理念,并为在所有 Apple 设备上创建直观、可访问、适合平台的体验提供了具体指导。
每个设计决策都应支持以下原则:
1. 清晰度 内容至上。界面元素应让位于内容,而非与之竞争。每个元素都有其目的,不必要的复杂性被消除,用户应能立即知道他们可以做什么,而无需大量说明。
2. 一致性 应用使用标准的 UI 元素和熟悉的模式。导航遵循平台惯例,手势按预期工作,组件出现在预期的位置。这种熟悉感减少了认知负荷。
3. 谦逊性 UI 不应分散对核心内容的注意力。使用微妙的背景,在不需要时隐藏导航,克制地使用品牌元素,让内容成为主角。
来自 Apple HIG: “谦逊性通过确保内容突出,而周围的视觉元素不与之竞争,使应用变得美观。”
来自 WWDC25:“系统化的方法意味着在每个层面都进行有意识的设计,确保从最小的控件到最大的表面,所有元素都被视为整体的一部分来考虑。”
axiom-hig 进行快速决策和清单检查axiom-liquid-glass 实现 iOS 26 材质axiom-liquid-glass-ref 实现 iOS 26 应用级采用axiom-accessibility-diag 进行无障碍功能故障排除广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
不要使用硬编码的颜色值,而是使用描述颜色用途而非外观的语义色彩。语义色彩会自动适应明暗模式和无障碍设置。
来自 WWDC19 的关键见解: “将深色模式视为灯光调暗,而不是将所有东西里外翻转。” 颜色并非简单地反转——表格行背景在两种模式下都更亮。
用于文本和符号的四个语义标签层级,每个层级的重要性依次递减:
| 样式 | 语义颜色 | 用途 |
|---|---|---|
.primary | label | 标题,最突出的文本 |
.secondary | secondaryLabel | 副标题,较不突出 |
.tertiary | tertiaryLabel | 占位符文本 |
.quaternary | quaternaryLabel | 禁用文本 |
Text("Title").foregroundStyle(.primary) // 浅色模式下为黑色,深色模式下为白色
Text("Subtitle").foregroundStyle(.secondary)
背景颜色分为两组 — 非分组(标准列表)和分组(iOS 设置样式):
| 层级 | 非分组 | 分组 |
|---|---|---|
| 主背景 | .systemBackground | .systemGroupedBackground |
| 二级背景 | .secondarySystemBackground | .secondarySystemGroupedBackground |
| 三级背景 | .tertiarySystemBackground | .tertiarySystemGroupedBackground |
非分组:在浅色/深色模式下为纯白/纯黑。分组:在浅色/深色模式下为浅灰/深色。
// 标准列表 → 非分组背景
List { Text("Item") }
.background(Color(.systemBackground))
// 设置样式列表 → 分组背景
List { Section("Section") { Text("Item") } }
.listStyle(.grouped)
实际上,用于界面分层的背景颜色有两组:
为什么这很重要:
在浅色模式下,简单的投影可以创建视觉分隔。在深色模式下,投影效果较差,因此系统使用更浅的颜色来提升内容。
示例: iPad 多任务处理:
关键点: 某些较深的颜色在提升状态下可能对比度不佳。始终在提升状态下测试设计。半透明填充色和分隔线颜色能很好地适应。
色调颜色是动态的 - 它们有适用于浅色和深色模式的变体:
// 色调颜色自动适应
Button("Primary Action") {
// action
}
.tint(.blue)
// 在深色模式下变浅,在浅色模式下变深
自定义色调颜色: 创建自定义色调颜色时,请选择在两种模式下都表现良好的颜色。使用对比度计算器,目标是4.5:1 或更高的对比度。在浅色模式下有效的颜色可能在深色模式下对比度不足。
填充颜色是半透明的,以便在变化的背景上形成良好对比:
// 系统填充颜色
Color(.systemFill)
Color(.secondarySystemFill)
Color(.tertiarySystemFill)
Color(.quaternarySystemFill)
何时使用: 需要出现在动态背景之上的控件、按钮和交互元素。
// 标准分隔线(半透明)
Color(.separator)
// 不透明分隔线
Color(.opaqueSeparator)
不透明分隔线在透明度会产生不良效果时使用(例如,交叉的网格线,重叠的半透明颜色会产生视错觉)。
Apple 的明确指导:
“在极少数情况下,考虑在界面中仅使用深色外观。例如,对于支持沉浸式媒体观看的应用,使用永久深色外观是有意义的,它可以让 UI 退居幕后,帮助人们专注于媒体。”
来自 Apple 应用的示例:
| 应用 | 背景 | 理由 |
|---|---|---|
| 音乐 | 深色 | 专辑封面应是视觉焦点 |
| 照片 | 深色 | 图像是核心内容 |
| 时钟 | 深色 | 夜间使用,仪器感 |
| 股市 | 深色 | 数据可视化,图表 |
| 相机 | 深色 | 减少拍摄时的干扰 |
对于所有其他应用: 通过系统背景支持浅色和深色模式。
当需要自定义颜色时:
// 使用资源目录中的自定义颜色
Color("BrandAccent")
// 自动使用正确的变体
San Francisco (SF): 系统无衬线字体家族。
New York (NY): 用于编辑内容的系统衬线字体家族。
两者都作为可变字体提供,具有无缝的字重过渡。
来自 Apple HIG: “避免使用细字体字重。优先使用常规、中等、半粗体或粗体字重,而不是超细、细或轻字重。”
原因: 细字重存在可读性问题,尤其是在小尺寸、明亮光照下或对于有视觉障碍的用户。
层级结构:
// 标题 - 粗体字重以突出显示
Text("Header")
.font(.title.weight(.bold))
// 副标题 - 半粗体
Text("Subheader")
.font(.title2.weight(.semibold))
// 正文 - 常规或中等
Text("Body text")
.font(.body)
// 说明文字 - 常规(切勿使用细体)
Text("Caption")
.font(.caption)
使用内置文本样式实现自动层级结构和动态类型支持:
.font(.largeTitle) .font(.title) .font(.title2)
.font(.title3) .font(.headline) .font(.body)
.font(.callout) .font(.subheadline) .font(.footnote)
.font(.caption) .font(.caption2)
所有文本样式都会随动态类型自动缩放。
要求: 应用必须支持至少 200%(iOS、iPadOS)或 140%(watchOS)的文本缩放。
实现方式:
// ✅ 正确 - 自动缩放
Text("Hello")
.font(.body)
// ❌ 错误 - 固定大小,不缩放
Text("Hello")
.font(.system(size: 17))
布局注意事项:
并非所有内容都同等缩放: 优先考虑用户真正关心的内容。像标签标题这样的次要元素不应像主要内容那样增长太多。
使用自定义字体时:
如果您的自定义字体较细: 与拉丁大写文本配对时,将尺寸增加约 2 点。
宽松行距: 宽列(更容易追踪到下一行) 紧凑行距: 高度受限(避免用于 3 行以上)
// 为特定布局调整行距
Text("Long content...")
.lineSpacing(8) // 在行间添加间距
来自 WWDC25:“我们的形状如何组合在一起有一种安静的几何学,由同心性驱动。通过围绕一个共享中心对齐半径和边距,形状可以舒适地相互嵌套。”
无论大小如何,角半径恒定:
RoundedRectangle(cornerRadius: 12)
何时使用: 当您需要特定、不变的角半径时。
半径是容器高度的一半:
Capsule()
何时使用: 当您希望形状适应内容,同时保持圆角末端时。非常适合按钮、药丸状控件和控件。
贯穿 iOS 26: 滑块、开关、分组表格视图、标签栏、导航栏。
通过从父级半径减去内边距来计算半径:
.containerRelativeShape(.roundedRectangle)
何时使用: 在容器内嵌套形状以保持视觉和谐。
硬件 ↔ 软件和谐: Apple 的硬件具有一致的边框曲率。同样的精确性现在指导着 UI,曲率、尺寸和比例相互对齐,在您手持之物与所见之物之间创造统一的节奏。
同心性示例:
Window (rounded corners)
├─ Sheet (concentric to window)
│ ├─ Card (concentric to sheet)
│ │ └─ Button (concentric to card)
iOS:
macOS:
为了保持视觉平衡,视图应:
示例: 非对称图标可能需要调整内边距以实现视觉居中,而非几何居中。
材质允许背景内容透出,创造视觉深度和层级结构。
选择厚度:
内容需要更多对比度 → 较厚的材质
较简单的内容 → 薄/超薄材质
// 应用材质 .background(.ultraThinMaterial) .background(.thinMaterial) .background(.regularMaterial) .background(.thickMaterial)
关键原则: 在材质上使用充满活力的颜色以提高可读性。纯色可能会因背景环境而变得浑浊。活力效果能保持对比度,无论背景如何。
// 材质上的活力文本
VStack {
Text("Primary")
.foregroundStyle(.primary) // 充满活力
Text("Secondary")
.foregroundStyle(.secondary) // 充满活力
}
.background(.regularMaterial)
目的: 为控件和导航创建一个独特的功能层,悬浮在内容之上。
两种变体:
常规液态玻璃
透明液态玻璃
模态视图与表单(iOS 26+): 使用 Xcode 26 时,表单、警告框和弹出框会自动采用液态玻璃 — 移除自定义的 .presentationBackground() 或 UIBlurEffect 背景。系统会处理材质、同心角半径和变形过渡。对模态内容背景使用提升的语义颜色,而不是在表单主体上使用液态玻璃。
交叉参考: 有关完整的液态玻璃实现模式(表单、警告框、弹出框、变形过渡),请参阅 axiom-liquid-glass-ref。有关决策树,请参阅 axiom-liquid-glass。
放置项目以传达其相对重要性:
来自 Apple HIG: “通过给予足够空间,使基本信息易于查找,并避免非必要细节将其掩盖。”
使用以下方式对相关项目进行分组:
通过液态玻璃材质和滚动边缘效果,确保内容和控件保持清晰区分。
“将内容延伸以填充屏幕或窗口”,使背景和艺术作品延伸到显示边缘。
背景延伸视图: 当内容不能自然跨越整个窗口时使用。
// 内容延伸至边缘
VStack {
FullWidthImage()
.ignoresSafeArea() // 延伸至屏幕边缘
}
安全区域: 未被以下元素遮挡的矩形区域:
布局参考线: 定义矩形区域,用于定位和间距内容,具有:
关键原则: “尊重每个平台的关键显示和系统特性。”
// 尊重安全区域
VStack {
Text("Content")
}
.safeAreaInset(edge: .bottom) {
BottomBar()
}
“将组件彼此对齐,使它们更易于浏览。”
网格对齐:
设计布局应:
要求:
WCAG AA 级标准:
实现方式:
// ✅ 使用语义颜色(自动对比度)
Text("Label").foregroundStyle(.primary)
// ❌ 自定义颜色可能对比度不足
Text("Label").foregroundStyle(.gray) // 使用计算器检查
高对比度模式: 当启用“增强对比度”无障碍设置时,提供更高对比度的配色方案。
在浅色和深色模式下都进行测试。
关键点: “使用颜色以外的更多方式传达信息”,以支持色盲用户。
解决方案:
示例:
// ❌ 仅颜色指示状态
Circle().fill(isActive ? .green : .red)
// ✅ 形状 + 颜色
HStack {
Image(systemName: isActive ? "checkmark.circle.fill" : "xmark.circle.fill")
Text(isActive ? "Active" : "Inactive")
}
.foregroundStyle(isActive ? .green : .red)
为 VoiceOver 无障碍功能描述界面和内容:
Button {
share()
} label: {
Image(systemName: "square.and.arrow.up")
}
.accessibilityLabel("Share")
对于视频/音频内容,提供:
将音频信号与以下内容配对:
触控目标:
手势:
辅助技术:
尊重“减弱动态效果”:
尽量减少动画
避免过度闪烁的灯光
支持“减弱闪烁灯光”
减少弹跳效果
尽量减少 Z 轴深度变化
// 检查减弱动态效果设置 @Environment(.accessibilityReduceMotion) var reduceMotion
var body: some View { content .animation(reduceMotion ? nil : .spring(), value: isExpanded) }
提供可调节的难度级别。
优先考虑舒适度:
有目的的动画: “有目的地添加动效,支持体验而不喧宾夺主。”
避免不必要的动画,以免分散注意力或引起不适。动效应增强而非主导界面。
使动效成为可选项。 用触觉反馈和音频补充视觉反馈,以传达重要信息,确保所有用户无论动效偏好如何都能理解您的界面。
设计与用户期望和手势一致的动画。反馈应:
避免为频繁的 UI 交互添加动画。 标准系统元素已经包含微妙的动画,因此自定义元素不应为常见操作添加不必要的动效。
“允许用户取消动效”,不要强迫他们在继续操作前等待动画完成,尤其是对于重复交互。
// ✅ 允许立即点击,不因动画而阻塞
Button("Next") {
withAnimation(.easeOut(duration: 0.2)) {
showNext = true
}
}
// 用户可以立即再次点击,无需等待
SwiftUI 提供动画功能;WatchKit 提供 WKInterfaceImage 用于布局动画和序列。
6900+ 个矢量符号,与 San Francisco 字体匹配,随动态类型缩放,并自动适应粗体文本和深色模式。九种字重,三种比例,四种渲染模式,以及 12+ 种动画效果。
有关渲染模式(单色、层级、调色板、多色)、符号效果(弹跳、脉动、摆动、绘制开/关)和自定义符号创作的全面覆盖,请参阅
axiom-sf-symbols(决策树)和axiom-sf-symbols-ref(完整 API)。
设计原则: 可识别、简化的设计,具有熟悉的视觉隐喻。保持统一的尺寸、细节水平、描边粗细和透视。使图标字重与相邻文本匹配。当视觉权重不对称时,调整内边距以实现视觉居中。
格式: 使用 PDF 或 SVG 以实现自动缩放。系统组件会自动处理选中状态。
来自 WWDC25:“铅笔可能暗示注释,而勾选标记可能看起来像确认——使得像选择或编辑这样的操作容易被误读。当没有明确的简写时,文本标签总是更好的选择。 ”
使用图标的情况:
使用文本的情况:
始终提供替代文本标签,以便 VoiceOver 描述:
Image(systemName: "star.fill")
.accessibilityLabel("Favorite")
一致性与熟悉度: “人们期望大多数手势无论当前上下文如何都能以相同方式工作。” 点击、滑动和拖动等标准手势应在各平台上执行其预期功能。
响应式反馈: “尽可能响应地处理手势”,并在手势执行过程中提供即时反馈,以便用户能够预测结果。
所有平台支持的基本手势(尽管精确动作因设备而异):
最小触控目标尺寸:
| 平台 | 最小尺寸 | 间距 |
|---|---|---|
| iOS/iPadOS | 44x44 点 | 12-24 点内边距 |
| macOS | 因控件而异 | 系统间距 |
| watchOS | 系统控件 | 针对小屏幕优化 |
| tvOS | 大(焦点模型) | 60 点+ 间距 |
// ✅ 足够的触控目标
Button("Tap") { }
.frame(minWidth: 44, minHeight: 44)
// ❌ 太小
Button("Tap") { }
.frame(width: 20, height: 20) // 无法满足无障碍要求
自定义手势仅在必要时才应实现,并且必须:
警告: 不要用自定义手势替换标准手势。快捷方式应补充而非替换熟悉的交互。
关键点: “为用户提供多种与应用交互的方式。” 切勿假设用户能够执行特定手势。
提供替代方案:
语音控制
键盘导航
手势的按钮替代方案
// ✅ 滑动操作 + 按钮替代方案 .swipeActions { Button("Delete", role: .destructive) { delete() } } .contextMenu { Button("Delete", role: .destructive) { delete() } }
强制要求: iOS、iPadOS、tvOS 不需要: macOS、axiom-visionOS、watchOS
设计原则: “设计一个与应用或游戏第一个屏幕几乎相同的启动屏幕”,以避免突兀的视觉过渡。
最小化品牌元素:
无文本:
匹配外观:
尊重设备方向
适应浅色/深色模式
// 启动屏幕匹配第一个屏幕 // 平滑过渡,无闪烁
入门引导是独立的体验,跟随启动阶段。提供“应用或游戏的高级概览”,如果需要可以包含启动画面。
何时使用: 仅当您有重要的上下文需要传达给新用户时。
入门引导可以包含的内容:
时间线:
标签栏指南:
TabView 和 Tab 进行适配导航栏指南:
prefersLargeTitles)仅用于顶级视图;内联标题用于推送视图... 菜单处理额外操作系统集成: 小组件、主屏幕快速操作、聚焦搜索、快捷指令、活动视图
扩展了 iOS,具有更大的显示屏、侧边栏导航、分屏视图、指针/触控板、任意窗口(iOS 26+)。不要仅仅缩放 iOS 布局 — 充分利用侧边栏和分屏视图。
指针优先,键盘为中心。布局密集,控件比 iOS 小。多窗口、菜单栏、上下文菜单、键盘快捷键必不可少。控件:迷你/小/中等 → 圆角矩形,大/超大 → 胶囊形状。
显示屏非常小 — 一目了然,交互最少。全出血内容,最小内边距,数码表冠交互,表盘复杂功能。始终显示考虑。
从 iPad/iOS 适配: 用基于页面的流程替换侧边栏。将滑动/捏合转换为数码表冠旋转。使用不透明度/间距创建层级结构(无材质/液态玻璃)。复杂功能替换仪表板。@State/@Environment 重用良好;视图层次结构必须重写。
10 英尺观看距离,基于焦点的导航,手势遥控器。大触控目标,突出的焦点状态,有限的文本输入,定向导航。
焦点引擎:tvOS 使用 UIKit 焦点引擎进行硬件导航,与 SwiftUI 的 @FocusState 共存。焦点引擎是最终权威 — 如果焦点引擎认为视图不可聚焦,则忽略 @FocusState 赋值。使用 UIFocusGuide 来桥接孤立视图之间的导航间隙。
TVUIKit:tvOS 独占组件 — TVPosterView(视差焦点效果)、TVDigitEntryViewController(PIN 码输入)。不存在 SwiftUI 等效项;通过 UIViewRepresentable 桥接。
文本输入:标准文本字段会触发全屏系统键盘。为了获得更好的用户体验,使用影子输入模式(按钮 UI + 隐藏的 CocoaTextField)。有关实现细节,请参阅 axiom-tvos。
存储:无持久本地存储。所有本地文件都是缓存,系统会删除。有关数据策略,请参阅 axiom-tvos。
空间计算,具有玻璃材质、3D 布局、深度。舒适的观看深度,避免头部锚定的内容,将内容置于视野中心。
欢迎性语言要求:
避免带有压迫性起源的短语(例如,“peanut gallery”)。
谨慎使用幽默 — 它是主观的,并且难以跨文化翻译。
描绘人类多样性:
避免假设:
最佳实践:
认识到:
包括:
为以下方面准备软件:
文化色彩意识:
使用平实的语言并避免刻板印象,以促进更顺畅的本地化。
声音与语气: 通过书面沟通保持一致的品牌个性。
视觉元素:
最重要的指导 — 克制:
让位于内容: “使用屏幕空间来显示一个除了展示品牌资产外什么都不做的元素,可能意味着用户关心的内容空间更少。”
徽标极简主义: “抵制在整个应用或游戏中显示徽标的诱惑,除非这对于提供上下文至关重要。”
熟悉的模式: 即使采用风格化设计,也要保持标准的 UI 行为和组件放置,以保持界面的平易近人。
启动屏幕注意事项: 避免使用启动屏幕进行品牌塑造,因为它们消失得太快;考虑使用入门引导屏幕进行品牌整合。
应该:
不应该:
Apple 商标不能出现在您的应用名称或图像中 — 请查阅 Apple 的官方商标指南。
症状: App Store 因违反无障碍功能而拒绝,或颜色不符合 WCAG 标准。
诊断: 使用无障碍功能检查器、对比度计算器、浅色/深色模式以及启用增强对比度进行测试。有关对比度要求,请参阅上文无障碍功能 > 视觉部分。
解决方案:
// ❌ 自定义灰色可能对比度不足
Text("Label").foregroundStyle(.gray)
// ✅ 语义颜色(自动合规)
Text("Label").foregroundStyle(.secondary)
// ✅ 经过验证的自定义颜色(在白色上约 8:1,WCAG AAA)
Text("Label").foregroundStyle(Color(red: 0.25, green: 0.25, blue: 0.25))
症状: 用户报告难以点击,App Store 无障碍功能拒绝。
诊断:
// 检查按钮大小
Button("Tap") { }
.frame(width: 30, height: 30) // ❌ 太小
解决方案:
// ✅ 将触控目标扩展到最小 44x44
Button("Tap") { }
.frame(minWidth: 44, minHeight: 44)
// ✅ 替代方案:添加内边距
Button("Tap") { }
.padding() // 系统添加适当的内边距
症状: 颜色在深色模式下看起来错误,对比度不足。
诊断:
解决方案:
// ❌ 问题:硬编码的白色文本
Text("Label").foregroundStyle(.white)
// 在
The Human Interface Guidelines (HIG) define Apple's design philosophy and provide concrete guidance for creating intuitive, accessible, platform-appropriate experiences across all Apple devices.
Every design decision should support these principles:
1. Clarity Content is paramount. Interface elements should defer to content, not compete with it. Every element has a purpose, unnecessary complexity is eliminated, and users should immediately know what they can do without extensive instructions.
2. Consistency Apps use standard UI elements and familiar patterns. Navigation follows platform conventions, gestures work as expected, and components appear in expected locations. This familiarity reduces cognitive load.
3. Deference The UI should not distract from essential content. Use subtle backgrounds, receding navigation when not needed, restrained branding, and let content be the hero.
From Apple HIG: "Deference makes an app beautiful by ensuring the content stands out while the surrounding visual elements do not compete with it."
From WWDC25: "A systematic approach means designing with intention at every level, ensuring that all elements, from the tiniest control to the largest surface, are considered in relation to the whole."
axiom-hig for quick decisions and checklistsaxiom-liquid-glass for iOS 26 material implementationaxiom-liquid-glass-ref for iOS 26 app-wide adoptionaxiom-accessibility-diag for accessibility troubleshootingInstead of hardcoded color values, use semantic colors that describe the purpose of a color rather than its appearance. Semantic colors automatically adapt to light/dark mode and accessibility settings.
Key insight from WWDC19: "Think of Dark Mode as having the lights dimmed rather than everything being flipped inside out." Colors are NOT simply inverted—table row backgrounds are lighter in both modes.
Four semantic label levels for text and symbols, each progressively less prominent:
| Style | Semantic Color | Usage |
|---|---|---|
.primary | label | Titles, most prominent text |
.secondary | secondaryLabel | Subtitles, less prominent |
.tertiary | tertiaryLabel | Placeholder text |
.quaternary |
Text("Title").foregroundStyle(.primary) // Black in Light, white in Dark
Text("Subtitle").foregroundStyle(.secondary)
Background colors come in two sets — ungrouped (standard lists) and grouped (iOS Settings style):
| Level | Ungrouped | Grouped |
|---|---|---|
| Primary | .systemBackground | .systemGroupedBackground |
| Secondary | .secondarySystemBackground | .secondarySystemGroupedBackground |
| Tertiary | .tertiarySystemBackground | .tertiarySystemGroupedBackground |
Ungrouped: pure white/black in Light/Dark. Grouped: light gray/dark in Light/Dark.
// Standard list → ungrouped backgrounds
List { Text("Item") }
.background(Color(.systemBackground))
// Settings-style list → grouped backgrounds
List { Section("Section") { Text("Item") } }
.listStyle(.grouped)
There are actually two sets of background colors for layering interfaces:
Why this matters:
In Light Mode, simple drop shadows create visual separation. In Dark Mode, drop shadows are less effective, so the system uses lighter colors for elevated content.
Example: iPad multitasking:
Critical: Some darker colors may not contrast well when elevated. Always test designs in elevated state. Semi-opaque fill and separator colors adapt gracefully.
Tint colors are dynamic - they have variants for Light and Dark modes:
// Tint color automatically adapts
Button("Primary Action") {
// action
}
.tint(.blue)
// Gets lighter in Dark Mode, darker in Light Mode
Custom tint colors: When creating custom tint colors, select colors that work well in both modes. Use a contrast calculator to aim for 4.5:1 or higher contrast ratio. Colors that work in Light Mode may have insufficient contrast in Dark Mode.
Fill colors are semi-transparent to contrast well against variable backgrounds:
// System fill colors
Color(.systemFill)
Color(.secondarySystemFill)
Color(.tertiarySystemFill)
Color(.quaternarySystemFill)
When to use: Controls, buttons, and interactive elements that need to appear above dynamic backgrounds.
// Standard separator (semi-transparent)
Color(.separator)
// Opaque separator
Color(.opaqueSeparator)
Opaque separators are used when transparency would create undesirable results (e.g., intersecting grid lines where overlapping semi-transparent colors create optical illusions).
Apple's explicit guidance:
"In rare cases, consider using only a dark appearance in the interface. For example, it can make sense for an app that enables immersive media viewing to use a permanently dark appearance that lets the UI recede and helps people focus on the media."
Examples from Apple's apps:
| App | Background | Rationale |
|---|---|---|
| Music | Dark | Album art should be visual focus |
| Photos | Dark | Images are hero content |
| Clock | Dark | Nighttime use, instrument feel |
| Stocks | Dark | Data visualization, charts |
| Camera | Dark | Reduces distraction during capture |
For all other apps: Support both Light and Dark modes via system backgrounds.
When you need custom colors:
// Use custom color from asset catalog
Color("BrandAccent")
// Automatically uses correct variant
San Francisco (SF): The system sans-serif font family.
New York (NY): System serif font family for editorial content.
Both available as variable fonts with seamless weight transitions.
From Apple HIG: "Avoid light font weights. Prefer Regular, Medium, Semibold, or Bold weights instead of Ultralight, Thin, or Light."
Why: Light weights have legibility issues, especially at small sizes, in bright lighting, or for users with visual impairments.
Hierarchy:
// Headers - Bold weight for prominence
Text("Header")
.font(.title.weight(.bold))
// Subheaders - Semibold
Text("Subheader")
.font(.title2.weight(.semibold))
// Body - Regular or Medium
Text("Body text")
.font(.body)
// Captions - Regular (never Light)
Text("Caption")
.font(.caption)
Use built-in text styles for automatic hierarchy and Dynamic Type support:
.font(.largeTitle) .font(.title) .font(.title2)
.font(.title3) .font(.headline) .font(.body)
.font(.callout) .font(.subheadline) .font(.footnote)
.font(.caption) .font(.caption2)
All text styles scale automatically with Dynamic Type.
Requirement: Apps must support text scaling of at least 200% (iOS, iPadOS) or 140% (watchOS).
Implementation:
// ✅ CORRECT - Scales automatically
Text("Hello")
.font(.body)
// ❌ WRONG - Fixed size, doesn't scale
Text("Hello")
.font(.system(size: 17))
Layout considerations:
Not all content scales equally: Prioritize what users actually care about. Secondary elements like tab titles shouldn't grow as much as primary content.
When using custom fonts:
If your custom font is thin: Increase size by ~2 points when pairing with uppercase Latin text.
Loose leading: Wide columns (easier to track to next line) Tight leading: Constrained height (avoid for 3+ lines)
// Adjust leading for specific layouts
Text("Long content...")
.lineSpacing(8) // Add space between lines
From WWDC25: "There's a quiet geometry to how our shapes fit together, driven by concentricity. By aligning radii and margins around a shared center, shapes can comfortably nest within each other."
Constant corner radius regardless of size:
RoundedRectangle(cornerRadius: 12)
Use when: You need a specific, unchanging corner radius.
Radius is half the container's height:
Capsule()
Use when: You want shapes that adapt to content while maintaining rounded ends. Perfect for buttons, pills, and controls.
Found throughout iOS 26: Sliders, switches, grouped table views, tab bars, navigation bars.
Calculate radius by subtracting padding from parent's radius:
.containerRelativeShape(.roundedRectangle)
Use when: Nesting shapes within containers to maintain visual harmony.
Hardware ↔ Software harmony: Apple's hardware features consistent bezel curvature. The same precision now guides UI, with curvature, size, and proportion aligning to create unified rhythm between what you hold and what you see.
Example of concentricity:
Window (rounded corners)
├─ Sheet (concentric to window)
│ ├─ Card (concentric to sheet)
│ │ └─ Button (concentric to card)
iOS:
macOS:
To preserve optical balance, views are:
Example: Asymmetric icons may need padding adjustments for optical centering rather than geometric centering.
Materials allow background content to show through, creating visual depth and hierarchy.
Choosing thickness:
Content needs more contrast → thicker material
Simpler content → thin/ultra-thin material
// Apply material .background(.ultraThinMaterial) .background(.thinMaterial) .background(.regularMaterial) .background(.thickMaterial)
Key principle: Use vibrant colors on top of materials for legibility. Solid colors can get muddy depending on background context. Vibrancy maintains contrast regardless of background.
// Vibrant text on material
VStack {
Text("Primary")
.foregroundStyle(.primary) // Vibrant
Text("Secondary")
.foregroundStyle(.secondary) // Vibrant
}
.background(.regularMaterial)
Purpose: Creates a distinct functional layer for controls and navigation, floating above content.
Two variants:
Regular Liquid Glass
Clear Liquid Glass
Modals & Sheets (iOS 26+): Sheets, alerts, and popovers automatically adopt Liquid Glass with Xcode 26 — remove custom .presentationBackground() or UIBlurEffect backgrounds. System handles material, concentric corner radius, and morphing transitions. Use elevated semantic colors for modal content backgrounds, not Liquid Glass on the sheet body.
Cross-reference: For full Liquid Glass implementation patterns (sheets, alerts, popovers, morphing transitions), see axiom-liquid-glass-ref. For decision trees, see axiom-liquid-glass.
Place items to convey their relative importance:
From Apple HIG: "Make essential information easy to find by giving it sufficient space and avoid obscuring it with nonessential details."
Group related items using:
Ensure content and controls remain clearly distinct through Liquid Glass material and scroll edge effects.
"Extend content to fill the screen or window" with backgrounds and artwork reaching display edges.
Background extension views: Use when content doesn't naturally span the full window.
// Content extends to edges
VStack {
FullWidthImage()
.ignoresSafeArea() // Extends to screen edges
}
Safe Areas: Rectangular regions unobstructed by:
Layout Guides: Define rectangular regions for positioning and spacing content with:
Key principle: "Respect key display and system features in each platform."
// Respect safe areas
VStack {
Text("Content")
}
.safeAreaInset(edge: .bottom) {
BottomBar()
}
"Align components with one another to make them easier to scan."
Grid alignment:
Design layouts that:
Requirements:
WCAG Level AA standards:
Implementation:
// ✅ Use semantic colors (automatic contrast)
Text("Label").foregroundStyle(.primary)
// ❌ Custom colors may fail contrast
Text("Label").foregroundStyle(.gray) // Check with calculator
High contrast mode: Provide higher contrast color schemes when "Increase Contrast" accessibility setting is enabled.
Test in both Light and Dark modes.
Critical: "Convey information with more than color alone" to support colorblind users.
Solutions:
Example:
// ❌ Only color indicates status
Circle().fill(isActive ? .green : .red)
// ✅ Shape + color
HStack {
Image(systemName: isActive ? "checkmark.circle.fill" : "xmark.circle.fill")
Text(isActive ? "Active" : "Inactive")
}
.foregroundStyle(isActive ? .green : .red)
Describe interface and content for VoiceOver accessibility:
Button {
share()
} label: {
Image(systemName: "square.and.arrow.up")
}
.accessibilityLabel("Share")
For video/audio content, provide:
Pair audio signals with:
Touch targets:
Gestures:
Assistive technologies:
Respect "Reduce Motion":
Minimize animations
Avoid excessive flashing lights
Support "Dim Flashing Lights"
Reduce bounce effects
Minimize z-axis depth changes
// Check Reduce Motion setting @Environment(.accessibilityReduceMotion) var reduceMotion
var body: some View { content .animation(reduceMotion ? nil : .spring(), value: isExpanded) }
Offer adjustable difficulty levels.
Prioritize comfort:
Purposeful Animation: "Add motion purposefully, supporting the experience without overshadowing it."
Avoid gratuitous animations that distract or cause discomfort. Motion should enhance rather than dominate the interface.
Make motion optional. Supplement visual feedback with haptics and audio to communicate important information, ensuring all users can understand your interface regardless of motion preferences.
Design animations aligned with user expectations and gestures. Feedback should be:
Avoid animating frequent UI interactions. Standard system elements already include subtle animations, so custom elements shouldn't add unnecessary motion to common actions.
"Let people cancel motion" by not forcing them to wait for animations to complete before proceeding, especially for repeated interactions.
// ✅ Allow immediate tap, don't block on animation
Button("Next") {
withAnimation(.easeOut(duration: 0.2)) {
showNext = true
}
}
// User can tap again immediately, not forced to wait
SwiftUI provides animation capabilities; WatchKit offers WKInterfaceImage for layout animations and sequences.
6,900+ vector symbols that match San Francisco font, scale with Dynamic Type, and adapt to Bold Text and Dark Mode automatically. Nine weights, three scales, four rendering modes, and 12+ animation effects.
For comprehensive coverage of rendering modes (Monochrome, Hierarchical, Palette, Multicolor), symbol effects (Bounce, Pulse, Wiggle, Draw On/Off), and custom symbol authoring, see
axiom-sf-symbols(decision trees) andaxiom-sf-symbols-ref(complete API).
Design principles: Recognizable, simplified designs with familiar visual metaphors. Maintain uniform size, detail level, stroke thickness, and perspective. Match icon weight with adjacent text. Adjust padding for optical centering when visual weight is asymmetric.
Format: Use PDF or SVG for automatic scaling. System components handle selected states automatically.
From WWDC25: "A pencil might suggest annotate, and a checkmark can look like confirm—making actions like Select or Edit easy to misread. When there's no clear shorthand, a text label is always the better choice. "
Use icons when:
Use text when:
Always provide alternative text labels enabling VoiceOver descriptions:
Image(systemName: "star.fill")
.accessibilityLabel("Favorite")
Consistency and Familiarity: "People expect most gestures to work the same regardless of their current context." Standard gestures like tap, swipe, and drag should perform their expected functions across platforms.
Responsive Feedback: "Handle gestures as responsively as possible" and provide immediate feedback during gesture performance so users can predict outcomes.
Basic gestures supported across all platforms (though precise movements vary by device):
Minimum touch target sizes:
| Platform | Minimum Size | Spacing |
|---|---|---|
| iOS/iPadOS | 44x44 points | 12-24pt padding |
| macOS | Varies by control | System spacing |
| watchOS | System controls | Optimized for small screen |
| tvOS | Large (focus model) | 60pt+ spacing |
// ✅ Adequate touch target
Button("Tap") { }
.frame(minWidth: 44, minHeight: 44)
// ❌ Too small
Button("Tap") { }
.frame(width: 20, height: 20) // Fails accessibility
Custom gestures should only be implemented when necessary and must be:
Warning: Don't replace standard gestures with custom ones. Shortcuts should supplement, not replace, familiar interactions.
Critical: "Give people more than one way to interact with your app." Never assume users can perform specific gestures.
Provide alternatives:
Voice control
Keyboard navigation
Button alternatives to gestures
// ✅ Swipe action + button alternative .swipeActions { Button("Delete", role: .destructive) { delete() } } .contextMenu { Button("Delete", role: .destructive) { delete() } }
Mandatory for: iOS, iPadOS, tvOS Not required for: macOS, axiom-visionOS, watchOS
Design principle: "Design a launch screen that's nearly identical to the first screen of your app or game" to avoid jarring visual transitions.
Minimize branding:
No text:
Match appearance:
Respect device orientation
Adapt to light/dark mode
// Launch screen matches first screen // Transitions smoothly without flash
Onboarding is a separate experience that follows the launch phase. Provides "a high-level view of your app or game" and can include a splash screen if needed.
When to use: Only when you have meaningful context to communicate to new users.
What onboarding can include:
Timeline:
Tab Bar Guidelines:
TabView with Tab for adaptationNavigation Bar Guidelines:
prefersLargeTitles) for top-level views only; inline for pushed views... menu for additionalSystem integration: Widgets, Home Screen quick actions, Spotlight, Shortcuts, Activity views
Extends iOS with larger display, sidebar navigation, split view, pointer/trackpad, arbitrary windows (iOS 26+). Don't just scale iOS layouts — leverage sidebars and split views.
Pointer-first, keyboard-centric. Dense layouts, smaller controls than iOS. Multiple windows, menu bar, contextual menus, keyboard shortcuts essential. Controls: Mini/Small/Medium → rounded rectangles, Large/X-Large → capsules.
Very small display — glanceable, minimal interaction. Full-bleed content, minimal padding, Digital Crown interactions, complications for watch faces. Always-on display consideration.
Adapting from iPad/iOS: Replace sidebars with page-based flow. Convert swipe/pinch to Digital Crown rotation. Use opacity/spacing for hierarchy (no materials/Liquid Glass). Complications replace dashboards. @State/@Environment reuse well; view hierarchy must be rewritten.
10-foot viewing distance, focus-based navigation, gestural remote. Large touch targets, prominent focus states, limited text input, directional navigation.
Focus Engine : tvOS uses a UIKit Focus Engine for hardware navigation that coexists with SwiftUI's @FocusState. The Focus Engine is the ultimate authority — @FocusState assignments are ignored if the Focus Engine considers a view unfocusable. Use UIFocusGuide to bridge navigation gaps between isolated views.
TVUIKit : tvOS-exclusive components — TVPosterView (parallax focus effects), TVDigitEntryViewController (PIN entry). No SwiftUI equivalents exist; bridge via UIViewRepresentable.
Text input : Standard text fields trigger a fullscreen system keyboard. For better UX, use the shadow input pattern (Button UI + hidden CocoaTextField). See axiom-tvos for implementation details.
Storage : No persistent local storage. All local files are cache that the system deletes. See axiom-tvos for data strategy.
Spatial computing with glass materials, 3D layouts, depth. Comfortable viewing depth, avoid head-anchored content, center content in field of view.
Welcoming language requirements:
Avoid phrases with oppressive origins (e.g., "peanut gallery").
Exercise caution with humor — it's subjective and difficult to translate across cultures.
Portraying human diversity:
Avoiding assumptions:
Best practices:
Recognize:
Include:
Prepare software for:
Cultural color awareness:
Use plain language and avoid stereotypes to facilitate smoother localization.
Voice & Tone: Maintain consistent brand personality through written communication.
Visual Elements:
Most critical guidance — restraint:
Defer to content: "Using screen space for an element that does nothing but display a brand asset can mean there's less room for the content people care about."
Logo minimalism: "Resist the temptation to display your logo throughout your app or game unless it's essential for providing context."
Familiar patterns: Maintain standard UI behaviors and component placement even with stylized designs to keep interfaces approachable.
Launch screen caution: Avoid using launch screens for branding since they disappear too quickly; consider onboarding screens instead for brand integration.
Do:
Don't:
Apple trademarks cannot appear in your app name or images—consult Apple's official trademark guidelines.
Symptom: App Store rejection for accessibility violations, or colors don't meet WCAG standards.
Diagnosis: Test with Accessibility Inspector, contrast calculators, both Light/Dark modes, and Increase Contrast enabled. See Accessibility > Vision section above for contrast ratio requirements.
Solution:
// ❌ Custom gray may fail contrast
Text("Label").foregroundStyle(.gray)
// ✅ Semantic colors (automatic compliance)
Text("Label").foregroundStyle(.secondary)
// ✅ Verified custom color (~8:1 on white, WCAG AAA)
Text("Label").foregroundStyle(Color(red: 0.25, green: 0.25, blue: 0.25))
Symptom: Users report difficult tapping, App Store accessibility rejection.
Diagnosis:
// Check button size
Button("Tap") { }
.frame(width: 30, height: 30) // ❌ Too small
Solution:
// ✅ Expand touch target to minimum 44x44
Button("Tap") { }
.frame(minWidth: 44, minHeight: 44)
// ✅ Alternative: Add padding
Button("Tap") { }
.padding() // System adds appropriate padding
Symptom: Colors look wrong in Dark Mode, insufficient contrast.
Diagnosis:
Solution:
// ❌ PROBLEM: Hardcoded white text
Text("Label").foregroundStyle(.white)
// Invisible in Light Mode
// ✅ SOLUTION: Semantic color
Text("Label").foregroundStyle(.primary)
// Black in Light, white in Dark
// ✅ ALTERNATIVE: Asset catalog color with variants
Text("Label").foregroundStyle(Color("BrandText"))
// Define in Assets.xcassets with Light/Dark variants
Symptom: Text hard to read, especially at small sizes or in bright lighting.
Diagnosis:
Text("Headline")
.font(.system(size: 17, weight: .ultralight)) // ❌ Too light
Solution:
// ✅ Use Regular minimum
Text("Headline")
.font(.system(size: 17, weight: .regular))
// ✅ Better: Use system text styles
Text("Headline")
.font(.headline) // Automatically uses appropriate weight
Symptom: Text doesn't scale when user changes text size in Settings.
// ❌ Fixed size doesn't scale
Text("Label").font(.system(size: 17))
// ✅ Text styles scale automatically
Text("Label").font(.body)
// ✅ Custom font with scaling
Text("Label").font(.custom("CustomFont", size: 17, relativeTo: .body))
Symptom: Users with motion sensitivity experience discomfort.
Diagnosis:
Solution:
// ✅ Check Reduce Motion setting
@Environment(\.accessibilityReduceMotion) var reduceMotion
var body: some View {
content
.animation(reduceMotion ? nil : .spring(), value: isExpanded)
}
// ✅ Alternative: Simpler animation
.animation(reduceMotion ? .linear(duration: 0.1) : .spring(), value: isExpanded)
Symptom: VoiceOver announces unhelpful information like "Button" instead of action.
Diagnosis:
// ❌ Image button without label
Button {
share()
} label: {
Image(systemName: "square.and.arrow.up")
}
// VoiceOver says: "Button"
Solution:
// ✅ Add accessibility label
Button {
share()
} label: {
Image(systemName: "square.and.arrow.up")
}
.accessibilityLabel("Share")
// VoiceOver says: "Share, Button"
Symptom: Colorblind users can't distinguish status.
Diagnosis:
// ❌ Only color indicates state
Circle()
.fill(isComplete ? .green : .red)
Solution:
// ✅ Use shape + color + text
HStack {
Image(systemName: isComplete ? "checkmark.circle.fill" : "xmark.circle.fill")
Text(isComplete ? "Complete" : "Incomplete")
}
.foregroundStyle(isComplete ? .green : .red)
Symptom: App Store rejects launch screen with logo or text.
Diagnosis:
Solution:
// ❌ Launch screen with logo (rejected)
// Launch.storyboard contains app logo
// ✅ Launch screen matches first screen (approved)
// Launch.storyboard shows same background/layout as first screen
// No text, no logos, minimal branding
// Move branding to onboarding screen instead
Symptom: Users confused by app-specific dark mode setting, double settings.
Diagnosis:
Solution:
// ❌ App-specific appearance toggle
.preferredColorScheme(userPreference == .dark ? .dark : .light)
// ✅ Respect system preference
// Remove custom toggle, use system preference
// Let iOS Settings control appearance
WWDC : 356, 2019-808
Docs : /design/human-interface-guidelines, /design/human-interface-guidelines/color, /design/human-interface-guidelines/dark-mode, /design/human-interface-guidelines/materials, /design/human-interface-guidelines/typography, /design/human-interface-guidelines/layout, /design/human-interface-guidelines/accessibility, /design/human-interface-guidelines/icons
Skills : axiom-hig, axiom-liquid-glass, axiom-liquid-glass-ref, axiom-swiftui-layout-ref, axiom-accessibility-diag, axiom-tvos
Last Updated : Based on Apple HIG (2024-2025), WWDC25-356, WWDC19-808 Skill Type : Reference (Comprehensive guide with code examples)
Weekly Installs
121
Repository
GitHub Stars
606
First Seen
Jan 21, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode104
codex99
gemini-cli95
claude-code93
cursor90
github-copilot88
前端设计技能指南:避免AI垃圾美学,打造独特生产级界面
49,900 周安装
quaternaryLabel |
| Disabled text |