← Tous les articles

Liquid Glass dans SwiftUI : trois patterns issus du déploiement de Return sur iOS 26

Le Liquid Glass d’Apple est une API SwiftUI d’une seule ligne : .glassEffect().1 Return, mon minuteur de méditation, l’utilise neuf fois sur iOS, macOS et tvOS.2 L’une de ces utilisations applique le modificateur à une Shape personnalisée qui transforme les chiffres mêmes du minuteur en Liquid Glass, glyphe par glyphe.

Return sur iPhone — les chiffres mêmes du minuteur s'affichent en Liquid Glass via une Shape personnalisée (présentée dans le Pattern 1 ci-dessous) ; le sélecteur de durée est un HUD Liquid Glass

La question intéressante est de savoir ce qui se passe lorsqu’on va au-delà de la ligne unique. Les Human Interface Guidelines d’Apple posent une règle de superposition stricte : le Liquid Glass appartient à la couche fonctionnelle (contrôles, navigation, UI transitoire) et jamais à la couche de contenu.3 La plupart des neuf utilisations de Return sont des applications de couche fonctionnelle exemplaires : sélecteurs, boutons, bandeaux de contrôle, badges d’état en pause. Les utilisations intéressantes sont les trois qui contournent les règles sans les enfreindre.

Cet essai parcourt trois patterns que j’ai déployés, les règles qu’ils respectent, les pièges qui m’ont surpris et la surface d’API que j’ai délibérément choisi de ne pas utiliser.

Les Human Interface Guidelines d’Apple définissent le Liquid Glass à travers trois variantes de matériau. La variante regular adapte son apparence à ce qui se trouve en dessous (exemple de gauche, sombre ; exemple de droite, clair) ; la variante clear laisse transparaître le détail sous-jacent avec beaucoup moins de filtrage :3

Variante regular du Liquid Glass sur un fond sombre — référence Apple HIG

Variante regular du Liquid Glass sur un fond clair — référence Apple HIG

Variante clear du Liquid Glass — référence Apple HIG, montrant comment la variante clear laisse transparaître le détail visuel du contenu sous-jacent

Images de référence tirées de la page Materials de l’Apple HIG.3 Les deux variantes sont ce que .glassEffect() produit dans SwiftUI ; le choix entre elles tient à un seul argument du modificateur.

En bref

  • iOS 26 livre le Liquid Glass sous la forme .glassEffect(_:in:). La variante par défaut est .regular et la forme par défaut est Capsule.1
  • Return utilise trois patterns qui vont au-delà de la ligne unique : du verre sur une Shape personnalisée (texte du minuteur via les tracés de glyphes Core Text), le pattern miroir (reflet en dessous via une copie retournée et masquée) et des superpositions HUD de couche fonctionnelle.
  • Règle de l’Apple HIG : le Liquid Glass pour la couche fonctionnelle, les matériaux standard pour la couche de contenu.3
  • J’ai délibérément choisi de ne pas utiliser GlassEffectContainer. L’API de morphing n’a aucun cas d’usage dans Return (aucun élément de verre ne se métamorphose en un autre), et je n’ai pas mesuré l’écart de performance de rendu ; il s’agit d’un compromis non mesuré, pas d’une recommandation.1
  • Pièges : le verre sur un fond plat paraît plat ; un rendu de chiffres sans tremblement nécessite des cellules de largeur fixe ; le HStack de tvOS ignore la valeur d’environnement de direction de mise en page ; la réduction des animations doit être respectée pour l’animation de morphing.

Pour des patterns d’UI Apple voisins, lisez l’analyse approfondie du protocole de mise en page SwiftUI, le système typographique SF Pro et le vocabulaire des Symbol Effects.

L’API d’une seule ligne et la règle de superposition

Apple livre le Liquid Glass avec une faible surface d’API, présentée comme un pilier majeur du design à la WWDC 2025 :113

Text("Hello, World!")
    .font(.title)
    .padding()
    .glassEffect()                              // default: .regular variant, Capsule shape

Text("Hello, World!")
    .glassEffect(in: .rect(cornerRadius: 16))   // custom shape

Text("Hello, World!")
    .glassEffect(.regular.tint(.orange).interactive())  // tint + touch reactivity

