4 points par GN⁺ 2024-11-25 | 1 commentaires | Partager sur WhatsApp
  • En partant des interfaces frosted acrylic de Forza Horizon 3 et Forza Motorsport 7, l’article résume le processus permettant de reproduire sur le web un effet similaire de panneau en verre avec HTML/CSS/JavaScript
  • Le cœur de l’effet est le flou gaussien ; il faut utiliser à la fois backdrop-filter en CSS et -webkit-backdrop-filter pour iOS afin de réduire les différences entre navigateurs
  • Comme un simple flou peut donner un rendu plat, on ajoute de la profondeur aux bords et du subsurface scattering avec box-shadow: inset, puis une ombre classique pour donner l’impression que le panneau flotte au-dessus de l’arrière-plan
  • Les reflets de surface sont implémentés en plaçant une image de rayons lumineux dans un calque séparé ; background-attachment: fixed ou JavaScript permettent de simuler des reflets dynamiques alignés avec le déplacement du verre
  • L’interface finale combine les calques .glass, .light et .drag-me, puis ajoute des coins arrondis, du clipping et une couleur d’arrière-plan semi-transparente pour obtenir un composant de verre copiable

Un effet de panneau en verre inspiré des interfaces de jeux

  • L’objectif est de reproduire en HTML le design frosted acrylic issu de l’expérience de développement des interfaces de Forza Horizon 3 et Forza Motorsport 7
  • Le résultat est un panneau de verre déplaçable, combinant flou d’arrière-plan, profondeur des bords, reflets lumineux, coins arrondis et calque de couleur semi-transparent
  • Une recette finale directement copiable est fournie au début, puis chaque effet est construit étape par étape

Créer le flou d’arrière-plan avec backdrop-filter

  • La clé d’un bon effet frosted glass est le flou gaussien, qui rend l’arrière-plan flou pour donner l’apparence d’un écran translucide
  • En CSS, il s’implémente en appliquant blur à backdrop-filter
  • L’élément de verre de base part d’un simple div avec une classe .glass
    • backdrop-filter: blur(10px)
    • -webkit-backdrop-filter: blur(10px)
  • Sur iOS, -webkit-backdrop-filter est nécessaire sauf à modifier en profondeur des réglages spécifiques
  • Comme backdrop-filter n’est pris en charge par les navigateurs que depuis peu, les utilisateurs d’Internet Explorer ne pourront pas voir la démo

Créer de la profondeur avec les bords et les ombres

  • Avec seulement backdrop-filter: blur(10px), le verre peut paraître plat et monotone
  • Les bords sont réalisés avec box-shadow: inset plutôt qu’avec border: 1px solid
    • border influe sur la taille de l’élément et le positionnement de ses enfants
    • Avec box-shadow: inset, les enfants peuvent remplir naturellement la zone de contenu du verre sans ajustements comme des marges négatives
  • Deux inset shadows blanches semi-transparentes servent à représenter les bords du verre
    • La première shadow représente l’arête du verre visible de l’extérieur ; dans l’exemple, elle apparaît sur les bords inférieur et gauche
    • La seconde shadow représente l’arête visible à travers le verre ; dans l’exemple, elle apparaît sur les bords supérieur et droit
  • Comme la lumière est atténuée lorsqu’elle traverse le verre, l’arête visible à travers celui-ci est réglée de façon plus douce et plus transparente
  • Ajouter une box-shadow sombre classique permet de donner l’impression que le verre flotte physiquement au-dessus de l’arrière-plan

Diffusion de la lumière et reflets de surface

  • L’impression de lumière qui se diffuse à l’intérieur du verre est une version simplifiée du subsurface scattering
  • L’implémentation utilise de nouveau box-shadow: inset
    • Effet de diffusion court : inset 0px 0px 10px 5px rgba(255, 255, 255, 0.025)
    • Effet de diffusion plus profond : inset 0px 0px 40px 5px rgba(255, 255, 255, 0.025)
  • Cet effet se voit mieux lorsqu’on fait glisser le verre au-dessus d’un arrière-plan sombre
  • En plus de l’impression de réfraction due au flou de l’arrière-plan, on ajoute aussi la propriété de réflexion de la lumière sur la surface du verre
  • Les reflets lumineux sont implémentés en mélangeant une image de rayons lumineux à l’arrière-plan
    • Il existe un tutoriel YouTube et une explication textuelle pouvant servir de référence pour créer une image similaire
    • Si l’image est placée directement dans background-image sur l’élément .glass, backdrop-filter la rend floue ; on utilise donc un calque séparé comme ::before

Transformer des reflets statiques en reflets dynamiques

  • Ajouter seulement l’image de rayons lumineux crée un reflet, mais lorsque le verre se déplace, la lumière peut sembler fixée à la surface du verre
  • La méthode en CSS pur consiste à ajouter background-attachment: fixed à ::before
    • L’implémentation est simple, mais peut ne pas fonctionner sur toutes les plateformes
  • Pour que cela fonctionne sur toutes les plateformes, JavaScript simule background-attachment: fixed
    • Manipuler directement ::before en JavaScript est inefficace ; on utilise donc un élément div.light séparé
    • L’attribut data-js-background-attachment-fixed est ajouté à l’élément cible
  • À chaque frame d’animation, JavaScript lit la valeur de getBoundingClientRect() pour l’élément cible, puis met à jour background-position dans la direction opposée à sa position dans le viewport
    • backgroundPositionX = -clientRect.x
    • backgroundPositionY = -clientRect.y
  • La boucle répétée s’exécute avec requestAnimationFrame

Structure HTML/CSS finale

  • Le HTML final de la version JavaScript place .light pour les reflets lumineux et .drag-me pour le calque texte/couleur à l’intérieur de .glass

  Drag Me

  • .glass gère la forme de base et les effets visuels du panneau de verre
    • Applique le flou d’arrière-plan avec backdrop-filter et -webkit-backdrop-filter
    • Applique les bords, l’ombre et les effets de diffusion avec plusieurs box-shadow
    • Utilise position: relative pour permettre aux calques enfants de remplir la zone du parent
    • Applique des coins arrondis avec border-radius: 5px
    • Découpe les éléments enfants avec overflow: hidden pour éviter qu’ils débordent hors des coins arrondis
  • .light utilise l’image de rayons lumineux comme arrière-plan répété
    • background-image: url(path/to/light.png)
    • background-repeat: repeat
    • background-size: 750px
    • opacity: 0.075
    • Remplit tout le parent avec position: absolute et des offsets 0 sur les quatre côtés
    • S’affiche derrière les autres enfants avec z-index: -1
  • .drag-me centre le contenu et crée un calque de verre semi-transparent coloré
    • display: flex
    • align-items: center
    • justify-content: center
    • height: 30px
    • background-color: rgba(12, 13, 14, 0.75)

Différences de la version sans JavaScript

  • La version sans JavaScript utilise .glass::before au lieu d’un élément .light séparé
  • Elle applique l’image de rayons lumineux à ::before et implémente un reflet fixé à l’écran avec background-attachment: fixed
  • Cette méthode ne fonctionne pas sur toutes les plateformes ; la version JavaScript la complète en mettant directement à jour background-position

