Le point de départ
Nous voulions, sur notre propre site, l'effet de verre popularisé par Aave et visionOS : des cartes qui semblent taillées dans une matière transparente et qui déforment ce qui passe derrière elles. Toutes les recettes publiques que nous avons essayées donnaient le même résultat : un flou, un reflet en dégradé, une bordure claire. Joli, mais faux — rien ne se déforme.
La différence tient en une phrase : un flou lisse ce qu'il y a derrière, une réfraction le déplace. Tant qu'on empile des dégradés, on imite l'apparence du verre sans jamais reproduire ce qui le rend reconnaissable — la façon dont il courbe l'image du décor près de ses bords.
Le mur : un comportement que rien ne documente
La technique théoriquement correcte existe pourtant. On construit une displacement map —
une image dont les canaux rouge et vert encodent, pour chaque pixel, de combien décaler ce qui se
trouve derrière — et on l'applique au décor via un filtre SVG posé en backdrop-filter.
Sur le papier, c'est réglé en vingt lignes. Dans Chromium, le résultat était inutilisable : la bande de courbure n'était pas au bord de la carte. Elle était décalée, et le décalage changeait selon l'endroit où la carte se trouvait dans la fenêtre. Une carte en haut de page se comportait différemment de la même carte en bas. Aucune des ressources consultées ne mentionnait ce comportement.
La démarche : quatre étapes, une variable à la fois
C'est ici que le travail commence vraiment. Un bug qu'aucune documentation ne décrit ne se résout pas en cherchant plus longtemps sur le web : il se résout en le rendant reproductible.
1. Reproduire au plus petit
Première décision : sortir du site. Nous avons monté une page nue — un fond, un seul élément, le filtre, et rien d'autre. Ni design system, ni animation d'apparition, ni police personnalisée. Tant que le bug vit dans une page de production, chaque hypothèse traîne des dizaines de causes possibles. Sur une page nue, il n'en reste qu'une poignée.
Le défaut est réapparu immédiatement. Bonne nouvelle : il ne venait ni de notre CSS, ni d'une interaction avec le reste de la page.
2. Isoler la variable
Nous avons ensuite fait varier une seule chose : la position de l'élément dans la fenêtre. Même élément, même filtre, même map — seule l'ordonnée change.
La déformation se déplaçait. Or si la map était correctement rattachée à l'élément, elle aurait dû le suivre sans bouger d'un pixel. Le problème n'était donc pas la map elle-même, mais l'espace de coordonnées dans lequel elle est résolue. Ce déplacement du problème — de « ma map est fausse » à « ma map est mal ancrée » — est ce qui a débloqué la suite.
3. Formuler une hypothèse vérifiable
Notre filtre était dimensionné en pourcentages, le réglage par défaut. L'hypothèse devenait donc : Chromium résout ces pourcentages dans un espace qui n'est pas celui de l'élément filtré.
Une hypothèse n'a d'intérêt que si elle prédit quelque chose de testable. Celle-ci prédisait qu'en
passant le filtre en coordonnées absolues — filterUnits="userSpaceOnUse", avec une image
posée à l'origine de l'élément — la bande cesserait de dériver. C'est exactement ce qui s'est produit.
L'espace utilisateur suit l'élément et ses transform ; les pourcentages, non.
4. Comprendre pourquoi personne n'en parle
Dernière étape, souvent sautée, et pourtant décisive : pourquoi un défaut aussi visible n'est-il documenté nulle part ? En réexaminant les démonstrations publiques, la réponse est apparue — elles montrent presque toutes un élément unique, centré, sur une page qui ne défile pas. Dans ces conditions, l'erreur d'ancrage est nulle ou constante. Elle ne devient visible qu'avec plusieurs éléments répartis dans une page réelle.
Savoir cela nous a évité de douter de notre propre code une deuxième fois.
Deux contournements, pour deux usages
Le diagnostic posé, une seule solution ne suffisait pas : les cartes et le curseur n'ont pas besoin de réfracter la même chose.
Les cartes et les boutons : la réfraction est calculée en WebGL
Le fond animé du site est déjà un canvas. Plutôt que de demander au navigateur de déformer le décor, nous dessinons nous-mêmes la déformation dedans. Un nuanceur parcourt les éléments en verre visibles, calcule pour chaque pixel sa distance au bord de la carte via une fonction de distance signée, et pousse l'échantillon d'autant plus fort qu'on approche du bord.
Les rectangles sont relus à chaque image, ce qui rend l'effet naturellement solidaire du défilement et des changements de mise en page. C'est aussi l'approche retenue par Aave.
Le curseur : là, il faut vraiment réfracter le DOM
Le curseur en verre doit déformer tout ce qu'il survole — le texte compris, qui n'est pas dans le canvas. Impossible de tricher : c'est le seul endroit où le filtre SVG reste indispensable. C'est donc là qu'on applique le contournement trouvé à l'étape 3, avec une nappe neutre sous la lentille pour que seule la zone de la goutte déforme quoi que ce soit.
Les deux pièges suivants
Un contournement validé n'est pas une fin : il ouvre en général la porte au problème d'après.
L'aberration chromatique qui désaligne toute l'image
Le verre réel décompose légèrement la lumière. On l'imite en déformant les canaux rouge, vert et bleu d'intensités différentes. Notre premier essai appliquait trois déformations à des échelles différentes — et les trois canaux se désalignaient sur toute la surface, pas seulement au bord. Le rendu virait au flou coloré.
La correction consiste à garder une échelle unique et à faire porter la différence par trois cartes d'amplitudes distinctes. La frange colorée reste alors confinée aux bords, là où le verre la produit vraiment.
Un canvas qui déborde de l'écran sans prévenir
Sur écran Retina, la réfraction se décalait à nouveau. En cause cette fois : un canvas est un élément remplacé. Sans dimensions explicites en CSS, il prend sa taille intrinsèque — multipliée par la densité de pixels — et déborde du viewport. Le décor rendu n'était plus aligné avec ce que voyait l'utilisateur.
Deux détails s'ajoutent : la taille doit être lue sur l'élément lui-même et non sur la fenêtre, qui inclut la barre de défilement ; et la densité de pixels doit être surveillée en continu, car elle change quand on déplace la fenêtre d'un écran à l'autre.
Mesurer avant d'arbitrer
Le filtre du curseur a un coût, et ce coût dépend directement de la surface sur laquelle le navigateur doit travailler. Nos relevés au banc de test ont été sans appel :
| Région du filtre | Images par seconde | Verdict |
|---|---|---|
| 185 × 185 px | ≈ 240 | Fluide, marge confortable |
| 300 × 300 px | ≈ 35 | Saccadé, inutilisable |
Un facteur sept pour une région à peine deux fois et demie plus grande. Sans cette mesure, le réglage aurait été choisi « à l'œil » sur une machine de développement puissante — et le site aurait ramé chez une partie des visiteurs. La région est donc maintenue serrée, et ce n'est pas négociable.
Ce que voit un visiteur qui ne veut pas de tout ça
Un effet visuel n'a pas à s'imposer. Trois replis sont en place : l'animation de fond est coupée si le système demande moins de mouvement, le verre devient une surface opaque si le système demande moins de transparence, et le curseur personnalisé n'apparaît que sur les appareils dotés d'un pointeur précis — il n'a aucun sens au doigt.
Ce que cette étude de cas dit de notre façon de travailler
L'effet de verre est anecdotique. La méthode, elle, est celle que nous appliquons à un bug de production, à une lenteur inexpliquée ou à une intégration récalcitrante :
- Reproduire au plus petit avant de chercher une cause. Un défaut qu'on ne sait pas reproduire, on ne sait pas non plus le corriger.
- Ne faire varier qu'une chose à la fois. C'est ce qui a déplacé le problème de la map vers son ancrage.
- Formuler des hypothèses qui prédisent un résultat, puis les tester. Sinon on ne débogue pas, on bricole.
- Mesurer avant d'arbitrer. L'intuition se trompe d'un facteur sept.
- Écrire le piège quelque part. Chacun de ceux décrits ici est consigné dans le dépôt, pour qu'aucun d'entre nous n'y retombe dans six mois.
Le détail purement technique — code, filtres, démonstrations interactives — est dans l'article associé : Liquid glass sur le web : une vraie réfraction (et le bug Chromium que personne ne documente).