Trois boutons de réglage : la variante (.regular ou .clear), la forme (n’importe quelle Shape) et une chaîne GlassEffectStyle (teinte, interactivité). Voilà toute l’API pour une vue unique. Le rendu multi-vues est pris en charge par un GlassEffectContainer distinct, sur lequel je reviendrai.

La HIG est plus stricte que l’API. Les Human Interface Guidelines d’Apple définissent deux couches dans toute interface iOS 26+ :3

  1. La couche de contenu : le document, la liste, la photo ou le média qu’une personne consulte. Utilisez ici des matériaux standard (les .regularMaterial, .thinMaterial, etc. existants).
  2. La couche fonctionnelle : contrôles, navigation, barres d’onglets, barres latérales, superpositions transitoires. Utilisez ici le Liquid Glass.

L’instruction précise d’Apple : « N’utilisez pas le Liquid Glass dans la couche de contenu. Le Liquid Glass fonctionne le mieux lorsqu’il établit une distinction claire entre les éléments interactifs et le contenu, et l’inclure dans la couche de contenu peut entraîner une complexité inutile et une hiérarchie visuelle déroutante. »3

La règle semble restrictive jusqu’à ce qu’on la transpose sur une vraie application. Return est un minuteur de méditation. Sa couche de contenu, c’est l’imagerie respiratoire et la vidéo en boucle qui défile derrière tout le reste. Sa couche fonctionnelle, c’est le sélecteur de durée, la pile de boutons démarrer/pause/arrêter, la rangée secondaire de boutons de réglages et (sur tvOS) le badge d’état en pause. Huit des neuf utilisations de verre de Return sont des applications de couche fonctionnelle exemplaires : trois variantes de sélecteur de durée pour les chemins de code iOS et macOS, le bouton bascule démarrer/pause, le bouton d’arrêt, la rangée de boutons de réglages, l’indicateur de pause tvOS et une superposition de contrôle transitoire de plus.4

La neuvième est le cas limite délibéré (le Liquid Glass sur les chiffres mêmes du minuteur), que la section suivante parcourt.

Pattern 1 : du verre sur une Shape personnalisée

Les chiffres du minuteur dans Return ne sont pas du texte dessiné par-dessus un fond de verre. Le verre est le texte. .glassEffect(.clear, in:) accepte n’importe quelle Shape,9 et une Shape est un protocole producteur de Path.10 L’astuce est donc la suivante : convertir la chaîne du minuteur en un tracé de glyphes à l’aide de Core Text,11 puis transmettre ce tracé-en-tant-que-Shape à .glassEffect.56

import SwiftUI
@preconcurrency import CoreText

struct GlassTextShape: Shape {
    let text: String
    let font: CTFont

    func path(in rect: CGRect) -> Path {
        guard !text.isEmpty else { return Path() }
        let combinedPath = CGMutablePath()

        let attrString = NSAttributedString(string: text, attributes: [.font: font])
        let line = CTLineCreateWithAttributedString(attrString)
        guard let runs = CTLineGetGlyphRuns(line) as? [CTRun], !runs.isEmpty else {
            return Path()
        }

        for run in runs {
            let glyphCount = CTRunGetGlyphCount(run)
            guard glyphCount > 0 else { continue }
            var glyphs = [CGGlyph](repeating: 0, count: glyphCount)
            var positions = [CGPoint](repeating: .zero, count: glyphCount)
            let range = CFRange(location: 0, length: glyphCount)
            CTRunGetGlyphs(run, range, &glyphs)
            CTRunGetPositions(run, range, &positions)

            for i in 0..<glyphCount {
                guard let glyphPath = CTFontCreatePathForGlyph(font, glyphs[i], nil) else { continue }
                let transform = CGAffineTransform(translationX: positions[i].x, y: positions[i].y)
                combinedPath.addPath(glyphPath, transform: transform)
            }
        }

        // Core Text y-axis is flipped vs SwiftUI; flip then re-bound and center.
        var swiftPath = Path(combinedPath).applying(CGAffineTransform(scaleX: 1, y: -1))
        let flippedBounds = swiftPath.boundingRect
        let offsetX = rect.midX - flippedBounds.midX
        let offsetY = rect.midY - flippedBounds.midY
        return swiftPath.applying(CGAffineTransform(translationX: offsetX, y: offsetY))
    }
}

