liquid-glass-design
affaan-m/ECC
SwiftUI、UIKit、およびWidgetKitを使用して、ダイナミックなガラスマテリアル、ぼかし、反射、インタラクティブなモーフィングを備えた、iOS 26以降向けのAppleの「Liquid Glass」デザインシステムを実装します。
...すべて拡張しますLiquid Glass デザインシステム (iOS 26)
Appleの「リキッドグラス」を実装するためのパターン。これは、背後のコンテンツをぼかし、周囲のコンテンツの色や光を反射し、タッチやポインタ操作に反応する動的なマテリアルです。SwiftUI、UIKit、WidgetKitとの統合について解説します。
有効にするタイミング
- 新しいデザイン言語を用いて、iOS 26以降向けのアプリを構築または更新する場合
- ガラス風のボタン、カード、ツールバー、またはコンテナを実装する場合
- ガラス要素間のモーフィング遷移を作成する場合
- ウィジェットに「Liquid Glass」効果を適用する場合
- 既存のぼかし/マテリアル効果を新しいLiquid Glass APIへ移行する場合
コアパターン — SwiftUI
基本的なガラス効果
任意のビューに「リキッドグラス」を追加する最も簡単な方法:
Text("Hello, World!")
.font(.title)
.padding()
.glassEffect() // デフォルト:通常のバリエーション、カプセル形状
形状と色合いのカスタマイズ
Text("Hello, World!")
.font(.title)
.padding()
.glassEffect(.regular.tint(.orange).interactive(), in: .rect(cornerRadius: 16.0))
主なカスタマイズオプション:
.regular— 標準のガラス効果.tint(Color)— 目立たせるために色合いを追加.interactive()— タッチやポインタの操作に反応する- 形状:
.capsule(デフォルト)、.rect(cornerRadius:)、.circle
ガラス風ボタンのスタイル
Button("Click Me") { /* アクション */ }
.buttonStyle(.glass)
Button("Important") { /* アクション */ }
.buttonStyle(.glassProminent)
複数の要素に対する GlassEffectContainer
パフォーマンスとモーフィング効果のため、複数のガラスビューは常にコンテナで囲むようにしてください:
GlassEffectContainer(spacing: 40.0) {
HStack(spacing: 40.0) {
Image(systemName: "scribble.variable")
.frame(width: 80.0, height: 80.0)
.font(.system(size: 36))
.glassEffect()
Image(systemName: "eraser.fill")
.frame(width: 80.0, height: 80.0)
.font(.system(size: 36))
.glassEffect()
}
}
spacingパラメータは合成距離を制御します。近い要素ほど、ガラスの形状が互いに溶け合います。
ガラスエフェクトの結合
glassEffectUnion を使用して、複数のビューを 1 つのガラス形状に結合します:
@Namespace private var namespace
GlassEffectContainer(spacing: 20.0) {
HStack(spacing: 20.0) {
ForEach(symbolSet.indices, id: \.self) { item in
Image(systemName: symbolSet[item])
.frame(width: 80.0, height: 80.0)
.glassEffect()
.glassEffectUnion(id: item < 2 ? "group1" : "group2", namespace: namespace)
}
}
}
モーフィング遷移
ガラス要素の表示・非表示時に滑らかなモーフィング効果を作成します:
@State private var isExpanded = false
@Namespace private var namespace
GlassEffectContainer(spacing: 40.0) {
HStack(spacing: 40.0) {
Image(systemName: "scribble.variable")
.frame(width: 80.0, height: 80.0)
.glassEffect()
.glassEffectID("pencil", in: namespace)
if isExpanded {
Image(systemName: "eraser.fill")
.frame(width: 80.0, height: 80.0)
.glassEffect()
.glassEffectID("eraser", in: namespace)
}
}
}
Button("Toggle") {
withAnimation { isExpanded.toggle() }
}
.buttonStyle(.glass)
サイドバーの下への水平スクロールの拡張
サイドバーやインスペクタの下まで水平スクロール可能なコンテンツを拡張するには、ScrollViewのコンテンツがコンテナの左端または右端に届くようにしてください。レイアウトが端まで拡張されている場合、システムが自動的にサイドバー下部のスクロール動作を処理するため、追加の修飾子は必要ありません。
コアパターン — UIKit
基本的な UIGlassEffect
let glassEffect = UIGlassEffect()
glassEffect.tintColor = UIColor.systemBlue.withAlphaComponent(0.3)
glassEffect.isInteractive = true
let visualEffectView = UIVisualEffectView(effect: glassEffect)
visualEffectView.translatesAutoresizingMaskIntoConstraints = false
visualEffectView.layer.cornerRadius = 20
visualEffectView.clipsToBounds = true
view.addSubview(visualEffectView)
NSLayoutConstraint.activate([
visualEffectView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
visualEffectView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
visualEffectView.widthAnchor.constraint(equalToConstant: 200),
visualEffectView.heightAnchor.constraint(equalToConstant: 120)
])
// contentViewにコンテンツを追加
let label = UILabel()
label.text = "Liquid Glass"
label.translatesAutoresizingMaskIntoConstraints = false
visualEffectView.contentView.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: visualEffectView.contentView.centerXAnchor),
label.centerYAnchor.constraint(equalTo: visualEffectView.contentView.centerYAnchor)
])
複数の要素に対する UIGlassContainerEffect
let containerEffect = UIGlassContainerEffect()
containerEffect.spacing = 40.0
let containerView = UIVisualEffectView(effect: containerEffect)
let firstGlass = UIVisualEffectView(effect: UIGlassEffect())
let secondGlass = UIVisualEffectView(effect: UIGlassEffect())
containerView.contentView.addSubview(firstGlass)
containerView.contentView.addSubview(secondGlass)
スクロールエッジエフェクト
scrollView.topEdgeEffect.style = .automatic
scrollView.bottomEdgeEffect.style = .hard
scrollView.leftEdgeEffect.isHidden = true
ツールバーへのガラス効果の統合
let favoriteButton = UIBarButtonItem(image: UIImage(systemName: "heart"), style: .plain, target: self, action: #selector(favoriteAction))
favoriteButton.hidesSharedBackground = true // 共有ガラス背景を無効化
コアパターン — WidgetKit
レンダリングモードの検出
struct MyWidgetView: View {
@Environment(\.widgetRenderingMode) var renderingMode
var body: some View {
if renderingMode == .accented {
// ティントモード:白を基調とした、テーマに合わせたガラス背景
} else {
// フルカラーモード:標準の外観
}
}
}
視覚的階層のためのアクセントグループ
HStack {
VStack(alignment: .leading) {
Text("Title")
.widgetAccentable() // アクセントグループ
Text("Subtitle")
// プライマリグループ(デフォルト)
}
Image(systemName: "star.fill")
.widgetAccentable() // アクセントグループ
}
アクセントモードでの画像のレンダリング
Image("myImage")
.widgetAccentedRenderingMode(.monochrome)
コンテナの背景
VStack { /* コンテンツ */ }
.containerBackground(for: .widget) {
Color.blue.opacity(0.2)
}
主要な設計上の決定事項
| 決定事項 | 理由 |
|---|---|
| GlassEffectContainerによるラップ | パフォーマンスの最適化、ガラス要素間のモーフィングを可能にする |
間隔パラメータ |
マージ距離を制御 — 要素がブレンドされるための距離を微調整 |
@Namespace+glassEffectID |
ビュー階層の変更時にスムーズなモーフィング遷移を有効にします |
interactive()修飾子 |
タッチ/ポインタ反応の明示的な有効化 — すべてのガラスが反応するわけではない |
| UIKit の UIGlassContainerEffect | 一貫性を保つため、SwiftUIと同じコンテナパターンを採用 |
| ウィジェットにおけるアクセント付きレンダリングモード | ユーザーが色付きホーム画面を選択すると、システムが色付きガラスを適用する |
ベストプラクティス
- 複数の兄弟ビューにガラス効果を適用する場合は、常に GlassEffectContainer を使用してください。これによりモーフィングが可能になり、レンダリングパフォーマンスが向上します
-
.glassEffect()は、他の外観修飾子(frame、font、padding)の後に適用してください -
.interactive()は、ユーザーの操作に応答する要素(ボタン、切り替え可能な項目)にのみ使用してください - ガラス効果がいつ融合するかを制御するために、コンテナ内の間隔を慎重に設定してください
- ビューの階層を変更する際は
withAnimationを使用し、スムーズなモーフィング遷移を実現してください - ライトモード、ダークモード、アクセントモード/ティントモードなど、さまざまな外観でテストを行ってください
- アクセシビリティのコントラストを確保する— ガラス上のテキストは読みやすい状態を維持する必要がある
避けるべきアンチパターン
- GlassEffectContainer を使用せずに、複数の独立した
.glassEffect()ビューを使用すること - ガラスエフェクトを過度にネストしない — パフォーマンスと視覚的な明瞭さが低下します
- すべてのビューにガラス効果を適用すること — インタラクティブな要素、ツールバー、カードに限定する
- 角の半径を使用する際、UIKitで
clipsToBounds = trueを指定し忘れること - ウィジェットでのアクセント付きレンダリングモードを無視する — ホーム画面のティント表示が崩れる
- ガラスの背後に不透明な背景を使用する — 半透明効果が失われる
使用すべき場面
- 新しい iOS 26 デザインのナビゲーションバー、ツールバー、タブバー
- フローティングアクションボタンやカードスタイルのコンテナ
- 視覚的な奥行きとタッチフィードバックが必要なインタラクティブなコントロール
- システムのリキッドグラス(Liquid Glass)の外観と統合すべきウィジェット
- 関連するUI状態間のモーフィング遷移
---
name: liquid-glass-design
description: Implement Apple's Liquid Glass design system for iOS 26+ with dynamic glass materials, blur, reflection, and interactive morphing in SwiftUI, UIKit, and WidgetKit.
---
# Liquid Glass Design System (iOS 26)
Patterns for implementing Apple's Liquid Glass — a dynamic material that blurs content behind it, reflects color and light from surrounding content, and reacts to touch and pointer interactions. Covers SwiftUI, UIKit, and WidgetKit integration.
## When to Activate
- Building or updating apps for iOS 26+ with the new design language
- Implementing glass-style buttons, cards, toolbars, or containers
- Creating morphing transitions between glass elements
- Applying Liquid Glass effects to widgets
- Migrating existing blur/material effects to the new Liquid Glass API
## Core Pattern — SwiftUI
### Basic Glass Effect
The simplest way to add Liquid Glass to any view:
```swift
Text("Hello, World!")
.font(.title)
.padding()
.glassEffect() // Default: regular variant, capsule shape
```
### Customizing Shape and Tint
```swift
Text("Hello, World!")
.font(.title)
.padding()
.glassEffect(.regular.tint(.orange).interactive(), in: .rect(cornerRadius: 16.0))
```
Key customization options:
- `.regular` — standard glass effect
- `.tint(Color)` — add color tint for prominence
- `.interactive()` — react to touch and pointer interactions
- Shape: `.capsule` (default), `.rect(cornerRadius:)`, `.circle`
### Glass Button Styles
```swift
Button("Click Me") { /* action */ }
.buttonStyle(.glass)
Button("Important") { /* action */ }
.buttonStyle(.glassProminent)
```
### GlassEffectContainer for Multiple Elements
Always wrap multiple glass views in a container for performance and morphing:
```swift
GlassEffectContainer(spacing: 40.0) {
HStack(spacing: 40.0) {
Image(systemName: "scribble.variable")
.frame(width: 80.0, height: 80.0)
.font(.system(size: 36))
.glassEffect()
Image(systemName: "eraser.fill")
.frame(width: 80.0, height: 80.0)
.font(.system(size: 36))
.glassEffect()
}
}
```
The `spacing` parameter controls merge distance — closer elements blend their glass shapes together.
### Uniting Glass Effects
Combine multiple views into a single glass shape with `glassEffectUnion`:
```swift
@Namespace private var namespace
GlassEffectContainer(spacing: 20.0) {
HStack(spacing: 20.0) {
ForEach(symbolSet.indices, id: \.self) { item in
Image(systemName: symbolSet[item])
.frame(width: 80.0, height: 80.0)
.glassEffect()
.glassEffectUnion(id: item < 2 ? "group1" : "group2", namespace: namespace)
}
}
}
```
### Morphing Transitions
Create smooth morphing when glass elements appear/disappear:
```swift
@State private var isExpanded = false
@Namespace private var namespace
GlassEffectContainer(spacing: 40.0) {
HStack(spacing: 40.0) {
Image(systemName: "scribble.variable")
.frame(width: 80.0, height: 80.0)
.glassEffect()
.glassEffectID("pencil", in: namespace)
if isExpanded {
Image(systemName: "eraser.fill")
.frame(width: 80.0, height: 80.0)
.glassEffect()
.glassEffectID("eraser", in: namespace)
}
}
}
Button("Toggle") {
withAnimation { isExpanded.toggle() }
}
.buttonStyle(.glass)
```
### Extending Horizontal Scrolling Under Sidebar
To allow horizontal scroll content to extend under a sidebar or inspector, ensure the `ScrollView` content reaches the leading/trailing edges of the container. The system automatically handles the under-sidebar scrolling behavior when the layout extends to the edges — no additional modifier is needed.
## Core Pattern — UIKit
### Basic UIGlassEffect
```swift
let glassEffect = UIGlassEffect()
glassEffect.tintColor = UIColor.systemBlue.withAlphaComponent(0.3)
glassEffect.isInteractive = true
let visualEffectView = UIVisualEffectView(effect: glassEffect)
visualEffectView.translatesAutoresizingMaskIntoConstraints = false
visualEffectView.layer.cornerRadius = 20
visualEffectView.clipsToBounds = true
view.addSubview(visualEffectView)
NSLayoutConstraint.activate([
visualEffectView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
visualEffectView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
visualEffectView.widthAnchor.constraint(equalToConstant: 200),
visualEffectView.heightAnchor.constraint(equalToConstant: 120)
])
// Add content to contentView
let label = UILabel()
label.text = "Liquid Glass"
label.translatesAutoresizingMaskIntoConstraints = false
visualEffectView.contentView.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: visualEffectView.contentView.centerXAnchor),
label.centerYAnchor.constraint(equalTo: visualEffectView.contentView.centerYAnchor)
])
```
### UIGlassContainerEffect for Multiple Elements
```swift
let containerEffect = UIGlassContainerEffect()
containerEffect.spacing = 40.0
let containerView = UIVisualEffectView(effect: containerEffect)
let firstGlass = UIVisualEffectView(effect: UIGlassEffect())
let secondGlass = UIVisualEffectView(effect: UIGlassEffect())
containerView.contentView.addSubview(firstGlass)
containerView.contentView.addSubview(secondGlass)
```
### Scroll Edge Effects
```swift
scrollView.topEdgeEffect.style = .automatic
scrollView.bottomEdgeEffect.style = .hard
scrollView.leftEdgeEffect.isHidden = true
```
### Toolbar Glass Integration
```swift
let favoriteButton = UIBarButtonItem(image: UIImage(systemName: "heart"), style: .plain, target: self, action: #selector(favoriteAction))
favoriteButton.hidesSharedBackground = true // Opt out of shared glass background
```
## Core Pattern — WidgetKit
### Rendering Mode Detection
```swift
struct MyWidgetView: View {
@Environment(\.widgetRenderingMode) var renderingMode
var body: some View {
if renderingMode == .accented {
// Tinted mode: white-tinted, themed glass background
} else {
// Full color mode: standard appearance
}
}
}
```
### Accent Groups for Visual Hierarchy
```swift
HStack {
VStack(alignment: .leading) {
Text("Title")
.widgetAccentable() // Accent group
Text("Subtitle")
// Primary group (default)
}
Image(systemName: "star.fill")
.widgetAccentable() // Accent group
}
```
### Image Rendering in Accented Mode
```swift
Image("myImage")
.widgetAccentedRenderingMode(.monochrome)
```
### Container Background
```swift
VStack { /* content */ }
.containerBackground(for: .widget) {
Color.blue.opacity(0.2)
}
```
## Key Design Decisions
| Decision | Rationale |
|----------|-----------|
| GlassEffectContainer wrapping | Performance optimization, enables morphing between glass elements |
| `spacing` parameter | Controls merge distance — fine-tune how close elements must be to blend |
| `@Namespace` + `glassEffectID` | Enables smooth morphing transitions on view hierarchy changes |
| `interactive()` modifier | Explicit opt-in for touch/pointer reactions — not all glass should respond |
| UIGlassContainerEffect in UIKit | Same container pattern as SwiftUI for consistency |
| Accented rendering mode in widgets | System applies tinted glass when user selects tinted Home Screen |
## Best Practices
- **Always use GlassEffectContainer** when applying glass to multiple sibling views — it enables morphing and improves rendering performance
- **Apply `.glassEffect()` after** other appearance modifiers (frame, font, padding)
- **Use `.interactive()`** only on elements that respond to user interaction (buttons, toggleable items)
- **Choose spacing carefully** in containers to control when glass effects merge
- **Use `withAnimation`** when changing view hierarchies to enable smooth morphing transitions
- **Test across appearances** — light mode, dark mode, and accented/tinted modes
- **Ensure accessibility contrast** — text on glass must remain readable
## Anti-Patterns to Avoid
- Using multiple standalone `.glassEffect()` views without a GlassEffectContainer
- Nesting too many glass effects — degrades performance and visual clarity
- Applying glass to every view — reserve for interactive elements, toolbars, and cards
- Forgetting `clipsToBounds = true` in UIKit when using corner radii
- Ignoring accented rendering mode in widgets — breaks tinted Home Screen appearance
- Using opaque backgrounds behind glass — defeats the translucency effect
## When to Use
- Navigation bars, toolbars, and tab bars with the new iOS 26 design
- Floating action buttons and card-style containers
- Interactive controls that need visual depth and touch feedback
- Widgets that should integrate with the system's Liquid Glass appearance
- Morphing transitions between related UI states
すべてのファイル
1件のファイルliquid-glass-designをインストール
スキルファイルをダウンロードし、.claude/skills/ ディレクトリに解凍してください。
ZIPをダウンロードリポジトリをクローンし、スキルファイルをプロジェクトにコピーしてください。
git clone https://github.com/affaan-m/ECC/tree/main/skills/liquid-glass-design # Copy SKILL.md to your .claude/skills/ directory
コピー





家
