Maison > interface Web > tutoriel CSS > Effet d'icône de verre en verre dans CSS

Effet d'icône de verre en verre dans CSS

Joseph Gordon-Levitt
Libérer: 2025-03-18 12:16:11
original
607 Les gens l'ont consulté

Effet d'icône en verre de verre dans CSS

Je suis récemment tombé sur un effet cool connu sous le nom de Glassmorphisme dans un coup de dribble. Ma première pensée a été que je pouvais rapidement le recréer en quelques minutes si j'utilise juste des emojis pour les icônes sans perdre de temps sur les SVG.

Je n'aurais pas pu se tromper plus à propos de ces «quelques minutes» - ils ont fini par être des jours de grattement furieusement et frustrant!

Il s'avère que, bien qu'il existe des ressources sur la façon de CSS un tel effet, ils supposent tous le cas très simple où la superposition est rectangulaire ou tout au plus un rectangle avec le radius frontalier. Cependant, obtenir un effet de mamorphisme en verre pour des formes irrégulières comme les icônes, que ces icônes soient des emojis ou des SVG appropriés, est beaucoup plus compliqué que ce à quoi je m'attendais, donc j'ai pensé que cela valait la peine de partager le processus, les pièges dans lesquels je suis tombé et les choses que j'ai apprises en cours de route. Et aussi les choses que je ne comprends toujours pas.

Pourquoi les emojis?

Réponse courte: parce que SVG prend trop de temps. Réponse longue: parce que je n'ai pas le sens artistique de simplement les dessiner dans un éditeur d'image, mais je connais suffisamment la syntaxe pour que je puisse souvent compacter les SVG prêts à l'emploi que je trouve en ligne à moins de 10% de leur taille d'origine. Donc, je ne peux pas simplement les utiliser comme je les trouve sur Internet - je dois refaire le code pour le rendre super propre et compact. Et cela prend du temps. Beaucoup de temps car c'est un travail détaillé.

Et si tout ce que je veux, c'est coder rapidement un concept de menu avec des icônes, je recourir à l'utilisation d'emojis, en appliquant un filtre sur eux afin de les faire correspondre au thème et c'est tout! C'est ce que j'ai fait pour cette démonstration d'interaction de bar à onglet liquide - ces icônes sont tous des emojis! L'effet lisse de la vallée utilise la technique de composition du masque.

Très bien, donc ce sera notre point de départ: utiliser des emojis pour les icônes.

L'idée initiale

Ma première pensée a été d'empiler les deux pseudos (avec le contenu des emoji) des liens de navigation, légèrement décalés et pivoter celui inférieur avec une transformation afin qu'ils ne se chevauchent que partiellement. Ensuite, je ferais le semi-transparent supérieur avec une valeur d'opacité inférieure à 1, mettant en fond le filtre: blur () dessus, et cela devrait être à peu près suffisant.

Maintenant, après avoir lu l'intro, vous avez probablement compris que cela ne s'est pas déroulé comme prévu, mais voyons à quoi il ressemble dans le code et quels problèmes il y a.

Nous générons la barre de navigation avec le carlin suivant:

 - Laissez les données = {
- Accueil: {ico: '?', Hue: 200}, 
- Remarques: {ICO: '? ️', Hue: 260}, 
- Activité: {ico: '?', Hue: 320}, 
- Discovery: {ico: '?', Hue: 30}
-};
- Soit e = object.entries (données);
- Soit n = e.Length;

navigation de navigation
  - pour (soit i = 0; i> n; i)
    a (href = '#' data-ico = e [i] [1] .ico style = `- hue: $ {e [i] [1] .hue} deg`) # {e [i] [0]}
Copier après la connexion

Qui se compile au HTML ci-dessous:

 <nav>
  <a href="'#'" data-ico="'?'" style="'-" hue:> Accueil </a>
  <a href="'#'" data-ico="'?" style="'-" hue:> notes </a>
  <a href="'#'" data-ico="'?'" style="'-" hue:> Activité </a>
  <a href="'#'" data-ico="'?'" style="'-" hue:> Iscovery </a>
 nav></nav>
Copier après la connexion

Nous commençons par la mise en page, faisant nos éléments des éléments de grille. Nous plaçons le Nav au milieu, donnons des liens explicites des largeurs, mettons les deux pseudos pour chaque lien dans la cellule supérieure (qui pousse le contenu du texte de liaison à la cellule inférieure) et alignent le texte et les pseudos de liaison.

 corps, nav, un {affichage: grille; }

corps {
  marge: 0;
  Hauteur: 100VH;
}

nav {
  grille-automne-flux: colonne;
  Place-Soi: Centre;
  rembourrage: .75em 0 .375em;
}

un {
  Largeur: 5EM;
  Texte-aligne: Centre;
  
  & :: avant, & :: après {
    Grid-Area: 1/1;
    Contenu: att (DATA-ICO);
  }
}
Copier après la connexion

Notez que l'apparence des emojis va être différente en fonction du navigateur que vous utilisez, affichez les démos.