Code de production réel issu de Return/Return/GlassTextShape.swift.5 La fonction path(in:) utilise Core Text pour disposer la chaîne, parcourt chaque CTRun, extrait le CGPath de chaque glyphe et les réunit en un seul CGMutablePath. Les deux étapes non évidentes viennent après la réunion : le système de coordonnées de Core Text place l’origine en bas à gauche, tandis que le Path de SwiftUI la place en haut à gauche ; le tracé doit donc être retourné via CGAffineTransform(scaleX: 1, y: -1). Ensuite, le boundingRect du tracé retourné a des valeurs y négatives, si bien qu’une translation le recentre à l’intérieur du rectangle que SwiftUI transmet à la Shape. Omettez l’une ou l’autre transformation et les glyphes s’affichent à l’envers ou hors de l’écran.

L’application tient ensuite en une seule ligne :

Rectangle()
    .fill(.clear)
    .glassEffect(.clear, in: textShape)
    .frame(width: cellWidth, height: cellHeight)

Le Rectangle transparent est un substitut de cible tactile ; le visuel réel est la forme produite par textShape. Avec une forme de tracé de glyphes, le matériau Liquid Glass ne remplit que les contours des glyphes. Le résultat : chaque chiffre du minuteur est une forme de Liquid Glass distincte, réfractant l’animation qui défile derrière elle.6

La nuance de la HIG. La règle énoncée par Apple est le Liquid Glass pour la couche fonctionnelle, les matériaux standard pour la couche de contenu, avec une exception explicite : les contrôles interactifs transitoires de la couche de contenu (curseurs, interrupteurs) peuvent adopter le Liquid Glass lorsqu’ils sont activés.3 Les chiffres du minuteur dans Return sont un affichage d’état, pas un contrôle : ils se mettent à jour une fois par seconde via Timer.publish(every: 1, ...) et n’ont aucun geste tactile (c’est le bouton démarrer/pause situé en dessous qui bascule l’état). Y poser du Liquid Glass est donc un cas limite délibéré, plus proche d’un « contrôle interactif transitoire » par intention que par interactivité littérale, puisque les chiffres sont le point focal visuel que les utilisateurs regardent durant toute la session. Je contourne la règle, je ne l’enfreins pas. Un relecteur qui lit la HIG à la lettre pourrait soutenir qu’il faudrait ici un matériau standard ; j’avance que le minuteur est une surface de contrôle de temps écoulé de la même famille qu’un indicateur de progression. La documentation d’Apple ne tranche pas directement le cas.

Pourquoi une Shape personnalisée plutôt que Text + arrière-plan. Du Text rendu au-dessus d’un fond de verre se lit comme du texte sur du verre. Du Text rendu en tant que verre se lit comme une catégorie visuelle différente. L’utilisateur perçoit les chiffres comme un premier plan fonctionnel, et plus précisément comme un élément transitoire qui existe pour qu’on regarde à travers, et non qu’on le regarde lui.

Pattern 2 : le pattern miroir

Return affiche un reflet du minuteur en dessous, en fondu. Code de production réel :6

Return sur Mac — le sélecteur de durée sous forme de superposition HUD Liquid Glass, avec le traitement verre du texte du minuteur visible au-dessus

VStack(spacing: 0) {
    GlassTimerText(text: displayTime, fontSize: fontSize)
        .accessibilityLabel("Time remaining: \(accessibleDescription)")

    if showReflection {
        GlassTimerText(text: displayTime, fontSize: fontSize)
            .scaleEffect(x: 1, y: -1)
            .mask(
                LinearGradient(
                    stops: [
                        .init(color: .white.opacity(0.2), location: 0),
                        .init(color: .clear, location: 0.6)
                    ],
                    startPoint: .top,
                    endPoint: .bottom
                )
            )
            .offset(y: -8)
            .accessibilityHidden(true)
    }
}

Trois transformations composent le miroir, toutes des primitives SwiftUI standard :14

  1. scaleEffect(x: 1, y: -1) retourne la seconde copie à l’envers.
  2. .mask(LinearGradient(...)) fait passer le reflet de 20 % d’opacité en haut à une transparence totale à 60 % de hauteur.
  3. .offset(y: -8) remonte le reflet de 8 points pour qu’il jouxte l’original au lieu de laisser une jointure visible.

