Liquid Glass Framework

repository·main·Indexed 43 days ago

https://github.com/conorluddy/liquidglassreference

A Swift/SwiftUI framework for implementing Apple's iOS 26 design language. It provides translucent, dynamic materials for navigation layers featuring real-time lensing, morphing transitions via GlassEffectContainer, and specialized modifiers like .glassEffect(), .glassEffectID(), and .glassEffectUnion(). Includes built-in support for glass button styles, toolbars, TabViews, and accessibility adaptations for reduced transparency and motion.

Tokens
9.6K
Snippets
26
Records
36
Agent score
6%

What's inside Liquid Glass

  1. What is Liquid Glass and when should I use it?

    main

    Liquid Glass is a translucent, dynamic material designed for the navigation layer that floats above app content. It uses real-time lensing (light bending) and specular highlights to create depth.

    Design Philosophy

    Never apply Liquid Glass to the content itself (e.g., lists, tables, or media). It is intended exclusively for functional overlays like toolbars, buttons, and navigation bars to maintain a clear visual hierarchy.

    Material Variants

    VariantUse CaseTransparencyAdaptivity
    .regularDefault for most UI (toolbars, buttons, tab bars)MediumFull - adapts to any content
    .clearSmall floating controls over media (photos/maps)HighLimited - requires dimming layer
    .identityConditional disabling of the effectNoneN/A

    Requirements for the .clear variant:

    1. The element must sit over media-rich content.
    2. The content must not be negatively affected by the required dimming layer.
    3. The content above the glass must be bold and bright.
  2. How GlassEffectContainer works

    main

    A GlassEffectContainer is used to group multiple Liquid Glass shapes into a unified composition. It improves rendering performance by sharing a sampling region and is required for morphing transitions between glass elements.

    Critical Rule: Glass cannot sample other glass; the GlassEffectContainer provides the shared sampling region necessary for multiple elements to interact visually.

    Use the spacing parameter to control the morphing threshold. Elements within this distance will visually blend and morph together during transitions.

    GlassEffectContainer(spacing: 40.0) {
        ForEach(icons) { icon in
            IconView(icon)
                .glassEffect()
        }
    }
  3. Design principles for Liquid Glass

    main

    When to use Liquid Glass

    • Use for: Navigation bars, toolbars, tab bars, floating action buttons, sheets, popovers, menus, and system-level alerts.
    • Avoid for: Content layers (lists, tables, media), full-screen backgrounds, scrollable content, or stacking multiple glass layers.

    Design Guidelines

    • Hierarchy: Content is Primary $\rightarrow$ Glass controls are Secondary $\rightarrow$ Overlay fills/vibrancy are Tertiary.
    • Contrast: Maintain a minimum 4.5:1 contrast ratio. Use vibrant text on glass and subtle borders for definition.
    • Tinting: Use selectively for primary actions to convey meaning, not just decoration.
  4. Understand dynamic glass color adaptation

    main

    Glass effects automatically adapt their appearance based on the background color scheme:

    • Light/Dark Switching: Glass automatically flips between light and dark modes based on the background (e.g., a black background triggers light glass).
    • Element Size Logic:
      • Small elements (nav bars, tab bars): Flip between light/dark.
      • Large elements (sidebars, menus): Adapt appearance without flipping to avoid jarring visual shifts.
    • Visual Adjustments: Shadows adjust opacity based on text/background contrast, and tints adjust hue, brightness, and saturation for legibility.
  5. Follow glass layering guidelines

    main

    To maintain a clear visual hierarchy, avoid 'Glass-on-Glass' stacking. Instead, follow this layering philosophy:

    1. Content layer (bottom): The primary content (lists, tables, media). Do not apply glass here.
    2. Navigation layer (middle): Floating elements like tab bars, toolbars, or sidebars. Apply Liquid Glass here.
    3. Overlay layer (top): Elements like vibrancy fills or popovers that sit on top of the glass.

    Correct Pattern: Use a ZStack to place a single glass layer (like a Header) over a non-glass content layer.

    // ✅ GOOD - Clear separation
    ZStack {
        ContentView()  // No glass
        HeaderView().glassEffect()  // Single floating layer
    }
  6. Implement morphing transitions with glassEffectID

    main

    To enable morphing transitions between glass elements, you must satisfy four requirements:

    1. Elements must reside in the same GlassEffectContainer.
    2. Each view must have a glassEffectID using a shared @Namespace.
    3. Views must be conditionally shown/hidden to trigger the morph.
    4. An animation must be applied to the state changes.

    Use the glassEffectID(_:in:) modifier to assign a unique identifier to a view within a namespace.

    struct MorphingExample: View {
        @State private var isExpanded = false
        @Namespace private var namespace
        
        var body: some View {
            GlassEffectContainer(spacing: 30) {
                Button(isExpanded ? "Collapse" : "Expand") {
                    withAnimation(.bouncy) {
                        isExpanded.toggle()
                    }
                }
                .glassEffect()
                .glassEffectID("toggle", in: namespace)
                
                if isExpanded {
                    Button("Action 1") { }
                        .glassEffect()
                        .glassEffectID("action1", in: namespace)
                    
                    Button("Action 2") { }
                        .glassEffect()
                        .glassEffectID("action2", in: namespace)
                }
            }
        }
    }
  7. Implement backward compatibility for Liquid Glass

    main

    While basic adoption is automatic upon recompiling with Xcode 26, you can manage compatibility manually:

    1. Temporary Opt-Out: Add the UIDesignRequiresCompatibility key to your Info.plist (expires iOS 27).
    2. Custom Compatibility Extension: Create a wrapper that checks for #available(iOS 26.0, *) to provide a manual fallback (like .ultraThinMaterial) for older OS versions.
    extension View {
        @ViewBuilder
        func glassedEffect(
            in shape: some Shape = Capsule(),
            interactive: Bool = false
        ) -> some View {
            if #available(iOS 26.0, *) {
                let glass = interactive ? Glass.regular.interactive() : .regular
                self.glassEffect(glass, in: shape)
            } else {
                // Fallback for iOS 18
                self
                    .background(
                        shape
                            .fill(.ultraThinMaterial)
                            .overlay(
                                LinearGradient(
                                    colors: [.white.opacity(0.3), .clear],
                                    startPoint: .topLeading,
                                    endPoint: .bottomTrailing
                                )
                            )
                            .overlay(shape.stroke(.white.opacity(0.2), lineWidth: 1))
                    )
            }
        }
    }
  8. Optimize glass effect performance

    main

    Follow these best practices to ensure smooth performance and avoid GPU lag or thermal issues:

    1. Use GlassEffectContainer: Always wrap multiple glass elements in a single GlassEffectContainer for efficient rendering. Avoid applying .glassEffect() to multiple individual elements in a list or stack without a container.
    2. Use .identity for toggling: When conditionally showing glass, use .glassEffect(shouldShowGlass ? .regular : .identity) to avoid layout recalculations.
    3. Limit continuous animations: Avoid continuous rotations or infinite linear animations on glass elements; let them rest in steady states.
    4. Hardware testing: Monitor performance on older devices (iPhone 11-13) using Instruments to check GPU usage and thermal impact.
  9. Handle accessibility for Liquid Glass

    main

    Liquid Glass includes automatic system adaptations for accessibility settings. It is recommended to let the system handle these automatically rather than overriding them manually.

    Automatic Adaptations

    • Reduced Transparency: Increases frosting for better clarity.
    • Increased Contrast: Applies starker colors and borders.
    • Reduced Motion: Tones down animations and elastic effects.
    • iOS 26.1+ Tinted Mode: Respects user-controlled opacity settings.

    Manual Control (If necessary)

    If you must manually adjust the effect based on accessibility environments, use the following environment values:

    @Environment(\.accessibilityReduceTransparency) var reduceTransparency
    @Environment(\.accessibilityReduceMotion) var reduceMotion
    
    var body: some View {
        Text("Accessible")
            .padding()
            .glassEffect(reduceTransparency ? .identity : .regular)
    }
  10. Integrate with Toolbars

    main

    In iOS 26, toolbars automatically adopt Liquid Glass styling. .confirmationAction items automatically receive the .glassProminent style.

    Toolbar Features:

    • Grouping & Spacing: Use ToolbarSpacer to manage layout.
      • ToolbarSpacer(.fixed, spacing: 20): Inserts a fixed amount of space.
      • ToolbarSpacer(.flexible): Pushes items apart.
    • Badges: Use .badge(count) to add red notification badges.
    • Background Control: Use .sharedBackgroundVisibility(.hidden) to remove the glass background from a specific item.
    .toolbar {
        ToolbarItemGroup(placement: .topBarTrailing) {
            Button("Draw", systemImage: "pencil") { }
            Button("Erase", systemImage: "eraser") { }
        }
        
        ToolbarSpacer(.fixed, spacing: 20)
        
        ToolbarItem(placement: .topBarTrailing) {
            Button("Save", systemImage: "checkmark") { }
                .buttonStyle(.glassProminent)
        }
    }
  11. Best practices for implementing Liquid Glass

    main

    When implementing iOS 26 Liquid Glass, follow these architectural and design principles to ensure usability and performance:

    • Layering: Reserve Liquid Glass effects for the navigation layer only.
    • Composition: Always use GlassEffectContainer when managing multiple glass elements to ensure proper rendering and coordination.
    • Transitions: Use morphing transitions for smooth state changes between different glass configurations.
    • Legibility: Prioritize content legibility over visual effects; do not let glass effects obscure text or interactive elements.
    • Accessibility: Test extensively with accessibility settings enabled and respect user preferences and system settings.
    • Performance: Monitor performance closely, especially on older devices, as glass effects can be resource-intensive.