Nous choisissons une police lisible, augmentons sa taille, faisons des icônes encore plus grandes, définissons des arrière-plans et une couleur plus agréable pour chacun des liens (basé sur la propriété personnalisée - Hue dans l'attribut de style de chacun):

 corps {
  / * Identique qu'avant * /
  Contexte: # 333;
}

nav {
  / * Identique qu'avant * /
  Contexte: #FFF;
  FONT: CLAMP (.625EM, 5VW, 1.25EM) / 1,25 Ubuntu, Sans-Serif;
}

un {
  / * Identique qu'avant * /
  Couleur: HSL (var (- teinte), 100%, 50%);
  Décoration du texte: aucune;
  
  & :: avant, & :: après {
    / * Identique qu'avant * /
    taille de police: 2.5EM;
  }
}
Copier après la connexion

Voici où les choses commencent à devenir intéressantes parce que nous commençons à se différencier entre les deux couches emoji créées avec les pseudos de liaison. Nous bougeons et tournons légèrement le :: avant pseudo, faisons le monochrome avec un filtre sépia (1), le faisons à la bonne teinte et augmentant son contraste () - une technique Oldie mais Goldie de Lea Verou. Nous appliquons également un filtre: niveaux de gris (1) sur le :: après pseudo et le rendre semi-transparent parce que, sinon, nous ne pourrions pas voir l'autre pseudo à travers.

 un {
  / * Identique qu'avant * /
  
  &::avant {
    transformer: 
      traduire (.375em, -.25em) 
      Rotation (22,5 degrés);
    filtre: 
      sépia (1) 
      Hue-rotate (calc (var (- hue) - 50deg))) 
      saturer (3);
  }
	
  &::après {
    Opacité: .5;
    Filtre: niveaux de gris (1);
  }
}
Copier après la connexion

Frapper un mur

Jusqu'à présent, c'est bon… alors quoi? L'étape suivante, que je pensais bêtement serait la dernière lorsque j'ai eu l'idée de coder cela, implique de définir un plateau de fond: Blur (5px) sur le dessus (:: After).

Notez que Firefox a toujours besoin du gfx.webrender.all et de la mise en page.css.backdrop-filter.Enabled Flags défini sur true dans About: Config afin que la propriété en arrière-plan-filtre fonctionne.

Malheureusement, le résultat ne ressemble en rien à ce à quoi je m'attendais. Nous obtenons une sorte de superposition de la taille de toute la boîte de délimitation de l'icône supérieure, mais l'icône inférieure n'est pas vraiment floue.

Cependant, je suis sûr d'avoir joué avec Backdrop-Filter: Blur () avant et cela a fonctionné, alors qu'est-ce que le diable poilu se passe ici?

Arriver à la racine du problème

Eh bien, lorsque vous n'avez aucune idée de la raison pour laquelle quelque chose ne fonctionne pas, tout ce que vous pouvez faire est de prendre un autre exemple de travail, commencez à l'adapter pour essayer d'obtenir le résultat que vous voulez… et voir où il se casse!

Voyons donc une version simplifiée de mon ancienne démo de travail. Le HTML n'est qu'un article dans une section. Dans le CSS, nous avons d'abord fixé quelques dimensions, puis nous définissons un arrière-plan d'image sur la section et un semi-transparent sur l'article. Enfin, nous avons défini la propriété en dossier de fond de l'article.

 Section {Contexte: URL (Cake.jpg) 50% / couverture; }

article {
  Marge: 25vmin;
  hauteur: 40VH;
  Contexte: HSLA (0, 0%, 97%, .25);
  Filtre de toile de fond: Blur (5px);
}
Copier après la connexion

Cela fonctionne, mais nous ne voulons pas que nos deux couches soient imbriquées les unes aux autres; Nous voulons qu'ils soient des frères et sœurs. Donc, faisons les deux frères et sœurs de l'article des deux couches, faisons-les partiellement se chevaucher et voyons si notre effet de verre en verre fonctionne toujours.

 <article class="'Base'">  Article>
<article class="'gris'">  Article></article></article>
Copier après la connexion
 Article {Largeur: 66%; hauteur: 40VH; }

.Base {Background: URL (Cake.jpg) 50% / couverture; }

.gris {
  marge: -50% 0 0 33%;
  Contexte: HSLA (0, 0%, 97%, .25);
  Filtre de toile de fond: Blur (5px);
}
Copier après la connexion

Tout semble toujours bien dans Chrome et, pour la plupart, Firefox aussi. C'est juste que la façon dont Blur () est manipulée sur les bords de Firefox semble maladroite et non ce que nous voulons. Et, sur la base des quelques images de la spécification, je crois que le résultat de Firefox est également incorrect?

Je suppose qu'une solution pour le problème de Firefox dans le cas où nos deux couches se trouvent sur un fond solide (blanc dans ce cas particulier) est de donner le calque inférieur (.base) un shadow sans compensation, sans flou et un rayon de propagation qui est deux fois le rayon flou que nous utilisons pour le filtre de dos appliqué sur la couche supérieure (. Effectivement, ce correctif semble fonctionner dans notre cas particulier.