Le modificateur .accessibilityHidden(true) sur le reflet est porteur. VoiceOver ne doit pas annoncer deux fois l’heure en miroir ; l’accessibilityLabel et l’accessibilityAddTraits(.updatesFrequently) de l’original sont déjà rattachés à l’instance principale de GlassTimerText ci-dessus, et le reflet est purement décoratif.

Pourquoi cela fonctionne précisément avec le Liquid Glass. Le reflet hérite du matériau de verre de GlassTimerText. Tout arrière-plan sur lequel repose l’original (un dégradé de cercle respiratoire, une vidéo, une scène teintée) se réfracte à travers les deux copies. Le miroir n’a besoin d’aucun code spécifique au verre ; le matériau de verre gère la réfraction gratuitement. L’effet tout entier tient en trois modificateurs et un dégradé.

Le coût en accessibilité. Les utilisateurs ayant réduit les animations voient toujours le miroir, mais l’animation du matériau de verre entre les mises à jour de l’heure est supprimée ailleurs via @Environment(\.accessibilityReduceMotion).7 Le reflet en lui-même est statique ; seul le morphing entre les transitions de chiffres s’anime.

Pattern 3 : superpositions HUD en verre pour les contrôles transitoires

Les huit utilisations de verre restantes dans Return sont des applications de couche fonctionnelle exemplaires.4 Chacune suit le même pattern :

Return sur Apple Watch — du Liquid Glass de couche fonctionnelle à une petite taille de toile

durationPicker
    .frame(height: 50)
    .frame(maxWidth: 320)
    .glassEffect()
    .padding(.horizontal, 20)
    .transition(.opacity.combined(with: .scale(scale: 0.95)))

Le .transition(.opacity.combined(with: .scale(scale: 0.95))) est la partie porteuse. Le Liquid Glass sur des contrôles transitoires ne paraît juste que lorsque les contrôles transitent. Un HUD en verre statique qui reste en permanence à l’écran se lit comme un élément de chrome. Un HUD en verre qui apparaît en fondu et en mise à l’échelle lorsque l’utilisateur tape, puis disparaît lorsqu’il détourne le regard, se lit comme une surface de contrôle momentanée.

La documentation d’Apple sur glassEffect le note implicitement : le modificateur « capture le contenu à envoyer au conteneur pour le rendu » et « réagi[t] aux interactions tactiles et au pointeur en temps réel ».1 Les points d’accroche de l’animation ne sont pas dans l’API, mais le pipeline de rendu suppose que les éléments de verre bougent. Les éléments de verre statiques manquent cette affordance.

Return utilise le pattern pour le sélecteur de durée (qui glisse vers le haut lorsque l’utilisateur tape), le bouton bascule démarrer/pause (toujours visible mais qui se met à l’échelle à la pression), le bouton d’arrêt (visible uniquement en cours de session), la rangée de boutons de réglages (un bandeau de contrôle horizontal sous le sélecteur de durée) et le badge d’état en pause tvOS (visible uniquement lorsqu’une session est en pause sur Apple TV). Ces cinq contextes respectent la règle de couche fonctionnelle de la HIG.3

Référence tvOS d'Apple : des superpositions Liquid Glass flottant au-dessus d'un fond vidéo, laissant transparaître le média sous-jacent — le cas d'usage canonique de l'UI à 3 mètres

Référence Apple HIG : sur tvOS, les superpositions Liquid Glass se placent au-dessus de la couche média, la laissant transparaître.3 L’implémentation tvOS de Return suit le même modèle : les contrôles flottent au-dessus du fond de feu/forêt/eau en boucle.

Une note sur la toolbar issue des labs. Un panel du SwiftUI Group Lab de la WWDC 2026 a affiné la manière dont cela se traduit dans les toolbars. Placer un contenu non vitré dans une toolbar — l’exemple était une photo de profil — appelle sharedBackgroundVisibility(.hidden) afin que l’élément abandonne son fond de verre partagé et affiche directement la photo.15 Le panel a signalé un raffinement : une API plus récente ne supprime que la marge de contenu d’un bouton de toolbar, là où auparavant masquer le fond était le seul levier et qu’il supprimait conjointement le fond et la marge. Pour les boutons de toolbar eux-mêmes, le panel orientait vers le style de bouton prominent (glassProminent) et buttonBorderShape plutôt que de recourir directement à .glassEffect sur un bouton. La position de fond de la HIG est la même règle de superposition autour de laquelle pivote ce billet : le Liquid Glass appartient au chrome, pas à la zone de contenu, car une surface de verre sous laquelle aucun contenu ne défile n’a rien à réfracter.153

La question du GlassEffectContainer

Apple recommande GlassEffectContainer chaque fois qu’une application utilise .glassEffect() sur plusieurs vues, pour deux raisons : de meilleures performances de rendu (les effets de verre sont regroupés en lots) et la possibilité de métamorphoser les formes les unes en les autres pendant les transitions.1

Je ne l’ai pas utilisé. Le raisonnement est spécifique à l’application, et non une réfutation des conseils d’Apple. Return a neuf vues en verre, dont aucune n’a besoin de se métamorphoser en une autre.46 Le sélecteur de durée ne se transforme jamais en bouton de démarrage. Le texte du minuteur ne se transforme jamais en rangée de boutons de réglages. Chaque élément de verre est indépendant. L’API de morphing n’aurait aucun cas d’usage où se déclencher, et les règles d’espacement du conteneur contraindraient des mises en page qui n’ont aujourd’hui besoin d’aucune coordination.

L’argument des performances de rendu, je ne peux le réfuter pleinement sans mesure. La documentation d’Apple avertit que « trop » d’effets de verre hors d’un conteneur peut dégrader les performances.1 Les neuf vues de Return ne partagent jamais l’écran en même temps (le sélecteur de durée n’apparaît que dans l’état menu, le bouton d’arrêt uniquement en pause en cours de session). À une image donnée, je compte trois ou quatre éléments de verre visibles, ce qui a été fluide sur chaque appareil que j’ai testé sur iOS, iPadOS, macOS, watchOS et tvOS, mais je n’ai pas exécuté de trace Instruments comparant la version encapsulée dans un conteneur à la version uniquement par modificateur. La formulation honnête est donc la suivante : Return se passe de GlassEffectContainer sur la base d’une expérience utilisateur observée comme bonne, et non d’une équivalence de performance mesurée.

La règle que j’en ai tirée : GlassEffectContainer est destiné aux applications où plusieurs éléments de verre sont visibles et s’animent simultanément. L’exemple d’Apple est le rendu d’un jeu de symboles avec glassEffectUnion(id:namespace:) : quatre symboles météo qui fusionnent et se séparent avec fluidité comme une seule unité.1 C’est un cas d’usage exemplaire. Si une future fonctionnalité de Return a besoin que des éléments de verre se métamorphosent ou partagent les règles d’espacement d’un conteneur, le conteneur sera alors le bon outil à ajouter. Pour l’application d’aujourd’hui, je n’ai pas encore rencontré ce cas.

Les pièges qui m’ont surpris

Trois vrais bugs issus de la production :

Tremblement des chiffres en verre. SF Pro Rounded a des chiffres de largeur variable en rendu proportionnel. À mesure que le minuteur décomptait, la chaîne affichée changeait de longueur, et le HStack environnant se redisposait chaque seconde, faisant trembler tout le minuteur. Le correctif : des cellules de largeur fixe pour chaque caractère. Chaque chiffre reçoit un cellWidth de fontSize * 0.6, chaque deux-points reçoit fontSize * 0.3, et le HStack devient une grille stable.6

HStack(spacing: 0) {
    ForEach(Array(text.enumerated()), id: \.offset) { _, char in
        let isColon = char == ":"
        let cellWidth = isColon ? colonCellWidth : digitCellWidth
        GlassDigitCell(character: String(char), font: ctFont,
                       cellWidth: cellWidth, cellHeight: cellHeight)
    }
}

Les cellules ne sont pas standard chez Apple ; ce sont un contournement du rendu à largeur proportionnelle à de petites tailles de police fixes. SF Pro Rounded d’Apple avec .monospacedDigit() résoudrait le même problème sur Text, mais le modificateur n’est pas disponible sur un moteur de rendu en verre fondé sur une Shape personnalisée. La mise en page à cellules fixes en est le substitut.

Surcharge de la direction de mise en page tvOS. Le même GlassTimerText s’exécutait sur iOS, iPadOS, macOS et tvOS. Sur tvOS en particulier, le HStack se trouvait inversé dans un environnement de langue de droite à gauche alors même que la version iOS respectait la surcharge dans l’environnement. Le correctif : fixer la direction de mise en page à la fois via la valeur d’environnement et via le modificateur explicite flipsForRightToLeftLayoutDirection(false), appliqué directement au HStack de cellules de chiffres (le VStack parent applique séparément la surcharge d’environnement afin que la copie du reflet en hérite) :6

HStack(spacing: 0) { ... }
    .flipsForRightToLeftLayoutDirection(false)
    .environment(\.layoutDirection, .leftToRight)

La raison : le HStack de tvOS semble ignorer la surcharge au niveau de l’environnement dans certaines versions, et flipsForRightToLeftLayoutDirection(false) est le contrat explicite de non-inversion qui est respecté de manière plus fiable.12 Bretelles et ceinture.

Réduction des animations sur le morphing des chiffres. Le Liquid Glass anime par défaut les transitions de morphing entre les chaînes affichées. Les utilisateurs ayant activé accessibilityReduceMotion voyaient le morphing comme un scintillement. Le correctif :6

.animation(reduceMotion ? nil : .easeInOut(duration: 0.15), value: displayTime)

Le modificateur d’animation lit @Environment(\.accessibilityReduceMotion) et désactive entièrement la transition lorsque la réduction des animations est activée. Les recommandations d’accessibilité d’Apple sont explicites : toute animation décorative doit respecter la préférence de mouvement de l’utilisateur.7

Quand ne pas utiliser le Liquid Glass

Le refus fait partie du design.

Ne mettez pas de Liquid Glass dans la couche de contenu. La HIG d’Apple est explicite, et ignorer la règle produit une hiérarchie déroutante : l’utilisateur ne parvient pas à distinguer ce qui est interactif de ce qui est du contenu.3 Si un effet de verre décore une ligne de liste ou une fiche photo, le design lutte contre la plateforme.

N’utilisez pas de verre sur un fond plat. Le Liquid Glass réfracte ce qui se trouve derrière lui. Si « ce qui se trouve derrière lui » est une seule couleur unie, la réfraction n’a rien à courber, et le résultat se lit comme un rectangle teinté plat. Soit vous placez le verre sur un contenu varié (un dégradé, une image, une vidéo), soit vous n’utilisez pas de verre du tout. L’écran du minuteur de Return fait défiler une imagerie de couverture thématique et une vidéo en boucle en arrière-plan via VideoBackgroundView,4 précisément pour que les éléments de verre situés au-dessus aient toujours de la texture à réfracter.

Soyez prudent avec le verre sur du contenu à haute fréquence. Le rendu du matériau de verre est limité par le GPU, et l’animation de morphing par défaut entre les changements de forme du verre est elle-même une animation. Un minuteur qui se met à jour une fois par seconde convient dans mes tests ; une forme d’onde ou un visualiseur audio à 60 Hz n’est pas éprouvé et entre probablement en conflit avec l’animation de morphing. Je n’ai pas mesuré la limite supérieure ; traitez ceci comme une heuristique, et non comme un seuil mesuré. La documentation d’Apple n’en publie aucun.

Ne livrez pas de verre sans tester la réduction des animations. Toute animation en verre devrait être conditionnée à accessibilityReduceMotion.7 Le morphing par défaut entre les formes de verre est un effet cinétique, pas un simple fondu.

Ce que le Liquid Glass signifie pour les applications livrées sur iOS 26+

La thèse est modeste. Le Liquid Glass n’est une API d’une seule ligne que lorsque l’application respecte déjà la règle de superposition de la HIG. Une application SwiftUI qui place les contrôles dans la couche fonctionnelle et le contenu dans la couche de contenu peut adopter le Liquid Glass avec des modificateurs .glassEffect() et paraître native par défaut.

Les applications qui mélangent les deux couches (des contrôles à l’intérieur des lignes de liste, des barres de navigation traitées comme du contenu, du chrome décoratif sur des fiches photo) adopteront le Liquid Glass et paraîtront fausses. Le matériau est correct ; l’architecture qui le sous-tend ne l’est pas.

Le pattern de Shape personnalisée (Pattern 1) prolonge proprement la règle. Tout ce qui est fonctionnellement un contrôle peut adopter le Liquid Glass, même si cela ne ressemble pas à un « contrôle » au sens conventionnel. Un minuteur est un contrôle, un vumètre est un contrôle, un indicateur de progression est un contrôle. Le Liquid Glass sur chacun d’eux est conforme aux spécifications.

Associez ce billet à mes écrits antérieurs sur le déploiement de la couche de données de la même application via les App Intents et via un serveur MCP. La couche visuelle est la troisième surface de la même pile : des entités typées pour l’IA système, un format de fichier pour les agents multi-LLM, et le Liquid Glass pour l’humain devant l’appareil.8

FAQ

Puis-je utiliser .glassEffect() sur des plateformes autres qu’iOS 26 ?

Le modificateur .glassEffect() est disponible sur iOS 26+, iPadOS 26+, macOS 26+, watchOS 26+, tvOS 26+, visionOS 26+. Les plateformes antérieures à la version 26 disposent de .background(.regularMaterial) et de modificateurs similaires, qui produisent des effets de verre dépoli mais pas la nouvelle réfraction du Liquid Glass.1

GlassEffectContainer change-t-il le visuel ?

Les éléments de verre encapsulés dans un conteneur peuvent fondre leurs formes ensemble lorsque leurs règles d’espacement provoquent un chevauchement. Sans conteneur, chaque .glassEffect() est indépendant. Pour les applications où des éléments de verre doivent fusionner avec fluidité pendant l’animation, GlassEffectContainer est le bon outil. Pour les applications où chaque élément de verre reste distinct, un conteneur est une surcharge.1

Pourquoi ne pas utiliser Text directement avec .foregroundStyle(.thinMaterial) ?

thinMaterial est un matériau standard, pas du Liquid Glass. Le visuel est une superposition de verre dépoli, et non l’effet de verre réfractif avec courbure de la lumière du Liquid Glass.3 Pour du texte qui doit ressembler précisément au nouveau matériau, .glassEffect(.clear, in: customShape) est le chemin pris en charge.

Comment capturer une capture d’écran Liquid Glass pour le marketing ?

Les effets de verre sont rendus par le GPU à l’exécution, si bien que les captures d’écran sont prises depuis le simulateur ou l’appareil avec l’effet déjà appliqué. L’imagerie de référence officielle du Liquid Glass d’Apple provient de ses pages de documentation HIG et des sessions de la WWDC 2025.3

GlassTextShape fonctionne-t-il pour un texte arbitraire ou seulement pour des chiffres ?

Toute chaîne que Core Text peut disposer fonctionne. Return l’utilise pour des chiffres et un deux-points, mais la même Shape fonctionne pour des lettres, des symboles, des emoji (avec la bonne police) ou des chaînes mixtes. Les performances sont bornées par le nombre de glyphes ; un long paragraphe rendu en verre serait coûteux, mais un minuteur de six caractères est trivial.


Trois patterns, une règle et une API que j’ai délibérément ignorée. Le Liquid Glass est la troisième surface d’une application iOS 26+, posée au-dessus des entités typées et des formats de fichier partagés. L’API d’une seule ligne est bien réelle. La règle de la HIG qui la sous-tend est ce qui fait que cette ligne unique fonctionne.

