Liquid Glass 设计系统上手:iOS 26 / macOS Tahoe 的玻璃化 UI 应该怎么用
把 Liquid Glass 的设计原则、SwiftUI API、GlassEffectContainer、morphing 动画、工具栏集成、无障碍与已知坑整理成一份可直接上手的实践笔记。
Apple 在 WWDC 2025 推出的 Liquid Glass,不只是把毛玻璃做得更亮一点,而是把系统级材质、层级、动效和交互统一成了一套新的视觉语言。
如果你在做 iOS 26 / macOS Tahoe 的 SwiftUI 应用,这套设计最重要的不是“怎么把界面做得像玻璃”,而是要先理解它为什么存在:内容沉到底层,导航和控制浮到上层。
这篇文章不是逐段翻译文档,而是把 liquid-glass-design 这个技能里的重点压缩成一份更适合开发者快速上手的实践笔记。
Liquid Glass 到底是什么
Liquid Glass 的核心特征可以概括成五个词:
- 透光
- 折射
- 高光响应
- 背景自适应
- 状态形变
它和传统的模糊材质最大的区别在于,Liquid Glass 强调的是一种“有厚度、有动态反馈”的材质感:
- 背景内容会产生轻微的 lensing(透镜感)
- 设备或界面发生运动时,会出现 specular highlights(高光反射)
- 颜色会受到背后内容影响,而不是一块固定的半透明灰色
- 不同 UI 状态之间可以顺滑 morph,而不是生硬切换
所以它不是单一视觉效果,而是一整套系统材质 + 交互语言。
最重要的设计原则
Liquid Glass 最值得记住的一条规则只有一句话:
玻璃应该用在导航和控件上,不应该盖在内容本身上。
也就是说,下面这些场景适合用玻璃:
- 工具栏
- Tab Bar
- 浮动按钮
- 筛选器
- 轻量控制面板
- 状态切换按钮组
下面这些场景不适合直接上玻璃:
- 文章卡片
- 长文本容器
- 列表主体
- 内容区背景
- 大面积信息承载组件
Apple 想建立的是一种稳定的视觉层级:内容是地基,玻璃是漂浮层。如果你把内容卡片、正文容器、表单主体全做成玻璃,视觉层次会塌掉,界面也会变得很吵。
三种 Glass 形态
1. Regular Glass
默认款,也是最常用的一种。
Button("Action") {
performAction()
}
.buttonStyle(.glass)
它会自动适配明暗环境,能吸收背景色,适合绝大多数控制类元素。
2. Clear Glass
更通透、存在感更弱。
Button("Subtle Action") {
performAction()
}
.buttonStyle(.glassClear)
这类样式更容易受背景干扰,所以通常需要你对背景对比度更敏感。
3. Identity
相当于不加玻璃效果,用来做对照或者局部退出。
.glassEffect(.identity)
一个必须遵守的规则
不要在同一套界面里混用 Regular Glass 和 Clear Glass。
这是 Liquid Glass 里非常关键的一条视觉一致性规则。不要出现左边一个 .glass,右边一个 .glassClear 的情况,不然整个层级关系会立刻变得不稳定。
SwiftUI 里最常用的 API
基础用法
View()
.glassEffect()
View()
.glassEffect(in: RoundedRectangle(cornerRadius: 16))
View()
.glassEffect(.regular, in: Capsule())
View()
.glassEffect(in: Circle(), isEnabled: showGlass)
对应签名大致是这样:
func glassEffect(
_ glass: Glass = .regular,
in shape: some Shape = .rect,
isEnabled: Bool = true
) -> some View
给玻璃加 tint
Button("Tinted") { }
.buttonStyle(.glass)
.tint(.blue)
interactive 交互型玻璃
View()
.glassEffect(.regular.interactive(), in: Capsule())
常见按钮样式
Button("Glass") { }
.buttonStyle(.glass)
Button("Prominent") { }
.buttonStyle(.glassProminent)
Button("Borderless") { }
.buttonStyle(.glassBorderless)
如果你只是做一个普通的按钮或操作入口,优先考虑 .buttonStyle(.glass),先别急着上更重的视觉变体。
GlassEffectContainer 才是进阶重点
很多人第一眼只会注意 .glassEffect(),但真正能把 Liquid Glass 用出系统感的,是 GlassEffectContainer。
它的作用不是“包一层玻璃背景”,而是让多个玻璃元素共享同一套融合、模糊和形变逻辑。
GlassEffectContainer {
HStack {
Button("First") { }
.glassEffect(in: Capsule())
Button("Second") { }
.glassEffect(in: Capsule())
Button("Third") { }
.glassEffect(in: Capsule())
}
}
spacing 的意义
GlassEffectContainer(spacing: 8) {
HStack(spacing: 4) {
Button("A") { }
.glassEffect(in: Capsule())
Button("B") { }
.glassEffect(in: Capsule())
}
}
如果子元素之间的距离小于容器设定的 spacing 阈值,这些玻璃形状会更容易视觉融合;如果距离更大,它们就会保持独立。
这意味着 GlassEffectContainer 更像一个“玻璃行为域”,而不是一个普通布局容器。
Morphing 动画怎么做
Liquid Glass 很强的一点,是能把相关状态之间的切换做成更自然的形变。
用 glassEffectID 关联两个状态
@Namespace private var animation
Button("Collapsed") { }
.glassEffect(in: Capsule())
.glassEffectID("button", in: animation)
Button("Expanded") { }
.glassEffect(in: Capsule())
.glassEffectID("button", in: animation)
同一个 glassEffectID 可以告诉系统:这两个控件在视觉上是同一个角色,只是状态变了,所以请用 morphing 过渡,而不是把旧元素消失、新元素出现。
控制出现与消失的方式
View()
.glassEffect(in: Capsule())
.glassEffectTransition(.scale, isEnabled: true)
常见可选值包括:
.opacity.scale.slide.identity
如果你的状态变化本来就有明确主次关系,Liquid Glass 的形变动画会比普通的 opacity + offset 更有系统感。
工具栏、导航和 Tab Bar 会是主战场
在 iOS 26 里,工具栏和导航系统本身就会天然贴近 Liquid Glass 语言,所以你最应该把精力花在这些位置,而不是给页面中间的大卡片乱加玻璃。
工具栏分组
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Save") { }
}
ToolbarSpacer(.fixed)
ToolbarItem(placement: .secondaryAction) {
Button("Share") { }
}
}
ToolbarSpacer(.fixed) 的价值很直接:它能明确划分一组主操作和一组次操作,让玻璃层的结构更清楚。
关闭按钮角色
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Close", role: .close) {
dismiss()
}
}
}
role: .close 会更贴近系统的关闭按钮语义和样式。
搜索 Tab
TabView {
SearchView()
.tabItem {
Label("Search", systemImage: "magnifyingglass")
}
.tab(role: .search)
}
这里的 tab(role: .search) 也体现了 Liquid Glass 的一个核心思路:不是把组件静态摆在那里,而是让它在不同任务态之间自然过渡。
无障碍不是补丁,而是默认约束
Liquid Glass 会自动尊重系统无障碍设置,这一点非常重要。
Reduce Transparency
开启后,玻璃会更偏磨砂、更不透明,以保证阅读对比度。
@Environment(\.accessibilityReduceTransparency) var reduceTransparency
Increase Contrast
开启后,整体会更偏黑白高对比,边界也会更清晰。
@Environment(\.colorSchemeContrast) var contrast
Reduce Motion
如果用户开启减少动态效果,玻璃的 morphing 和过渡应该跟着收敛。
@Environment(\.accessibilityReduceMotion) var reduceMotion
withAnimation(reduceMotion ? .none : .spring) {
state.toggle()
}
这不是锦上添花,而是你在做 Liquid Glass 时必须默认纳入的交互约束。
一个当前已知坑
根据当前资料,iOS 26.1 中把 Menu 放进 GlassEffectContainer 会破坏 morphing 动画。
也就是说,下面这种写法要避免:
GlassEffectContainer {
Menu("Options") {
Button("Edit") { }
Button("Delete") { }
}
.glassEffect(in: Capsule())
}
更稳妥的做法,是把 Menu 拿到容器外面,让容器只负责那些真的需要共享玻璃行为的元素。
我建议你在项目里这样落地
如果你要把 Liquid Glass 用进真实应用,我建议按这个顺序推进:
- 先只在工具栏、浮动操作按钮、Tab Bar 邻近控件里使用玻璃。
- 再把一个最核心的状态切换,改成
GlassEffectContainer + glassEffectID。 - 最后再测试 Reduce Transparency、Increase Contrast、Reduce Motion 三组无障碍场景。
而不是一上来就把整个页面都玻璃化。
一份足够实用的检查清单
在进入开发前,你至少应该确认下面这些点:
- 玻璃是否只用于导航和控制,而不是内容主体
- 同一套界面里有没有混用
.glass和.glassClear - 相关状态切换是否值得用
glassEffectID做形变衔接 - 是否已经验证 Reduce Transparency 和 Reduce Motion
- 是否出现 glass-on-glass 的嵌套层叠
GlassEffectContainer的范围是否只包住真正有关联的一组控件
结语
Liquid Glass 最容易让人误解的地方,是大家会先把它当成“新的视觉特效”。
但如果只把它当成玻璃滤镜,你做出来的 UI 往往会很快变廉价。它真正的价值其实在于:重新定义内容、控制、导航、状态变化之间的层级关系。
如果你在做 iOS 26 / macOS Tahoe 的新项目,最值得优先学习的不是如何把所有 View 都套上 .glassEffect(),而是先想清楚哪些元素应该漂浮、哪些元素必须沉稳。
只有这一步对了,Liquid Glass 才会看起来像系统设计,而不是装饰。