Les choses deviennent beaucoup plus cheveux si nos deux couches sont assises sur un élément avec un fond d'image qui n'est pas fixe (dans ce cas, nous pourrions utiliser une approche d'arrière-plan en couches pour résoudre le problème de Firefox), mais ce n'est pas le cas ici, donc nous n'y entrerons pas.

Pourtant, passons à l'étape suivante. Nous ne voulons pas que nos deux couches soient deux boîtes carrées, nous voulons alors être des emojis, ce qui signifie que nous ne pouvons pas garantir la semi-transparence pour le haut en utilisant un arrière-plan HSLA () - nous devons utiliser l'opacité.

 .gris {
  / * Identique qu'avant * /
  Opacité: .25;
  Contexte: HSL (0, 0%, 97%);
}
Copier après la connexion

On dirait que nous avons trouvé le problème! Pour une raison quelconque, faire du semi-transparent de la couche supérieure à l'aide d'opacité rompt l'effet filtre de fond dans Chrome et Firefox. Est-ce un bug? Est-ce ce qui est censé arriver?

Bug ou pas?

MDN dit ce qui suit dans le tout premier paragraphe sur la page de dossier de fond:

Parce qu'il s'applique à tout ce qui derrière l'élément, pour voir l'effet, vous devez faire l'élément ou son arrière-plan au moins partiellement transparent.

À moins que je ne comprenne pas la phrase ci-dessus, cela semble suggérer que l'opacité ne devrait pas briser l'effet, même si c'est le cas dans Chrome et Firefox.

Et la spécification? Eh bien, la spécification est un énorme mur de texte sans beaucoup d'illustrations ou démos interactives, écrite dans une langue qui rend la lecture aussi attrayante que de renifler les glandes parfumes d'une moufette. Il contient cette partie, ce que j'ai un sentiment peut être pertinent, mais je ne suis pas sûr que je comprends ce qu'il essaie de dire - que l'opacité définie sur l'élément supérieur sur lequel nous avons également le filtre en toile de fond est également appliqué sur le frère ou la sœur en dessous? Si c'est le résultat prévu, cela ne se produit sûrement pas dans la pratique.

L'effet du filtre de fond ne sera visible que si une partie de l'élément B est semi-transparente. Notez également que toute opacité appliquée à l'élément B sera également appliquée à l'image de fond filtrée.

Essayer des choses aléatoires

Quelle que soit la spécification, le fait demeure: rendre le semi-transparent de la couche supérieure avec la propriété d'opacité casse l'effet de mamorphisme en verre dans Chrome et Firefox. Y a-t-il un autre moyen de faire un semi-transparent emoji? Eh bien, nous pourrions essayer Filtre: Opacity ()!

À ce stade, je devrais probablement signaler si cette alternative fonctionne ou non, mais la réalité est… Je n'en ai aucune idée! J'ai passé quelques jours autour de cette étape et j'ai pu vérifier le test d'innombrables fois en attendant - parfois cela fonctionne, parfois ce n'est pas exactement dans les mêmes navigateurs, avec des résultats différents en fonction de l'heure de la journée. J'ai également demandé sur Twitter et j'ai obtenu des réponses mitigées. Juste un de ces moments où vous ne pouvez pas vous empêcher de vous demander si un fantôme d'Halloween ne hante pas, ne fait pas peur et ne cache pas votre code. Pour l'éternité!

Il semble que tout espoir soit parti, mais essayons une seule chose: remplacer les rectangles par du texte, le haut étant semi-transparent par la couleur: hsla (). Nous pouvons ne pas être en mesure d'obtenir l'effet cool enterre de verre emoji que nous recherchions, mais nous pouvons peut-être obtenir un tel résultat pour du texte brut.

Nous ajoutons donc du contenu de texte à nos éléments d'article, supprimons leur dimensionnement explicite, augmentant leur taille de police, ajustez la marge qui nous donne un chevauchement partiel et, surtout, remplacez les déclarations d'arrière-plan dans la dernière version de travail avec des couleurs. Pour des raisons d'accessibilité, nous définissons également Aria-Hidden = 'True' sur le bas.

 <article class="'Base'" aria-hidden="'True'"> Lion?  Article>
<article class="'Gray'"> Lion? </article></article>
Copier après la connexion
 Article {Font: 900 21VW / 1 Cursif; }

.Base {Color: # ff7a18; }

.gris {
  marge: -.75em 0 0 .5em;
  Couleur: HSLA (0, 0%, 50%, .25);
  Filtre de toile de fond: Blur (5px);
}
Copier après la connexion

Il y a quelques choses à noter ici.

Tout d'abord, la définition de la propriété couleur sur une valeur avec un alpha sous-unitaire fait également des emojis semi-transparents, pas seulement du texte tout simplement , à la fois en chrome et dans Firefox! C'est quelque chose que je n'ai jamais connu auparavant et je trouve absolument époustouflant, étant donné que les autres canaux n'influencent en aucune façon les emojis.

Deuxièmement, Chrome et Firefox brouillent toute la zone du texte orange et des emoji qui se trouve sous la boîte de délimitation de la couche gris semi-transparent supérieure, au lieu de simplement brouiller ce qui se trouve sous le texte réel. Dans Firefox, les choses semblent encore pires en raison de cet effet de bord pointu maladroit.

Même si le flou de la boîte n'est pas ce que nous voulons, je ne peux m'empêcher de penser que cela a du sens car la spécification dit ce qui suit:

[…] Pour créer un élément «transparent» qui permet de voir l'image complète de toile de fond filtrée, vous pouvez utiliser «Background-Color: Transparent».

Passons donc à un test pour vérifier ce qui se passe lorsque la couche supérieure est une autre forme non rectangulaire qui n'est pas du texte, mais obtenu avec un gradient d'arrière-plan, un chemin à clip ou un masque!

Dans Chrome et Firefox, la zone sous la boîte entière de la couche supérieure est floue lorsque la forme est obtenue avec arrière-plan: Gradient () qui, comme mentionné dans le cas de texte précédent, est logique selon la spécification. Cependant, Chrome respecte les formes de chemin de clip et de masque, tandis que Firefox ne le fait pas. Et, dans ce cas, je ne sais vraiment pas ce qui est correct, bien que le résultat chrome ait plus de sens pour moi.

Se déplacer vers une solution chromée

Ce résultat et une suggestion de Twitter que j'ai obtenue lorsque j'ai demandé comment faire en sorte que le flou respecte les bords du texte et non ceux de sa boîte de délimitation m'a conduit à l'étape suivante pour Chrome: appliquer un masque coupé sur le texte sur la couche supérieure (.Grey). Cette solution ne fonctionne pas dans Firefox pour deux raisons: la première, le texte est malheureusement une valeur de masque non standard qui ne fonctionne que dans les navigateurs WebKit et, deux, comme le montre le test ci-dessus, le masquage ne limite pas la zone floue à la forme créée par le masque dans Firefox de toute façon.

 / * Identique qu'avant * /

.gris {
  / * Identique qu'avant * /
  -Webkit-mask: texte linéaire (rouge, rouge); / * fonctionne uniquement dans les navigateurs webkit * /
}
Copier après la connexion

D'accord, cela ressemble en fait à ce que nous voulons, donc nous pouvons dire que nous nous dirigeons dans la bonne direction! Cependant, ici, nous avons utilisé un emoji du cœur orange pour la couche inférieure et un emoji de cœur noir pour la couche semi-transparent supérieure. D'autres emojis génériques n'ont pas de versions en noir et blanc, donc ma prochaine idée était de rendre initialement les deux couches identiques, puis de faire le haut semi-transparent et d'utiliser le filtre: niveaux de gris (1) dessus.

 article { 
  Couleur: HSLA (25, 100%, 55%, VAR (- A, 1));
  Police: 900 21VW / 1,25 Cursive;
}

.gris {
  --a: .25;
  marge: -1em 0 0 .5em;
  Filtre: niveaux de gris (1);
  Filtre de toile de fond: Blur (5px);
  -Webkit-mask: texte linéaire (rouge, rouge);
}
Copier après la connexion

Eh bien, cela a certainement eu l'effet que nous voulions sur la couche supérieure. Malheureusement, pour une raison étrange, cela semble avoir également affecté la zone floue de la couche en dessous. Ce moment est où envisager brièvement de jeter l'ordinateur portable par la fenêtre… avant d'avoir l'idée d'ajouter une autre couche.

Cela irait comme ceci: nous avons le calque de base, tout comme nous l'avons jusqu'à présent, légèrement décalé des deux autres au-dessus. La couche intermédiaire est une «fantôme» (transparente) qui a le filtre de fond appliquée. Et enfin, le haut du haut est semi-transparent et obtient le filtre en niveaux de gris (1).

 corps {affichage: grille; }

article {
  Grid-Area: 1/1;
  Place-Soi: Centre;
  rembourrage: .25em;
  Couleur: HSLA (25, 100%, 55%, VAR (- A, 1));
  FONT: 900 21VW / 1.25 Pacifico, Z003, script Segoe, bande dessinée Sans MS, cursive;
}

.Base {margin: -.5em 0 0 -.5em; }

.midl {
  --a: 0;
  Filtre de toile de fond: Blur (5px);
  -Webkit-mask: texte linéaire (rouge, rouge);
}

.Grey {filtre: niveaux de gris (1) opacité (.25)}
Copier après la connexion

Maintenant, nous allons quelque part! Il reste encore une chose à faire: faire le monochrome de la couche de base!

 / * Identique qu'avant * /

.base {
  marge: -.5em 0 0 -.5em;
  Filtre: sépia (1) Hue-rotate (165deg) Contraste (1,5);
}
Copier après la connexion

D'accord, c'est l'effet que nous voulons!

Se rendre à une solution Firefox

Lors du codage de la solution chromée, je ne pouvais pas m'empêcher de penser que nous pourrons peut-être retirer le même résultat dans Firefox, car Firefox est le seul navigateur qui prend en charge la fonction élément (). Cette fonction nous permet de prendre un élément et de l'utiliser comme arrière-plan pour un autre élément.

L'idée est que les couches .Base et .Grey auront les mêmes styles que dans la version chromée, tandis que la couche intermédiaire aura un arrière-plan qui est (via la fonction élément ()) une version floue de nos couches.

Pour faciliter les choses, nous commençons avec juste cette version floue et la couche intermédiaire.

 <article id="'blur'" aria-hidden="'true'"> lion? 
<article class="'midl'"> lion? </article></article>
Copier après la connexion

Nous positionnons absolument la version floue (toujours en le gardant en vue pour l'instant), faisons-le monochrome et le brouillage, puis l'utilisons comme arrière-plan pour .midl.

 #se brouiller {
  Position: absolue;
  En haut: 2EM; à droite: 0;
  marge: -.5em 0 0 -.5em;
  Filtre: sépia (1) Hue-rotate (165deg) Contraste (1.5) Blur (5px);
}

.midl {
  --a: .5;
  Contexte: -moz-element (#blur);
}
Copier après la connexion

Nous avons également fait le texte sur l'élément .midl semi-transparent afin que nous puissions voir l'arrière-plan à travers. Nous le rendrons éventuellement entièrement transparents, mais pour l'instant, nous voulons toujours voir sa position par rapport à l'arrière-plan.

Nous pouvons remarquer un problème tout de suite: bien que la marge fonctionne pour compenser l'élément #blur réel, il ne fait rien pour déplacer sa position de fond. Afin d'obtenir un tel effet, nous devons utiliser la propriété Transform. Cela peut également nous aider si nous voulons une rotation ou toute autre transformée - comme on peut le voir ci-dessous où nous avons remplacé la marge par Transform: Rotate (-9deg).

Très bien, mais nous nous en tenons toujours à une traduction pour l'instant:

 #se brouiller {
  / * Identique qu'avant * /
  Transform: tradlater (-. 25EM, -.25EM); / * marge remplacée * /
}
Copier après la connexion

Une chose à noter ici est qu'un peu d'arrière-plan flou est coupé car il sort des limites de la boîte de rembourrage de la couche moyenne. Cela n'a pas d'importance à cette étape de toute façon, car notre prochain coup est de couper l'arrière-plan à la zone de texte, mais il est bon d'avoir cet espace car la couche .base va être traduite aussi loin.

Donc, nous allons augmenter un peu le rembourrage, même si, à ce stade, cela ne fait absolument aucune différence visuellement car nous définissons également le clip de fond: texte sur notre élément .midl.

 article {
  / * Identique qu'avant * /
  rembourrage: .5em;
}

#se brouiller {
  Position: absolue;
  En bas: 100VH;
  Transform: tradlater (-. 25EM, -.25EM);
  Filtre: sépia (1) Hue-rotate (165deg) Contraste (1.5) Blur (5px);
}

.midl {
  --a: .1;
  Contexte: -moz-element (#blur);
  Clip d'arrière-plan: texte;
}
Copier après la connexion

Nous avons également déplacé l'élément #blur hors de vue et réduit encore l'alpha de la couleur de l'élément .midl, car nous voulons une meilleure vue à l'arrière-plan à travers le texte. Nous ne le rendons pas entièrement transparents, mais le gardons toujours visible pour l'instant juste pour que nous sachions quelle zone il couvre.

L'étape suivante consiste à ajouter l'élément .Base avec à peu près les mêmes styles que dans le cas chrome, remplaçant uniquement la marge par une transformation.

 <article id="'blur'" aria-hidden="'true'"> lion? 
<article class="'Base'" aria-hidden="'True'"> Lion?  Article>
<article class="'midl'"> lion? </article></article></article>
Copier après la connexion
 #se brouiller {
  Position: absolue;
  En bas: 100VH;
  Transform: tradlater (-. 25EM, -.25EM);
  Filtre: sépia (1) Hue-rotate (165deg) Contraste (1.5) Blur (5px);
}

.base {
  Transform: tradlater (-. 25EM, -.25EM);
  Filtre: sépia (1) Hue-rotate (165deg) Contraste (1,5);
}
Copier après la connexion

Étant donné qu'une partie de ces styles est courante, nous pouvons également ajouter la classe .Base sur notre élément flou #Blur afin d'éviter la duplication et de réduire la quantité de code que nous écrivons.

 <article id="'blur'" class="'base'" aria-hidden="'true'"> lion?  article>
<article class="'Base'" aria-hidden="'True'"> Lion?  Article>
<article class="'midl'"> lion? </article></article></article>
Copier après la connexion
 #se brouiller {
  --R: 5px;
  Position: absolue;
  En bas: 100VH;
}