Références


  1. Apple Developer, « Applying Liquid Glass to custom views ». Documentation du modificateur glassEffect(_:in:), de GlassEffectContainer, de glassEffectUnion(id:namespace:), de glassEffectID(_:in:) et de GlassEffectTransition. Variante par défaut .regular, forme par défaut Capsule

  2. Return de l’auteur, une application de minuteur de méditation publiée sur l’App Store le 21 avril 2026, disponible pour iPhone, iPad, Mac, Apple Watch et Apple TV. Utilise SwiftUI, SwiftData et HealthKit sur iOS 26+ / macOS 26+. 

  3. Apple Developer, Human Interface Guidelines « Materials ». Définit la règle couche fonctionnelle vs couche de contenu pour le Liquid Glass : « N’utilisez pas le Liquid Glass dans la couche de contenu. » Liste les variantes regular et clear ainsi que leurs usages prévus. 

  4. Code de production dans Return/Return/ContentView.swift (sept sites d’appel .glassEffect()), Return/Return/GlassTimerText.swift (un site d’appel sur GlassDigitCell) et Return/ReturnTV/TVContentView.swift (un site d’appel sur l’indicateur « Paused » tvOS). Neuf au total. Plus Return/Return/VideoBackgroundView.swift, qui rend l’imagerie de couverture thématique et la vidéo en boucle que les éléments de verre réfractent. 

  5. Code de production dans Return/Return/GlassTextShape.swift. Le wrapper conforme à Shape autour de Core Text. Créé le 26 novembre 2025, inclus dans la v1.0 livrée sur l’App Store. 

  6. Code de production dans Return/Return/GlassTimerText.swift. Les vues GlassDigitCell, GlassTimerText et GlassTimerDisplay. Implémente la mise en page à cellules de largeur fixe, le reflet en miroir et le conditionnement à la réduction des animations. 

  7. Apple Developer, valeur d’environnement « accessibilityReduceMotion ». Les applications doivent respecter la préférence de mouvement de l’utilisateur ; les animations de morphing par défaut du Liquid Glass devraient être conditionnées à cette valeur. 

  8. Analyse de l’auteur dans App Intents Are Apple’s New API to Your App et Two Agent Ecosystems, One Shopping List. Le modèle à trois surfaces : App Intents pour Apple Intelligence, MCP pour les agents multi-LLM, Liquid Glass pour l’humain devant l’appareil. 

  9. Apple Developer, « glassEffect(_:in:isEnabled:) » sur View. Le paramètre in: accepte n’importe quel type conforme à Shape. La forme par défaut est Capsule

  10. Apple Developer, protocole « Shape ». Une Shape est tout type qui produit un Path pour un rectangle donné. Les formes personnalisées peuvent encapsuler des données CGPath arbitraires. 

  11. Apple Developer, « Core Text Programming Guide » et CTLineCreateWithAttributedString. Core Text est le moteur de texte de plus bas niveau utilisé pour disposer les chaînes attribuées en runs de glyphes et extraire les tracés par glyphe. 

  12. Apple Developer, « flipsForRightToLeftLayoutDirection(_:) ». Surcharge explicitement l’inversion de droite à gauche sur une View, quelle que soit la valeur d’environnement \.layoutDirection environnante. 

  13. Apple, « WWDC 2025 Highlights » via Apple Newsroom. Le Liquid Glass annoncé comme le matériau de design unificateur sur iOS 26, iPadOS 26, macOS 26, watchOS 26, tvOS 26 et visionOS 26. Sessions : « Meet Liquid Glass » (WWDC 2025), « Build a SwiftUI app with Liquid Glass »

  14. Apple Developer, « LinearGradient », « scaleEffect(x:y:anchor:) », « mask(_:) ». Primitives SwiftUI standard, toutes disponibles depuis iOS 13. 

  15. Apple, SwiftUI Group Lab de la WWDC 2026 (session 2). Paraphrasé d’un enregistrement transcrit localement du SwiftUI Group Lab de la WWDC 2026 (session 2) ; Apple ne publie aucun sous-titre officiel pour les labs. Source pour le masquage du fond de verre partagé d’un élément de toolbar afin d’afficher un contenu non vitré (une photo de profil), pour l’API plus récente qui ne supprime que la marge de contenu d’un bouton de toolbar plutôt que le fond et la marge conjointement, pour la préférence du style de bouton de verre prominent et de buttonBorderShape plutôt que de .glassEffect sur un bouton, et pour la logique de superposition chrome-et-non-contenu. Les symboles afférents sont documentés à sharedBackgroundVisibility(_:) sur CustomizableToolbarContent, qui prend une valeur Visibility telle que .hidden, et à buttonBorderShape(_:) ; glassProminent est le PrimitiveButtonStyle Liquid Glass prominent. L’API de marge de contenu précise nommée dans le lab n’a pas pu être confirmée par rapport à la documentation publiée d’Apple, elle est donc décrite par son comportement plutôt qu’affirmée par son symbole. 

Articles connexes

HealthKit + SwiftUI sur iOS 26 : autorisation, types d'échantillons et patterns multi-plateformes tirés de la mise en production de deux apps

Patterns de production réels issus de Water (suivi de l'eau, HKQuantitySample) et Return (sessions de pleine conscience,…

16 min de lecture

Protocole Layout de SwiftUI : créer des mises en page personnalisées de sizeThatFits à placeSubviews

Le protocole Layout d'iOS 16 permet aux applications de créer des mises en page personnalisées avec deux méthodes. sizeT…

13 min de lecture

Le goût est une infrastructure

À mesure que les agents génèrent une part croissante de ce qui est livré, le plafond de qualité dépend de votre capacité…

7 min de lecture