1 commentaires

 
GN⁺ 2024-11-25
Avis sur Hacker News
  • Esthétiquement, j’aime vraiment beaucoup, mais il y a des aspects qui ne collent pas physiquement sur les bords.
    Du point de vue d’un développeur embarqué, ça me paraît un peu gaspilleur. On dirait que chaque client calcule à chaque fois un filtre de flou « coûteux » pour le mélanger avec une version floutée de l’image d’arrière-plan.
    Comme ça utilise le GPU et que c’est optimisé, le coût final n’est peut-être pas si élevé, mais le développement web actuel donne globalement l’impression de devenir beaucoup trop lourd. Même des sites simples mettent 5 secondes à charger et délèguent des traitements lourds au client ; bien sûr, ce n’est pas la faute de l’auteur de cet article.

    • Ce que l’on considère comme du gaspillage dépend sans doute des biais de chacun.
      Ayant grandi à l’époque des modems 14,4k, j’ai l’habitude de considérer que la bande passante réseau est bien plus rare et coûteuse que le temps CPU.
      Si l’on peut le calculer facilement côté client, je trouve plus gaspilleur de télécharger toute une image via Internet. Pour obtenir cette image, on fait travailler des routeurs, des serveurs et même des disques distants ; tout cela pour éviter un traitement sur des données déjà présentes dans la RAM du client, ça me semble encore plus dommage.
    • Même les sites web qui sont techniquement « gaspilleurs » sous certains aspects servent, dans la pratique, pour l’essentiel à du pur divertissement.
      Donc soit le divertissement lui-même est un gaspillage, soit, s’il ne l’est pas, utiliser davantage de calcul pour l’améliorer me paraît acceptable.
    • Du point de vue humain, cela ressemble à « recalculer lourdement des graphismes déjà rendus », donc à du gaspillage, mais techniquement ce n’est pas forcément le cas.
      Pour redessiner ce qui change dans une UI, il faut de toute façon du calcul GPU, et un flou simple peut s’ajouter assez efficacement. C’est probablement moins coûteux que d’animer des objets DOM non optimisés en calques GPU.
      Quand on voit que même les sites les plus simples chargent aujourd’hui plus de 1 Mo de JavaScript et une foule de traceurs qui consomment du CPU, un flou à but esthétique est très loin dans la liste des gaspillages.
    • Envoyer à la fois l’image floutée et l’image originale sur le réseau, n’est-ce pas justement ce que le développement web a fait pendant les 20 dernières années ?
      Avec beaucoup d’images haute résolution, la bande passante réseau réelle est limitée, et surtout sur mobile avec une mauvaise couverture sans fil, c’est clairement moins performant que du calcul local. Ce qu’on peut faire aujourd’hui uniquement avec CSS/WebGL est étonnant ; autrefois, ce genre d’effet demandait beaucoup de hacks et de contournements.
    • Il est temps de prendre au sérieux l’idée qu’une bonne partie des technologies du genre « oh, c’est joli, il nous le faut forcément » n’ont pas leur place dans ce monde.
      Indépendamment du fait que l’action elle-même soit du gaspillage ou non, cette façon de penser révèle un problème plus profond de la société. Pourquoi en a-t-on besoin, et pourquoi considère-t-on que l’absence de cela est mauvaise ?
      Vu l’ampleur des problèmes sociaux actuels, qui se soucie vraiment de savoir si un panneau d’UI est flouté ou non ?
  • En essayant de recréer l’effet Windows 7 Aero Glass sur Android pour voir ce qu’on pouvait faire avec la nouvelle API de shaders, j’ai extrait une texture de « rayons lumineux » similaire.
    Le résultat est devenu très proche de cet article, sauf que je n’ai pas ajouté d’ombre interne et que j’ai légèrement augmenté la saturation de l’arrière-plan flouté.
    https://mastodon.social/@grishka/110524476584503201

    • Très chouette. La texture de rayons lumineux peut vraiment jouer un grand rôle dans cet effet.
      Honnêtement, celle créée pour le tutoriel n’est pas si extraordinaire. J’aime les lignes plus nettes de la version Windows 7.
      J’ai aussi pensé à ajuster la saturation et je l’ai vu dans d’autres exemples, mais j’ai décidé de ne pas l’utiliser dans l’article. Comme l’image de lune utilisée n’avait pas beaucoup de couleurs, cela n’aurait probablement pas fait une grande différence. Ceux qui créent leur propre effet de verre devraient aussi expérimenter avec la saturation.
  • Le travail en lui-même est excellent, et la présentation sous forme de démo interactive est réussie. C’est amusant de faire glisser la fenêtre sur la lune.
    En revanche, je n’aime pas l’usage de l’effet verre dépoli dans la conception d’interfaces utilisateur, et quand il a été ajouté à Mac OS, je l’ai ressenti comme une régression. Les designers se laissent trop facilement séduire par cet effet, alors qu’en pratique il n’est jamais idéal, surtout lorsque le contenu derrière le panneau est dynamique ou généré par l’utilisateur.
    C’est un peu l’équivalent du métal brossé des années 2010, et il est surprenant qu’il se soit échappé de Windows Vista pour se répandre partout.

    • Je ne vois pas pourquoi ce ne serait « pas idéal ». En design visuel, les goûts personnels sur ce qui est beau comptent beaucoup plus que les objectifs pratiques.
      Bien sûr, le design affecte aussi la fonction, mais son objectif principal est de rendre l’expérience utilisateur plus agréable.
      Je trouve que le skeuomorphisme rend les interfaces plus agréables que la tendance minimaliste des dix dernières années et plus, qui a tout aplati. Les ornements visuels imitant les surfaces et matériaux du monde réel ajoutent de la familiarité et de l’accessibilité. Même d’un point de vue pratique, le flat design rend plus difficile la distinction entre les éléments et leurs états, alors qu’à l’époque des boutons 3D, du métal brossé et du verre dépoli, c’était beaucoup plus clair.
      Je pense que le pendule est en train de repartir dans l’autre sens. De plus en plus de designers évitent l’apparence plate, donc j’espère voir renaître des UI plus humaines.
    • Je ne suis pas designer UI, donc je pose la question sérieusement : le problème est-il l’usage même d’effets esthétiques comme le verre dépoli ou le métal brossé dans le design d’interface, ou bien le fait qu’en essayant de créer ce type d’interface, certains designers perdent les indices visuels qui indiquent l’emplacement et le rôle des contrôles ?
    • J’utilise depuis des années une légère transparence dans mes fenêtres de terminal, et maintenant ça me fait reconsidérer la question.
    • Le métal brossé n’affecte pas le contexte de l’information. Le flou fournit un contexte modulable.
      Le flou n’est généralement pas la bonne réponse, mais parfois c’est le bon choix.
    • Ironiquement, les anciennes versions de macOS utilisaient aussi beaucoup le métal brossé.
  • En 2008, avant que CSS ne prenne en charge backdrop-blur, j’avais déjà fait une expérimentation CSS pour obtenir un effet similaire : https://webdev.andersriggelsen.dk/aero/
    Le principe consistait à appliquer un effet de verre sur une image d’arrière-plan fixe et préalablement floutée : https://webdev.andersriggelsen.dk/aero/bgl.jpg
    C’est bien plus performant qu’un flou gaussien en temps réel, mais l’inconvénient reste le même : impossible d’autoriser des images d’arrière-plan dynamiques

    • Encore plus tôt, j’étais allé un cran plus loin en utilisant un fichier Flash comme arrière-plan
      Cela permettait d’obtenir un effet de verre même dans un cadre pouvant bouger dynamiquement. Je ne me souviens plus si j’utilisais une iframe, il faudrait que je retrouve le code, mais vu l’époque, il y a de fortes chances que oui
    • La fenêtre flottante ne se met pas à jour après sa position initiale
      Je suis sous Windows 10 19045.5131, avec Chrome à jour, Version 131.0.6778.86 (Official Build) (64-bit)
  • La prouesse technique est chouette, mais je trouve que c’est une mauvaise UX
    Le contenu dans des panneaux translucides est plus difficile à lire ou à comprendre que sur un fond uni et cohérent, avec un contraste plus faible et irrégulier par rapport à l’arrière-plan. En plus, si quelque chose bouge dessous, cela peut distraire et désorienter

    • Il est difficile de généraliser en disant qu’un simple effet visuel est une « mauvaise UX ». Tout dépend beaucoup de la façon dont il est intégré
      Une bonne intégration devrait ajuster l’intensité de l’effet pour ne pas surcharger l’UI, vérifier la prise en charge des fonctionnalités afin d’éviter d’ajouter des ornements quand le flou n’est pas disponible, et vérifier les capacités d’affichage et vidéo pour ne pas le rendre sur des appareils dont le GPU risque d’être insuffisant
      Il faut aussi tenir compte des préférences utilisateur pour proposer un aplat très contrasté aux personnes que les arrière-plans complexes gênent, limiter l’étendue de l’effet et des ombres selon l’espace disponible, et ajuster le flou et l’opacité en fonction de la complexité et du contraste de l’arrière-plan sous la zone floutée
      Il faut également s’assurer que le flou et les ombres s’adaptent de façon réactive à la typographie. L’UX consiste fondamentalement à concevoir la manière dont l’utilisateur vit son interaction avec l’application dans son ensemble ; elle ne se joue pas sur un choix de style isolé
    • Windows Vista réglait ce problème en ajoutant au texte noir sur verre dépoli un contour ressemblant à une ombre blanche
      Cela garantissait la lisibilité du texte même dans le cas extrême d’un arrière-plan noir. En CSS, on peut le reproduire avec la propriété text-shadow
    • C’est pour cela que je n’utilise pas cet effet sur tout mon site. Il rend plus difficile la création d’une bonne UX
      En revanche, il a davantage sa place dans les jeux. Il peut notamment convenir aux HUD, quand on ne veut pas masquer l’arrière-plan, qui est la zone principale avec laquelle l’utilisateur interagit
    • Si le problème est le manque de contraste, il suffit d’assombrir l’arrière-plan ou la teinte du verre et d’éclaircir le contenu au premier plan, ou l’inverse
      Obtenir un bon contraste est un défi pour n’importe quel élément de design, qu’il s’agisse d’un aplat ou d’un effet de verre
      L’idée que ce qui se passe en arrière-plan soit distrayant et désorientant est aussi très subjective. On peut réduire la translucidité du verre comme on réduit l’opacité d’un aplat
      Cette critique me paraît difficile à tenir comme objectivement vraie, et il existe des façons d’intégrer cet élément de design tout en évitant ces problèmes. La capture d’écran de Forza a l’air correcte, et en pratique l’arrière-plan ne m’a pas paru distrayant. En contrepartie, on obtient une UI plus intéressante et visuellement plus agréable qu’avec un fond uni. C’est peut-être plus important dans les jeux vidéo, mais cela peut aussi être utilisé avec élégance dans les OS et le design web
    • Le flou est une manière de masquer l’information tout en conservant le contexte à un degré réglable
      Si l’on a besoin de beaucoup de contexte, le flou est un mauvais choix ; si l’on n’a besoin d’aucun contexte, c’est aussi un mauvais choix
      Mais parfois, c’est un excellent choix
  • L’exemple interactif est bien, mais cela aurait été encore mieux avec un toggle permettant de comparer côte à côte avec l’étape précédente, ou de basculer entre les deux
    Dans la plupart des étapes, l’amélioration était trop subtile pour que l’on distingue vraiment la différence

    • D’accord. Sur mobile, à partir de la deuxième étape, la différence est à peine visible, voire pas visible du tout
  • Il y a une dizaine d’effets empilés ; à moins de viser une esthétique très exigeante, environ 7 d’entre eux sont de trop
    Une couleur de fond, du flou, et éventuellement une ombre ou une bordure suffisent

    • Ceux qui veulent un effet de verre moins lourd peuvent piocher dans le tutoriel
      Rien qu’à la troisième étape, avec seulement le flou et l’ombre, on obtient déjà un morceau de verre assez convaincant. Personnellement, je recommanderais d’y ajouter une image statique de reflets lumineux. Je ne pense pas que la plupart des applications aient besoin de l’effet JavaScript complet. C’est amusant, mais cela peut distraire
      Avec seulement le flou, l’ombre et les reflets lumineux, on peut déjà se rapprocher vraiment beaucoup de l’image Forza en haut
    • Il est intéressant que la plupart des commentaires les mieux classés parlent de gaspillage
      À mon avis, c’est l’une des raisons pour lesquelles tout le monde est passé au flat design. Windows Vista et les effets de verre étaient magnifiques, mais coûteux en calcul
      Le flat design est controversé sur le plan esthétique et peut être plus difficile à utiliser que le design skeuomorphique, surtout pour les utilisateurs plus âgés [0][1]
      Si le réalisme peut aider l’utilisabilité, alors employer ce genre d’effets sur le web me semble tout à fait justifié
      [0]: https://www.tandfonline.com/doi/abs/10.1080/0144929X.2020.18...
      [1]: https://www.sciencedirect.com/science/article/abs/pii/S01419...
    • Je me demande pourquoi la limite des effets empilés devrait être n <= 3
      Je ne sais pas s’il s’agit d’un problème d’accessibilité, de performance, de maintenabilité ou d’autre chose
      Comme CSS est de loin mon point le plus faible parmi les compétences de développement, je ne connais pas du tout les bonnes et mauvaises pratiques
    • Tu n’as pas raté le passage où l’auteur explique justement viser une esthétique très exigeante ?
  • C’est intéressant, on a vraiment l’impression d’avoir bouclé la boucle
    L’une des premières démos CSS, une démo pour CSS 1, était justement un effet de verre dépoli : https://meyerweb.com/eric/css/edge/complexspiral/glassy.html

  • Honnêtement, c’est assez impressionnant. C’est toujours un plaisir de voir à quel point CSS peut être créatif et puissant
    Cela dit, j’ai l’impression qu’il existe dans HTML/CSS un certain niveau que je ne comprendrai jamais. Cette démo en est le parfait exemple : cette personne est en train de créer une vitre givrée, alors que moi je n’arrive toujours pas à centrer un simple div

    • Quand j’apprenais comment fonctionnait le développement web, j’ai compris à la dure qu’ajouter un div de plus était souvent une bonne idée
      Quand on regarde la plupart des sites web modernes, on voit d’immenses piles de div. Si l’on veut un div centré, c’est relativement facile en créant à l’intérieur un autre div qui occupe tout l’espace dans lequel le centrer
      Beaucoup d’astuces visuelles reposent sur le même principe, mais cet exemple est très propre, ce qui le rend encore plus impressionnant
  • Ce n’est pas exactement du verre givré, mais j’ai essayé d’ajouter un effet de vitre dans la barre latérale de https://www.gyan.dev/ffmpeg/builds/

    • Sur PC, le site est très agréable et joli à regarder