.base {
  Transform: tradlater (-. 25EM, -.25EM);
  Filtre: Sépia (1) Hue-rotate (165DEG) Contraste (1.5) Blur (var (- R, 0));
}
Copier après la connexion

Nous avons un problème différent ici. Étant donné que la couche .base a une transformation, elle est maintenant au-dessus de la couche .midl malgré l'ordre Dom. La correction la plus simple? Ajoutez Z-Index: 2 sur l'élément .midl!

Nous avons encore un autre problème, légèrement plus subtil: l'élément .Base est toujours visible sous les parties semi-transparentes de l'arrière-plan flou que nous avons mis sur l'élément .midl. Nous ne voulons pas voir les bords tranchants du texte de la couche.

Selon le type de contexte que nous avons sur le parent de nos couches de texte, c'est un problème qui peut être résolu avec un peu ou beaucoup d'efforts.

Si nous n'avons qu'un arrière-plan solide, le problème est résolu en définissant la couleur d'arrière-plan sur notre élément .midl sur cette même valeur. Heureusement, cela se trouve être notre cas, donc nous n'entrerons pas pour discuter de l'autre scénario. Peut-être dans un autre article.

 .midl {
  / * Identique qu'avant * /
  Contexte: -moz-element (#blur) #fff;
  Clip d'arrière-plan: texte;
}
Copier après la connexion

Nous nous approchons d'un bon résultat dans Firefox! Il ne reste plus qu'à ajouter la couche supérieure .grey avec les mêmes styles exactement que dans la version chromée!

 .Grey {filtre: GraysCale (1) Opacité (.25); }
Copier après la connexion

Malheureusement, cela ne produit pas le résultat que nous voulons, ce qui est vraiment évident si nous rendons également le texte de la couche moyenne entièrement transparent (en zéro son alpha --a: 0) afin que nous ne voyions que son arrière-plan (qui utilise l'élément flou #Blur sur le dessus du blanc solide) avec la zone texte:

Le problème est que nous ne pouvons pas voir la couche .Grey! En raison du réglage Z-Index: 2 dessus, la couche intermédiaire .midl est maintenant au-dessus de ce qui devrait être la couche supérieure (la .Grey one), malgré l'ordre Dom. Le correctif? Réglez Z-Index: 3 sur la couche .Grey!

 .gris {
  Z-Index: 3;
  Filtre: niveaux de gris (1) opacité (.25);
}
Copier après la connexion

Je n'aime pas vraiment donner une couche d'index z après la couche, mais bon, c'est un faible effort et ça marche! Nous avons maintenant une belle solution Firefox:

Combinant nos solutions dans un cross-browser

Nous commençons par le code Firefox car il y en a juste plus:

 <article id="'blur'" class="'base'" aria-hidden="'true'"> lion?  article>
<article class="'Base'" aria-hidden="'True'"> Lion?  Article>
<article class="'midl'" aria-hidden="'true'"> lion? 
<article class="'Gray'"> Lion? </article></article></article></article>
Copier après la connexion
 corps {affichage: grille; }

article {
  Grid-Area: 1/1;
  Place-Soi: Centre;
  rembourrage: .5em;
  Couleur: HSLA (25, 100%, 55%, VAR (- A, 1));
  Police: 900 21VW / 1,25 Cursive;
}

#se brouiller {
  --R: 5px;
  Position: absolue;
  En bas: 100VH;
}

.base {
  Transform: tradlater (-. 25EM, -.25EM);
  Filtre: Sépia (1) Hue-rotate (165DEG) Contraste (1.5) Blur (var (- R, 0));
}

.midl {
  --a: 0;
  Z-Index: 2;
  Contexte: -moz-element (#blur) #fff;
  Clip d'arrière-plan: texte;
}

.gris {
  Z-Index: 3;
  Filtre: niveaux de gris (1) opacité (.25);
}
Copier après la connexion

Les déclarations supplémentaires de l'indice Z n'ont pas d'impact sur le résultat en Chrome et l'élément #blur hors de la vue non plus. Les seules choses qui manquent pour que cela fonctionne dans Chrome est le filtre de fond et les déclarations de masque sur l'élément .midl:

 Filtre de toile de fond: Blur (5px);
-Webkit-mask: texte linéaire (rouge, rouge);
Copier après la connexion

Comme nous ne voulons pas que le filtre de fond soit appliqué dans Firefox, et nous ne voulons pas non plus que l'arrière-plan soit appliqué dans Chrome, nous utilisons @Supports:

 $ r: 5px;

/ * Identique qu'avant * /

#se brouiller {
  / * Identique qu'avant * /
  --r: # {$ r};
}

.midl {
  --a: 0;
  Z-Index: 2;
  / * besoin de réinitialiser à l'intérieur de @Supports afin qu'il ne soit pas appliqué dans Firefox * /
  Filtre de toile de fond: Blur ($ r);
  / * Valeur non valide dans Firefox, non appliquée de toute façon, pas besoin de réinitialiser * /
  -Webkit-mask: texte linéaire (rouge, rouge);
  
  @Supports (arrière-plan: -moz-element (#blur)) {/ * pour firefox * /
    Contexte: -moz-element (#blur) #fff;
    Clip d'arrière-plan: texte;
    Filtre de toile de fond: Aucun;
  }
}
Copier après la connexion

Cela nous donne une solution croisée!

Bien que le résultat ne soit pas le même dans les deux navigateurs, il est encore assez similaire et assez bon pour moi.

Qu'en est-il de l'élément unique de notre solution?

Malheureusement, c'est impossible.

Tout d'abord, la solution Firefox nous oblige à avoir au moins deux éléments car nous en utilisons un (référencé par son identifiant) en arrière-plan pour un autre.

Deuxièmement, alors que la première pensée avec les trois couches restantes (qui sont les seules dont nous avons besoin pour la solution chromée) est que l'un d'eux pourrait être l'élément réel et les deux autres ses pseudos, ce n'est pas si simple dans ce cas particulier.

Pour la solution chromée, chacune des couches a au moins une propriété qui a également un impact irréversible pour tous les enfants et tous les pseudos qu'il peut avoir. Pour les couches .Base et .Grey, c'est la propriété filtrante. Pour la couche intermédiaire, c'est la propriété Mask.

Donc, même si ce n'est pas joli d'avoir tous ces éléments, il semble que nous n'ayons pas une meilleure solution si nous voulons que l'effet en verre de verre fonctionne également sur les emojis.

Si nous ne voulons que l'effet de verre en verre sur le texte brut - pas d'emojis sur l'image - cela peut être réalisé avec seulement deux éléments, dont un seul est nécessaire pour la solution chromée. L'autre est l'élément #blur, dont nous avons besoin uniquement dans Firefox.

 <article id="'blur'"> sang 
<article class="'text'" aria-hidden="'true'" data-text="'Blood'">  Article></article></article>
Copier après la connexion

Nous utilisons les deux pseudos de l'élément .Text pour créer la couche de base (avec le :: avant) et une combinaison des deux autres couches (avec le :: après). Ce qui nous aide ici, c'est qu'avec des emojis hors de l'image, nous n'avons pas besoin de filtre: niveaux de gris (1), mais nous pouvons plutôt contrôler le composant de saturation de la valeur de couleur.

Ces deux pseudos sont empilés l'un sur l'autre, avec le décalage inférieur (:: avant) par la même quantité et ayant la même couleur que l'élément #Blur. Cette valeur de couleur dépend d'un drapeau, --f, qui nous aide à contrôler à la fois la saturation et l'alpha. Pour l'élément #blur et le :: avant pseudo (--f: 1), la saturation est à 100% et l'alpha est 1. Pour le :: après pseudo (--f: 0), la saturation est 0% et l'alpha est de 0,25.

 $ r: 5px;

% texte {// utilisé par #blur et les deux pseudos.
  --F: 1;
  Grid-Area: 1/1; // Stack Pseudos, ignoré pour #Base absolument positionné
  rembourrage: .5em;
  Couleur: HSLA (345, calc (var (- f) * 100%), 55%, calc (.25 .75 * var (- f)));
  Contenu: att (Texte de données);
}

Article {Font: 900 21VW / 1.25 Cursif}

#se brouiller {
  Position: absolue;
  En bas: 100VH;
  Filtre: Blur ($ r);
}

#blur, .text :: avant {
  Transform: tradlater (-. 125em, -.125em);
  @Extend% texte;
}

.texte {
  Affichage: grille;
	
  &::après {
    --F: 0;
    @Extend% texte;
    Z-Index: 2;
    Filtre de toile de fond: Blur ($ r);
    -Webkit-mask: texte linéaire (rouge, rouge);

    @Supports (arrière-plan: -moz-element (#blur)) {
      Contexte: -moz-element (#blur) #fff;
      Clip d'arrière-plan: texte;
      Filtre de toile de fond: Aucun;
    }
  }
}
Copier après la connexion

Appliquer la solution de croisement à notre cas d'utilisation

La bonne nouvelle ici est notre cas d'utilisation particulière où nous n'avons que l'effet de verre de verre sur l'icône de lien (pas sur l'ensemble du lien, y compris le texte) simplifie en fait un tout petit peu.

Nous utilisons le carlin suivant pour générer la structure:

 - Laissez les données = {
- Accueil: {ico: '?', Hue: 200}, 
- Remarques: {ICO: '? ️', Hue: 260}, 
- Activité: {ico: '?', Hue: 320}, 
- Discovery: {ico: '?', Hue: 30}
-};
- Soit e = object.entries (données);
- Soit n = e.Length;

navigation de navigation
  - pour (soit i = 0; i <n i soit ico="e" .ico a.item style="`--heue:" .hue deg span.icon.tint aria-hidden="'true')" span.icon.midl blur span.icon.grey><p> Qui produit une structure HTML comme celle ci-dessous:</p>
<pre rel="HTML" data-line=""> <nav>
  <a class="'item'" href="'#'" style="'-" hue:>
    <span class="'icon" tint id="'blur0'" aria-hidden="'true'">? </span>
    <span class="'icon" tint aria-hidden="'true'">? </span>
    <span class="'icon" midl aria-hidden="'true'" style="'background-iMage:" blur0>? </span>
    <span class="'icon" gris aria-hidden="'true'">? </span>
    maison
  </a>
  
 nav></nav>
Copier après la connexion

Nous pourrions probablement remplacer une partie de ces portées par des pseudos, mais je pense que c'est plus cohérent et plus facile comme ça, donc un sandwich à la portée est!

Une chose très importante à remarquer est que nous avons une couche d'icône floue différente pour chacun des éléments (parce que chaque élément a sa propre icône), nous avons donc établi l'arrière-plan de l'élément .midl dans l'attribut de style. Faire les choses de cette façon nous permet d'éviter d'apporter des modifications au fichier CSS si nous ajoutons ou supprimons les entrées de l'objet de données (modifiant ainsi le nombre d'éléments de menu).

Nous avons presque la même mise en page et les mêmes styles Pretified que nous avions lorsque nous avons pour la première fois CSS-Ed the Nav Bar. La seule différence est que maintenant nous n'avons plus de pseudos dans la cellule supérieure de la grille d'un article; Nous avons les portées:

 portée {
  Grid-Area: 1/1; / * empiler tous les emojis les uns sur les autres * /
  taille de police: 4EM; / * augmenter la taille des emoji * /
}
Copier après la connexion

Pour les couches d'icône emoji elles-mêmes, nous n'avons pas non plus besoin d'apporter de nombreux changements par rapport à la version cross-browser, nous avons obtenu un peu plus tôt, bien qu'il y en ait quelques-uns.

Tout d'abord, nous utilisons les chaînes de transformation et de filtre que nous avons choisies initialement lorsque nous utilisons les pseudos de liaison au lieu de Spans. Nous n'avons pas non plus besoin de la déclaration de couleur: hsla () sur les couches de span car, étant donné que nous n'avons que des emojis ici, ce n'est que le canal alpha qui compte. La valeur par défaut, qui est conservée pour les couches .Base et .Grey, est 1. Ainsi, au lieu de définir une valeur de couleur où seul le canal alpha, --a, et nous le modifions en 0 sur la couche .midl, nous définissons directement la couleur: transparente là-bas. Nous n'avons également qu'à définir la couleur d'arrière-plan sur l'élément .midl dans le boîtier Firefox car nous avons déjà défini l'image d'arrière-plan dans l'attribut de style. Cela conduit à l'adaptation suivante de la solution:

 .base {/ * Version emoji mono * /
  Transformée: traduire (.375em, -.25em) Rotation (22.5deg);
  filtre: sépia (1) hue rotate (var (- hue)) sature (3) blur (var (- r, 0));
}

.midl {/ * Middle, Transparent Emoji version * /
  Couleur: transparent; / * donc ce n'est pas visible * /
  Filtre de toile de fond: Blur (5px);
  -Webkit-mask: Texte linéaire-gradient (rouge 0 0);
  
  @Supports (arrière-plan: -moz-element (#b)) {
    Color d'arrière-plan: #FFF;
    Clip d'arrière-plan: texte;
    Filtre de toile de fond: Aucun;
  }
}
Copier après la connexion

Et c'est tout - nous avons un bel effet d'icône en verre pour cette barre de navigation!

Il y a juste une autre chose à prendre en charge - nous ne voulons pas cet effet à tout moment; Seulement sur: Hover ou: Focus States. Ainsi, nous allons utiliser un drapeau, --hl, qui est 0 à l'état normal, et 1 dans l'état de: Hover ou: focus afin de contrôler les valeurs d'opacité et de transformation des étendues .base. Ceci est une technique que j'ai détaillée dans un article précédent.

 $ t: .3s;

un {
  / * Identique qu'avant * /
  --hl: 0;
  Couleur: HSL (var (- Hue), calc (var (- hl) * 100%), 65%);
  Transition: couleur $ t;
  
  &: Hover, &: focus {--hl: 1; }
}

.base {
  transformer: 
    traduire (calc (var (- hl) *. 375em), calc (var (- hl) * -. 25em)) 
    Rotation (calc (var (- hl) * 22.5deg));
  Opacité: var (- hl);
  Transition: Transform $ T, Opacité $ T;
}
Copier après la connexion

Le résultat peut être vu dans la démo interactive ci-dessous lorsque les icônes sont survolées ou concentrées.

Qu'en est-il de l'utilisation d'icônes SVG?

Je me suis naturellement posé cette question après tout qu'il a fallu pour faire fonctionner la version Emoji CSS. La voie SVG simple n'aurait-elle pas plus de sens qu'un sandwich à l'étendue, et ne serait-il pas plus simple? Eh bien, bien que cela ait plus de sens, d'autant plus que nous n'avons pas d'emojis pour tout, ce n'est malheureusement pas moins de code et ce n'est pas plus simple non plus.

Mais nous allons entrer dans les détails à ce sujet dans un autre article!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal