Maison > interface Web > tutoriel CSS > Modes de mélange d'approvisionnement: «différence» et «exclusion»

Modes de mélange d'approvisionnement: «différence» et «exclusion»

尊渡假赌尊渡假赌尊渡假赌
Libérer: 2025-03-26 10:53:14
original
768 Les gens l'ont consulté

Modes de mélange d'approvisionnement: «différence» et «exclusion»

Jusqu'en 2020, les modes de mélange étaient une fonctionnalité que je n'avais pas utilisé beaucoup parce que j'avais rarement une idée du résultat qu'ils pouvaient produire sans leur essayer d'abord. Et adopter l'approche «Essayez-le et voyez ce qui se passe» semblait toujours me laisser horrifié par le vomi visuel que j'avais réussi à créer à l'écran.

Le problème provenait de ne pas vraiment savoir comment ils fonctionnent dans le dos. Presque chaque article que j'ai vu sur le sujet est basé sur des exemples, des comparaisons avec Photoshop ou des descriptions artistiques verbales. Je trouve des exemples formidables, mais lorsque vous n'avez aucune idée de la façon dont les choses fonctionnent dans le dos, adapter une belle démo dans quelque chose qui mettrait en œuvre une idée différente que vous avez dans votre tête devient une aventure vraiment longue, frustrante et finalement futile. Ensuite, les comparaisons de Photoshop sont à peu près inutiles pour une personne issue d'un milieu technique. Et les descriptions artistiques verbales me ressemblent à la langue pingouin.

J'ai donc eu un moment d'ampoule lorsque je suis tombé sur la spécification et que cela comprend également des formules mathématiques selon les modes de mélange. Cela signifiait que je pouvais enfin comprendre comment ces trucs fonctionnent à l'arrière et où cela peut être vraiment utile. Et maintenant que je sais mieux, je partagerai ces connaissances dans une série d'articles.

Aujourd'hui, nous nous concentrerons sur le fonctionnement généralement du mélange, puis examinerons de plus près deux modes de mélange quelque peu similaires - la différence et l'exclusion - et, enfin, arriver à la viande de cet article où nous disséquerons des cas d'utilisation sympas comme ceux ci-dessous.

Discutons du «comment» des modes de mélange

Mélanger signifie combiner deux couches (qui sont empilées l'une sur l'autre) et obtenir une seule couche. Ces deux couches pourraient être deux frères et sœurs, auquel cas la propriété CSS que nous utilisons est en mode mélange de mélange. Ils pourraient également être deux couches d'arrière-plan, auquel cas la propriété CSS que nous utilisons est en mode mélange d'arrière-plan. Notez que lorsque je parle de mélange des «frères et sœurs», cela inclut le mélange d'un élément avec les pseudo-éléments ou avec le contenu texte ou l'arrière-plan de son parent. Et en ce qui concerne les couches d'arrière-plan, ce n'est pas seulement les couches d'image d'arrière-plan dont je parle - la couleur d'arrière-plan est également une couche.

Lors du mélange de deux couches, le calque sur le dessus est appelé la source , tandis que la couche en dessous est appelée destination . C'est quelque chose que je prends juste comme c'est parce que ces noms n'ont pas beaucoup de sens, du moins pour moi. Je m'attendais à ce que la destination soit une sortie, mais à la place, ils sont à la fois des entrées et la couche résultante est la sortie.

La façon dont nous combinons exactement les deux couches dépend du mode de mélange particulier utilisé, mais il est toujours par pixel. Par exemple, l'illustration ci-dessous utilise le mode de mélange multiple pour combiner les deux couches, représentées comme des grilles de pixels.

D'accord, mais que se passe-t-il si nous avons plus de deux couches? Eh bien, dans ce cas, le processus de mélange se produit par étapes, à partir du bas.

Dans une première étape, la deuxième couche du bas est notre source, et la première couche du bas est notre destination. Ces deux couches se mélangent et le résultat devient la destination de la deuxième étape, où la troisième couche du bas est la source. Le mélange de la troisième couche avec le résultat du mélange les deux premiers nous donne la destination de la troisième étape, où la quatrième couche du bas est la source.

Bien sûr, nous pouvons utiliser un mode de mélange différent à chaque étape. Par exemple, nous pouvons utiliser la différence pour mélanger les deux premières couches en bas, puis utiliser Multiply pour mélanger le résultat avec la troisième couche en bas. Mais c'est quelque chose que nous allons un peu plus dans les futurs articles.

Le résultat produit par les deux modes de mélange dont nous discutons ici ne dépend pas de lequel des deux couches est en haut. Notez que ce n'est pas le cas pour tous les modes de mélange possibles, mais c'est le cas pour ceux que nous envisageons dans cet article.

Ce sont également des modes de mélange séparables, ce qui signifie que l'opération de mélange est effectuée séparément sur chaque canal. Encore une fois, ce n'est pas le cas pour tous les modes de mélange possibles, mais c'est le cas de la différence et de l'exclusion.

Plus exactement, le canal rouge résultant ne dépend que du canal rouge de la source et du canal rouge de la destination; Le canal vert résultant ne dépend que du canal vert de la source et du canal vert de la destination; Et enfin, le canal bleu résultant ne dépend que du canal bleu de la source et du canal bleu de la destination.

 R = f <sub>b</sub> (r <sub>s</sub> , r <sub>d</sub> )
G = f <sub>b</sub> (g <sub>s</sub> , g <sub>d</sub> )
B = f <sub>b</sub> (b <sub>s</sub> , b <sub>d</sub> )
Copier après la connexion

Pour un canal générique, sans spécifier s'il est rouge, vert ou bleu, nous avons qu'il est fonction des deux canaux correspondants dans la couche source (supérieure) et dans la couche de destination (en bas):

 Ch = f <sub>b</sub> (ch <sub>s</sub> , ch <sub>d</sub> )
Copier après la connexion

Quelque chose à garder à l'esprit est que les valeurs de RVB peuvent être représentées soit dans l'intervalle [0, 255], soit en pourcentages dans l'intervalle [0%, 100%], et ce que nous utilisons réellement dans nos formules est le pourcentage exprimé en valeur décimale. Par exemple, Crimson peut être écrit en RVB (220, 20, 60) ou en RVB (86,3%, 7,8%, 23,5%) - les deux sont valides. Les valeurs de canal que nous utilisons pour les calculs si un pixel est cramoisi est les pourcentages exprimés en valeurs décimales, soit 0,863, .078, .235.

Si un pixel est noir, les valeurs de canal que nous utilisons pour les calculs sont toutes 0, car le noir peut être écrit en RVB (0, 0, 0) ou en RVB (0%, 0%, 0%). Si un pixel est blanc, les valeurs de canal que nous utilisons pour les calculs sont toutes 1, car les blancs peuvent être écrits en RVB (255, 255, 255) ou en RVB (100%, 100%, 100%).

Notez que partout où nous avons une transparence complète (un alpha égal à 0), le résultat est identique à l'autre couche.

différence

Le nom de ce mode de mélange pourrait fournir un indice sur ce que fait la fonction de mélange f b (). Le résultat est la valeur absolue de la différence entre les valeurs de canal correspondantes pour les deux couches.

 Ch = f <sub>b</sub> (ch <sub>s</sub> , ch <sub>d</sub> ) = | ch s - ch d |
Copier après la connexion

Tout d'abord, cela signifie que si les pixels correspondants dans les deux couches ont des valeurs RVB identiques (c'est-à-dire CH S = CH D pour chacun des trois canaux), le pixel de la couche résultante est noir car les différences pour les trois canaux sont 0.

 Ch <sub>s</sub> = ch <sub>d</sub>
Ch = f <sub>b</sub> (ch <sub>s</sub> , ch <sub>d</sub> ) = | ch <sub>s</sub> - ch <sub>d</sub> | = 0
Copier après la connexion

Deuxièmement, comme la valeur absolue de la différence entre tout nombre positif et 0 laisse ce nombre inchangé, il se traduit par le pixel de résultat correspondant ayant la même valeur RGB que le pixel de l'autre couche si le pixel d'une couche est noir (tous les canaux égaux 0).

Si le pixel noir est dans la couche supérieure (source), remplacer ses valeurs de canal par 0 dans notre formule nous donne:

 Ch = f <sub>b</sub> (0, ch <sub>d</sub> ) = | 0 - ch <sub>d</sub> | = | -Ch <sub>d</sub> | = Ch <sub>d</sub>
Copier après la connexion

Si le pixel noir est dans la couche inférieure (destination), le remplacement de ses valeurs de canal par 0 dans notre formule nous donne:

 Ch = f <sub>b</sub> (ch <sub>s</sub> , 0) = | ch <sub>s</sub> - 0 | = | Ch <sub>S</sub> | = Ch <sub>s</sub>
Copier après la connexion

Enfin, comme la valeur absolue de la différence entre tout nombre sous-unitaire positif et 1 nous donne le complément de ce nombre, il résulte que si le pixel d'une couche est blanc (a tous les canaux 1), le pixel de résultat correspondant est le pixel de l'autre couche entièrement inversé (quel filtre: invert (1) le ferait).

Si le pixel blanc est dans la couche supérieure (source), remplacer ses valeurs de canal par 1 dans notre formule nous donne:

 Ch = f <sub>b</sub> (1, ch <sub>d</sub> ) = | 1 - ch <sub>d</sub> | = 1 - ch <sub>d</sub>
Copier après la connexion

Si le pixel blanc est dans la couche inférieure (destination), remplacer ses valeurs de canal par 1 dans notre formule nous donne:

 Ch = f <sub>b</sub> (ch <sub>s</sub> , 1) = | ch <sub>s</sub> - 1 | = 1 - ch <sub>s</sub>
Copier après la connexion

Cela peut être vu en action dans le stylo interactif ci-dessous, où vous pouvez basculer entre la visualisation des couches séparées et les visualiser se chevauchant et mélangées. Faire planer les trois colonnes dans le cas qui se chevauchent révèle également ce qui se passe pour chacun.

exclusion

Pour le deuxième et dernier mode de mélange que nous envisageons aujourd'hui, le résultat est le double du produit des deux valeurs de canal, soustrait de leur somme:

 Ch = f <sub>b</sub> (ch <sub>s</sub> , ch <sub>d</sub> ) = ch s ch d - 2 · ch s · ch d
Copier après la connexion

Étant donné que les deux valeurs sont dans l'intervalle [0, 1], leur produit est toujours au plus égal à la plus petite d'entre eux, donc le double du produit est toujours au plus égal à leur somme.

Si nous considérons un pixel noir dans la couche supérieure (source), puis remplacez CH S par 0 dans la formule ci-dessus, nous obtenons le résultat suivant pour les canaux du Pixel de résultat correspondant:

 Ch = f <sub>b</sub> (0, ch <sub>d</sub> ) = 0 ch <sub>d</sub> - 2 · 0 · ch <sub>d</sub> = ch <sub>d</sub> - 0 = ch <sub>d</sub>
Copier après la connexion

Si nous considérons un pixel noir dans la couche inférieure (destination), puis remplacez Ch D par 0 dans la formule ci-dessus, nous obtenons le résultat suivant pour les canaux du Pixel de résultat correspondant:

 Ch = f <sub>b</sub> (ch <sub>s</sub> , 0) = ch <sub>s</sub> 0 - 2 · ch <sub>s</sub> · 0 = ch <sub>s</sub> - 0 = ch <sub>s</sub>
Copier après la connexion

Donc, si le pixel d'une couche est noir, il résulte que le pixel de résultat correspondant est identique au pixel de l'autre couche.

Si nous considérons un pixel blanc dans la couche supérieure (source), puis remplacez CH S par 1 dans la formule ci-dessus, nous obtenons le résultat suivant pour les canaux du Pixel de résultat correspondant:

 Ch = f <sub>b</sub> (1, ch <sub>d</sub> ) = 1 ch <sub>d</sub> - 2 · 1 · ch <sub>d</sub> = 1 ch <sub>d</sub> - 2 · ch <sub>d</sub> = 1 - ch <sub>d</sub>
Copier après la connexion

Si nous considérons un pixel blanc dans la couche inférieure (destination), puis remplacez Ch D par 1 dans la formule ci-dessus, nous obtenons le résultat suivant pour les canaux du Pixel de résultat correspondant:

 Ch = f <sub>b</sub> (ch <sub>s</sub> , 1) = ch <sub>s</sub> 1 - 2 · ch <sub>s</sub> · 1 = ch <sub>s</sub> 1 - 2 · ch <sub>s</sub> = 1 - ch <sub>s</sub>
Copier après la connexion

Donc, si le pixel d'une couche est blanc, il résulte que le pixel de résultat correspondant est identique au pixel de l'autre couche inversé.

Tout cela est indiqué dans la démo interactive suivante:

Notez que tant qu'au moins une des couches n'a que des pixels en noir et blanc, la différence et l'exclusion produisent exactement le même résultat.

Maintenant, tournons-nous vers le «quoi» des modes de mélange

Voici la partie intéressante - les exemples!

Effet de modification de l'état du texte

Disons que nous avons un paragraphe avec un lien:

 <p> Bonjour, <a href="'#'"> monde </a>! </p>
Copier après la connexion

Nous commençons par définir quelques styles de base pour mettre notre texte au milieu de l'écran, augmenter sa taille de police, définir un arrière-plan sur le corps et une couleur sur le paragraphe et le lien.

 corps {
  Affichage: grille;
  Content de lieu: Centre;
  Hauteur: 100VH;
  Contexte: # 222;
  Couleur: #ddd;
  taille de police: pince (1.25em, 15vw, 7EM);
}

Une couleur: or; }
Copier après la connexion

Cela ne ressemble pas beaucoup jusqu'à présent, mais nous allons bientôt changer cela!

L'étape suivante consiste à créer un pseudo-élément absolument positionné qui couvre l'intégralité du lien et a son arrière-plan sur CurrentColor.

 un {
  Position: relative;
  couleur: or;
  
  &::après {
    Position: absolue;
    en haut: 0;
    en bas: 0;
    à droite: 0;
    à gauche: 0;
    Contexte: CurrentColor;
    contenu: '';
  }
}
Copier après la connexion

Ce qui précède semble que nous avons gâché les choses… mais avons-nous vraiment? Ce que nous avons ici est un rectangle d'or au-dessus du texte en or. Et si vous avez prêté attention à la façon dont les deux modes de mélange discutés ci-dessus fonctionnent, alors vous avez probablement déjà deviné la prochaine - nous mélangeons les deux nœuds de frères et sœurs dans le lien (le rectangle pseudo-élémentaire et le contenu texte) en utilisant la différence, et puisqu'ils sont tous les deux or, il en résulte que ce qu'ils ont en commun - le texte - devient noir.

 p {isolement: isolat; }

un {
  / * Identique qu'avant * /
  
  &::après {
    / * Identique qu'avant * /
    Mode de mélange de mélange: différence;
  }
}
Copier après la connexion

Notez que nous devons isoler le paragraphe pour empêcher le mélange avec le fond du corps. Bien que ce ne soit qu'un problème dans Firefox (et étant donné que nous avons un fond très sombre sur le corps, ce n'est pas trop visible) et c'est bien dans Chrome, gardez à l'esprit que, selon la spécification, ce que Firefox fait est réellement correct. C'est Chrome qui se comporte de manière buggy ici, donc nous devrions avoir la propriété d'isolement définie au cas où le bug serait corrigé.

D'accord, mais nous voulons que cela se produise uniquement si le lien est concentré ou plané. Sinon, le pseudo-élément n'est pas visible - disons qu'il n'a rien fait à rien.

 un {
  / * Identique qu'avant * /
  Décoration du texte: aucune;
  
  &::après {
    / * Identique qu'avant * /
    transformée: échelle (0);
  }

  &: focus {contour: aucun}
  &: focus, &: hover {& :: after {transform: aucun; }}
}
Copier après la connexion

Nous avons également supprimé la soulignement du lien et le plan de mise au point. Ci-dessous, vous pouvez maintenant voir l'effet de différence sur: Hover (le même effet se produit sur: Focus, ce que vous pouvez tester dans la démo en direct).

Nous avons maintenant notre changement d'état, mais il a l'air rude, alors ajoutons une transition!

 un {
  / * Identique qu'avant * /
  
  &::après {
    / * Identique qu'avant * /
    transition: transformer .25S;
  }
}
Copier après la connexion

Beaucoup mieux!

Cela semblerait encore mieux si notre pseudo provenait de rien au milieu, mais d'une fine ligne en bas. Cela signifie que nous devons régler l'origine transformateur sur le bord inférieur (à 100% verticalement et quelle que soit la valeur horizontalement) et initialement évoluer notre pseudo à quelque chose de légèrement plus que rien le long de l'axe Y.

 un {
  / * Identique qu'avant * /
  
  &::après {
    / * Identique qu'avant * /
    Transform-Origin: 0 100%;
    Transformée: Scaley (.05);
  }
}
Copier après la connexion

Quelque chose d'autre que j'aimerais faire ici est de remplacer la police du paragraphe par un paragraphe plus esthétiquement attrayant, alors prenons soin de cela aussi! Mais nous avons maintenant un type de problème différent: la fin du «D» sort du rectangle sur: focus /: enrobé.

Nous pouvons résoudre ce problème avec un rembourrage horizontal sur notre lien.

 un {
  / * Identique qu'avant * /
  rembourrage: 0 .25em;
}
Copier après la connexion

Au cas où vous vous demandez pourquoi nous définissons ce rembourrage sur le côté droit et gauche au lieu de simplement définir un rembourrage droit, la raison est illustrée ci-dessous. Lorsque notre texte de lien devient «monde extraterrestre», le début bouclé du «A» finirait en dehors de notre rectangle si nous n'avions pas de padding-gauche.

Cette démo avec un lien multi-mots ci-dessus met également en évidence un autre problème lorsque nous réduisons la largeur de la fenêtre.

Une solution rapide ici serait de définir l'affichage: bloc en ligne sur le lien. Ce n'est pas une solution parfaite. Il se casse également lorsque le texte du lien est plus long que la largeur de la fenêtre, mais il fonctionne dans ce cas particulier, alors laissons-le ici maintenant et nous reviendrons à ce problème dans un petit moment.

Voyons maintenant la situation d'un thème léger. Puisqu'il n'y a aucun moyen de devenir blanc au lieu du noir pour le texte de lien sur: Hover ou: Focus en mélangeant deux couches de surbrillance identiques qui ne sont pas blanches, nous avons besoin d'un peu d'une approche différente ici, qui n'implique pas d'utiliser uniquement des modes de mélange.

Ce que nous faisons dans ce cas, c'est d'abord définir l'arrière-plan, la couleur du texte du paragraphe normal et la couleur du texte du lien aux valeurs que nous voulons, mais inversées . Je faisais initialement cette inversion manuellement, mais j'ai ensuite eu la suggestion d'utiliser la fonction Sass Invert (), ce qui est une idée très cool qui simplifie vraiment les choses. Ensuite, après avoir ce thème sombre qui est essentiellement le thème léger que nous voulons inverser, nous obtenons notre résultat souhaité en inversant à nouveau à l'aide de la fonction de filtre CSS Invert ().

Minuscule mise en garde ici: nous ne pouvons pas définir le filtre: invertiver (1) sur le corps ou les éléments HTML parce que cela ne se comportera pas comme nous l'attendons et nous n'aurons pas le résultat souhaité. Mais nous pouvons définir à la fois l'arrière-plan et le filtre sur un emballage autour de notre paragraphe.

 <segction>
  <p> Bonjour, <a href="'#'"> Alien World </a>! </p>
 section></segction>
Copier après la connexion
 corps {
  / * Identique qu'avant, 
     Sans les déclarations de lieux, d'arrière-plan et de couleurs, 
     que nous évoluons sur la section * /
}

section {
  Affichage: grille;
  Content de lieu: Centre;
  Contexte: invert (#ddd) / * sass invert (<mor>) function * /;
  Couleur: Invert (# 222); / * Sass Invert <omlowing>) Fonction * /;
  Filtre: Invert (1); / * Fonction CSS Filtre Invert (<nombre pourcentage>) * /
}

un {
  / * Identique qu'avant * /
  Couleur: Invert (violet); / * Sass Invert (<omlower>) Fonction * /
}</omlower></nombre></omlowing></mor>
Copier après la connexion

Voici un exemple de barre de navigation utilisant cet effet (et un tas d'autres astuces intelligentes, mais celles-ci sont en dehors de la portée de cet article). Sélectionnez une autre option pour le voir en action:

Quelque chose d'autre avec lequel nous devons faire attention est le suivant: Tous les descendants de notre section sont inversés lorsque nous utilisons cette technique. Et ce n'est probablement pas ce que nous voulons dans le cas des éléments IMG - je ne m'attends certainement pas à voir les images dans un article de blog inversé lorsque je passe de l'obscurité au thème clair. Par conséquent, nous devons inverser l'inversion du filtre sur chaque descendant IMG de notre section.

 section {
  / * Identique qu'avant * /
  
  &, & img {filtre: invert (1); }
}
Copier après la connexion

Le tout ensemble, la démo ci-dessous montre à la fois les cas de thème sombre et léger avec des images:

Revenons maintenant au problème du texte du lien d'emballage et voyons si nous n'avons pas de meilleures options que de faire des éléments en ligne en ligne.

Eh bien, nous le faisons! Nous pouvons mélanger deux couches d'arrière-plan au lieu de mélanger le contenu du texte et un pseud. Une couche est coupée au texte, tandis que l'autre est coupée à la boîte de bordure et sa taille verticale anime entre 5% initialement et 100% dans les cas planés et focalisés.

 un {
  / * Identique qu'avant * /
  -Webkit-Text-Fill-Color: transparent;
     -moz-text-fill-couleur: transparent;
  --Full: Linear-Gradient (CurrentColor, CurrentColor);
  arrière-plan: 
    var (- complet), 
    var (- complet) 0 100% / 1% var (- sy, 5%) répéter-x;
  -Webkit-Background-Clip: Texte, Border-Box;
          Clip d'arrière-plan: texte, border-box;
  Mode de mélange d'arrière-plan: différence;
  Transition: .25 de la taille de l'arrière-plan;
	
  &: focus, &: hover {--sy: 100%; }
}
Copier après la connexion

Notez que nous n'avons même plus de pseudo-élément, nous avons donc pris une partie du CSS dessus, l'avons déplacé sur le lien lui-même et l'avons modifié en fonction de cette nouvelle technique. Nous sommes passés de l'utilisation du mode mélange de mélange à l'utilisation du mode de mélange d'arrière-plan; Nous transitionnons maintenant la taille de l'arrière-plan de la transformation et, dans les états: Focus et: Hover; Et nous changeons maintenant non pas la transformation, mais une propriété personnalisée représentant la composante verticale de la taille de l'arrière-plan.

Beaucoup mieux, bien que ce ne soit pas non plus une solution parfaite.

Le premier problème est celui que vous avez sûrement remarqué si vous avez vérifié le lien de démonstration en direct de la légende dans Firefox: cela ne fonctionne pas du tout. Cela est dû à un bug de Firefox que j'ai apparemment signalé en 2018, puis j'ai tout oublié jusqu'à ce que je commence à jouer avec des modes de mélange et que je le frappe à nouveau.

Le deuxième problème est celui qui est perceptible dans l'enregistrement. Les liens semblent quelque peu fanés. En effet, pour une raison quelconque, Chrome mélange des éléments en ligne comme des liens (notez que cela ne se produira pas avec des éléments de bloc comme les divs) avec l'arrière-plan de leur ancêtre le plus proche (la section dans ce cas) si ces éléments en ligne ont un mode mélange de fond réglé sur autre chose que normal.

Encore plus étrangement, définir l'isolement: Isoler sur le lien ou son paragraphe parent n'empêche pas cela de se produire. J'avais toujours un sentiment harcelant que cela devait avoir quelque chose à voir avec le contexte, alors j'ai décidé de continuer à y lancer des hacks possibles, et j'espère peut-être que quelque chose finira par fonctionner. Eh bien, je n'ai pas eu à y passer beaucoup de temps. Définir l'opacité à une valeur sous-unité (mais toujours proche de 1, il n'est donc pas perceptible que ce n'est pas entièrement opaque) la valeur le corrige.

 un {
  / * Identique qu'avant * /
  Opacité: .999; / * pirater pour résoudre le problème de mélange ¯_ (ツ) _ / ¯ * /
}
Copier après la connexion

Le problème final est un autre qui est perceptible dans l'enregistrement. Si vous regardez le «R» à la fin de «Amur», vous pouvez remarquer que son extrémité droite est découpée car elle tombe en dehors du rectangle d'arrière-plan. Ceci est particulièrement perceptible si vous le comparez avec le «R» dans «Leopard».

Je n'avais pas de grands espoirs de réparer celui-ci, mais j'ai quand même posé la question à Twitter. Et que savez-vous, cela peut être réparé! L'utilisation de Box-Decoration-Break en combinaison avec le rembourrage que nous avons déjà défini peut nous aider à atteindre l'effet souhaité!

 un {
  / * Identique qu'avant * /
  Box-Decoration-Break: Clone;
}
Copier après la connexion

Notez que la boîte de décoration de boîte a encore besoin du pré-alignement -webkit pour tous les navigateurs WebKit, mais contrairement à des propriétés telles que le clip de fond où au moins une valeur est le texte, les outils de préfixe automatique peuvent très bien s'occuper du problème. C'est pourquoi je n'ai pas inclus la version préfixée dans le code ci-dessus.

Une autre suggestion que j'ai obtenue a été d'ajouter une marge négative pour compenser le rembourrage. Je fais des allers-retours sur celui-ci - je ne peux pas décider si j'aime mieux le résultat avec ou sans lui. En tout état de cause, c'est une option à mentionner.

 $ p: .25em;

un {
  / * Identique qu'avant * /
  marge: 0 (- $ p); / * Nous le mettons dans la parenthèse afin que Sass n'essaie pas d'effectuer une soustraction * /
  rembourrage: 0 $ p;
}
Copier après la connexion

Pourtant, je dois admettre que l'animation uniquement la position d'arrière-plan ou la taille de l'arrière-plan d'un dégradé est un peu ennuyeuse. Mais grâce à Houdini, nous pouvons maintenant faire preuve de créativité et animer n'importe quel composant d'un dégradé que nous souhaitons, même si cela n'est pris en charge que dans le chrome pour le moment. Par exemple, le rayon d'un gradient radial () comme ci-dessous ou la progression d'un gradient conique ().

Inverser juste une zone d'un élément (ou d'un arrière-plan)

C'est le type d'effet que je vois souvent réalisé en utilisant la duplication des éléments - les deux copies sont superposées l'une au-dessus de l'autre, où l'une d'entre elles a un filtre inversé et le chemin de clip est utilisé sur le haut afin de montrer les deux couches. Une autre route consiste à superposer un deuxième élément avec un alpha assez bas, vous ne pouvez même pas dire qu'il est là et un filtre en toile de fond.

Ces deux approches font le travail si nous voulons inverser une partie de l'élément entier avec tout son contenu et ses descendants, mais ils ne peuvent pas nous aider lorsque nous voulons inverser une partie de l'arrière-plan - le filtre et le filtre en toile de fond affectent des éléments entiers, pas seulement leurs arrière-plans. Et tandis que la nouvelle fonction filtre () (déjà prise en charge par Safari) a un effet uniquement sur les couches d'arrière-plan, elle affecte toute la zone de l'arrière-plan, pas seulement une partie de celui-ci.

C'est là que le mélange arrive. Ensuite, nous mélangeons à l'aide de l'un des deux modes de mélange discutés aujourd'hui. Aux fins de l'inversion, je préfère l'exclusion (c'est un caractère plus court que la différence).

Voici un premier exemple. Nous avons un élément carré qui a un fond à deux couches. Les deux couches sont une image d'un chat et d'un gradient avec une transition nette entre blanc et transparent.

 div {
  arrière-plan: 
    gradient linéaire (45 degrés, blanc 50%, transparent 0), 
    URL (cat.jpg) 50% / couverture;
}
Copier après la connexion

Cela nous donne le résultat suivant. Nous avons également établi des dimensions, un radius de frontière, des ombres et a supprimé le texte dans le processus, mais tout ça n'est pas vraiment important dans ce contexte:

Ensuite, nous avons juste besoin d'une autre déclaration CSS pour inverser la moitié inférieure gauche:

 div {
  / * Identique qu'avant * /
  Mode de mélange d'arrière-plan: exclusion; / * ou la différence, mais c'est 1 charl plus * /
}
Copier après la connexion

Notez comment le texte n'est pas affecté par l'inversion; il n'est appliqué qu'à l'arrière-plan.

Vous connaissez probablement les curseurs d'image interactifs avant et après. Vous avez peut-être même vu quelque chose du genre ici sur CSS-Tricks. Je l'ai vu sur Compressor.io, que j'utilise souvent pour compresser des images, y compris celles utilisées dans ces articles!

Notre objectif est de créer quelque chose du genre en utilisant un seul élément HTML, sous 100 octets de JavaScript - et pas même beaucoup de CSS!

Notre élément va être une entrée de plage. Nous ne définissons pas ses attributs MIN ou MAX, donc ils par défaut à 0 et 100, respectivement. Nous ne définissons pas non plus l'attribut de valeur, il est donc par défaut à 50, ce qui est également la valeur que nous donnons une propriété personnalisée, --k, définie dans son attribut de style.

 <entr type="'range'" style="'-" k:></entr>
Copier après la connexion

Dans le CSS, nous commençons par une réinitialisation de base, puis nous faisons de notre entrée un élément de bloc qui occupe toute la hauteur de la fenêtre. Nous donnons également des dimensions et des arrière-plans factice à sa piste et à son pouce juste pour que nous puissions commencer à voir des trucs à l'écran tout de suite.

 $ thumb-w: 5em;

@Mixin Track () {
  Border: aucun;
  Largeur: 100%;
  hauteur: 100%;
  Contexte: URL (fleurs.jpg) 50% / couverture;
}

@mixin thumb () {
  Border: aucun;
  Largeur: $ thumb-w;
  hauteur: 100%;
  Contexte: violet;
}

* {
  marge: 0;
  rembourrage: 0;
}

[type = 'range'] {
  &, & :: - webkit-lider-thumb, 
  & :: - webkit-slider-runnable-track {-webkit-apparition: aucun; }
  
  Affichage: bloc;
  Largeur: 100 VW; Hauteur: 100VH;
  
  & :: - webkit-slider-runnable-track {@include piste; }
  & :: - Moz-Range-Track {@include Track; }
  
  & :: - webkit-slider-thumb {@include thumb; }
  & :: - moz-range-thumb {@include thumb; }
}
Copier après la connexion

L'étape suivante consiste à ajouter une autre couche d'arrière-plan sur la piste, une gradient linéaire où la ligne de séparation entre transparent et blanc dépend de la valeur d'entrée de la plage actuelle, --k, puis de mélanger les deux.

 @Mixin Track () {
  / * Identique qu'avant * /
  arrière-plan:
    URL (fleurs.jpg) 50% / couverture, 
    Gradient linéaire (90deg, Var transparent (- p), blanc 0);
  Mode de mélange d'arrière-plan: exclusion;
}

[type = 'range'] {
  / * Identique qu'avant * /
  --P: calc (var (- k) * 1%);
}
Copier après la connexion

Notez que l'ordre des deux couches d'arrière-plan de la piste n'a pas d'importance car l'exclusion et la différence sont commutatives.

Cela commence à ressembler à quelque chose, mais faire glisser le pouce ne fait rien pour déplacer la ligne de séparation. Cela se produit parce que la valeur actuelle, --k (sur laquelle la position de la ligne de séparation du gradient, --P, dépend), n'est pas automatiquement mise à jour. Fixons cela avec un tout petit peu de javascript qui obtient la valeur du curseur chaque fois qu'il change puis définit --k sur cette valeur.

 addEventListener ('input', e => {
  Selt _t = e.target;
  _t.style.setproperty ('- k', _t.value)
})
Copier après la connexion

Maintenant, tout semble bien fonctionner!

Mais est-ce vraiment? Disons que nous faisons quelque chose d'un peu plus sophistiqué pour le fond du pouce:

 $ thumb-r: .5 * $ thumb-w;
$ thumb-l: 2px;

@mixin thumb () {
  / * Identique qu'avant * /
  --LIST: #FFF 0% 60DEG, transparent 0%;
  arrière-plan: 
    Gradient conic (à partir de 60deg, var (- liste)) 0 / 37,5% / * flèche gauche * /, 
    Gradient conic (à partir de 240deg, var (- liste)) 100% / 37,5% / * flèche droite * /, 
    gradient radial (cercle, 
      Calc transparent calc (# {$ thumb-r} - # {$ thumb-l} - 1px) / * Inside Circle * /, 
      #fff calc (# {$ thumb-r} - # {$ thumb-l}) calc (# {$ thumb-r} - 1px) / * Circle Line * /, 
      transparent $ thumb-r / * extérieur cercle * /), 
    gradient linéaire (
      #fff calc (50% - # {$ thumb-r} .5 * # {$ thumb-l}) / * ligne supérieure * /, 
      transparent 0 calc (50% # {$ thumb-r} - .5 * # {$ thumb-l}) / * écart derrière cercle * /, 
      #fff 0 / * Bottom Line * /) 50% 0 / # {$ thumb-l};
  République de fond: sans répétition;
}
Copier après la connexion

Le gradient linéaire () crée la fine ligne de séparation verticale, le gradient radial () crée le cercle et les deux couches de gradient conique () créent les flèches.

Le problème est désormais évident lors de la traînée du pouce d'un bout à l'autre: la ligne de séparation ne reste pas fixée à la ligne médiane verticale du pouce.

Lorsque nous définissons --P sur calc (var (- k) * 1%), la ligne de séparation passe de 0% à 100%. Il devrait vraiment se déplacer d'un point de départ d'une demi-largeur du pouce, $ thumb-r, jusqu'à une demi-largeur du pouce avant 100%. Autrement dit, dans une fourchette à 100% moins une largeur du pouce, $ thumb-w. Nous soustrayons une moitié de chaque extrémité, c'est donc une largeur de pouce entière à soustraire. Fixons cela!

 --p: calc (# {$ thumb-r} var (- k) * (100% - # {$ thumb-w}) / 100);
Copier après la connexion

Beaucoup mieux!

Mais le fonctionnement des entrées de plage, leur boîte de bordure se déplaçant dans les limites de la boîte de contenu de la piste (Chrome) ou dans les limites de la boîte de contenu de l'entrée réelle (Firefox)… Cela ne semble pas toujours bien. Il serait bien mieux si la ligne médiane du pouce (et, par conséquent, la ligne de séparation) allait jusqu'aux bords de la fenêtre.

Nous ne pouvons pas modifier le fonctionnement des entrées de plage, mais nous pouvons faire en sorte que l'entrée s'étende en dehors de la fenêtre de la fenêtre d'une demi-largeur à gauche et d'une demi-largeur de pouce vers la droite. Cela rend sa largeur égale à celle de la fenêtre, 100 VW, plus une largeur du pouce entière, $ thumb-w.

 corps {débordement: caché; }

[type = 'range'] {
  / * Identique qu'avant * /
  marge-gauche: - $ thumb-r;
  largeur: calc (100vw # {$ thumb-w});
}
Copier après la connexion

Quelques ajustements supplémentaires supplémentaires liés au curseur et c'est tout!

Une version plus sophistiquée de ceci (inspirée par le site Compressor.io) consiste à mettre l'entrée dans une carte dont la rotation 3D change également lorsque la souris se déplace dessus.

Nous pourrions également utiliser un curseur vertical. Ceci est légèrement plus complexe, car notre seul moyen de navigateur croisé fiable de créer des curseurs verticaux de style personnalisés est d'appliquer une rotation sur eux, mais cela ferait également tourner l'arrière-plan. Ce que nous faisons est de définir la valeur - p et ces arrière-plans sur le conteneur de curseur (non tourné), puis gardez l'entrée et sa piste complètement transparente.

Cela peut être vu en action dans la démo ci-dessous, où j'inverse une photo de moi montrant mon sweat à capuche Kreator bien-aimé.

Nous pouvons bien sûr utiliser un gradient radial () pour un effet cool également:

 arrière-plan: 
  Gradient radial (cercle à var (- x, 50%) var (- y, 50%), 
    # 000 calc (var (- card-r) - 1px), #fff var (- card-r)) border-box, 
  $ img 50% / couverture;
Copier après la connexion

Dans ce cas, la position donnée par les propriétés personnalisées --x et - y est calculée à partir du mouvement de la souris sur la carte.

La zone inversée de l'arrière-plan ne doit pas nécessairement être créée par un dégradé. Il peut également s'agir de la zone derrière le texte d'un cap, comme le montre cet ancien article sur le texte contrasté par rapport à une image d'arrière-plan.

Inversion progressive

La technique de mélange pour l'inversion est plus puissante que d'utiliser des filtres de plus d'une manière. Il nous permet également d'appliquer l'effet progressivement le long d'un gradient. Par exemple, le côté gauche n'est pas du tout inversé, mais nous progressons ensuite vers la droite jusqu'à l'inversion complète.

Afin de comprendre comment obtenir cet effet, nous devons d'abord comprendre comment obtenir l'effet inversé (P), où P peut être n'importe quelle valeur dans l'intervalle [0%, 100%] (ou dans l'intervalle [0, 1] si nous utilisons la représentation décimale).

La première méthode, qui fonctionne à la fois pour la différence et l'exclusion consiste à définir le canal alpha de notre blanc à p. Cela peut être vu en action dans la démo ci-dessous, où la traînée du curseur contrôle la progression de l'invression:

Au cas où vous vous interrogez sur la notation HSL (0, 0%, 100% / 100%), c'est maintenant une manière valable de représenter un blanc avec un alpha de 1, selon la spécification.

De plus, en raison de la façon dont le filtre: Invert (P) fonctionne dans le cas général (c'est-à-dire la mise à l'échelle de chaque valeur de canal à un intervalle écrasé [min (p, q), max (p, q)]), où q est le complément de p (ou q = 1 - p) avant de l'inverser (la soustrait de 1), nous avons ce qui suit pour un canal générique CH lorsque vous l'inservez partiellement:

 1 - (q ch · (p - q)) = 
= 1 - (1 - p ch · (p - (1 - p))) = 
= 1 - (1 - p ch · (2 ​​· p - 1)) = 
= 1 - (1 - p 2 · ch · p - ch) = 
= 1 - 1 p - 2 · ch · p ch = 
= Ch p - 2 · ch · p
Copier après la connexion

Ce que nous avons obtenu est exactement la formule d'exclusion où l'autre canal est P! Par conséquent, nous pouvons obtenir le même effet que le filtre: Invert (P) pour tout P dans l'intervalle [0%, 100%] en utilisant le mode de mélange d'exclusion lorsque l'autre couche est RVB (P, P, P).

Cela signifie que nous pouvons avoir une inversion progressive le long d'un gradient linéaire () qui ne va de l'absence d'inversion tout le long du bord gauche, à une inversion complète le long du bord droit), avec ce qui suit:

 arrière-plan: 
  URL (Butterfly_Blues.jpg) 50% / couverture, 
  gradient linéaire (90 degrés, 
    # 000 / * Équivalent à RVB (0%, 0%, 0%) et HSL (0, 0%, 0%) * /, 
    #FFF / * Équivalent à RVB (100%, 100%, 100%) et HSL (0, 0%, 100%) * /);
Mode de mélange d'arrière-plan: exclusion;
Copier après la connexion

Notez que l'utilisation d'un dégradé du noir au blanc pour une inversion progressive ne fonctionne qu'avec le mode de mélange d'exclusion et non avec la différence. Le résultat produit par la différence dans ce cas, compte tenu de sa formule, est une pseudo-inversion progressive qui ne passe pas par le gris à 50% au milieu, mais à travers des valeurs RVB qui ont chacun des trois canaux zéro à différents points le long du gradient. C'est pourquoi le contraste semble plus frappant. C'est peut-être aussi un peu plus artistique, mais ce n'est pas vraiment quelque chose que je suis qualifié pour avoir une opinion.

Avoir différents niveaux d'inversion sur un arrière-plan ne doit pas nécessairement provenir d'un gradient noir à blanc. Il peut également provenir d'une image en noir et blanc car les zones noires de l'image préserveraient la couleur d'arrière-plan, les zones blanches l'inversaient complètement et nous aurions une inversion partielle pour tout le reste lors de l'utilisation du mode de mélange d'exclusion. La différence nous donnerait à nouveau un résultat de duotone plus frappant.

Cela peut être vu dans la démo interactive suivante où vous pouvez modifier la couleur d'arrière-plan et faire glisser la ligne de séparation entre les résultats produits par les deux modes de mélange.

Effet d'intersection creux

L'idée de base ici est que nous avons deux couches avec seulement des pixels noirs et blancs.

Ondulations et rayons

Let's consider an element with two pseudos, each having a background that's a repeating CSS gradient with sharp stops:

 $d: 15em;
$u0: 10%;
$u1: 20%;

div {
  &::before, &::after {
    Affichage: bloc en ligne;
    width: $d;
    height: $d;
    background: repeating-radial-gradient(#000 0 $u0, #fff 0 2*$u0);
    contenu: '';
  }
  
  &::après {
    background: repeating-conic-gradient(#000 0% $u1, #fff 0% 2*$u1);
  }
}
Copier après la connexion

Depending on the browser and the display, the edges between black and white may look jagged… or not.

Just to be on the safe side, we can tweak our gradients to get rid of this issue by leaving a tiny distance, $e, between the black and the white:

 $u0: 10%;
$e0: 1px;
$u1: 5%;
$e1: .2%;

div {
  &::avant {
    arrière-plan: 
      repeating-radial-gradient(
        #000 0 calc(#{$u0} - #{$e0}), 
        #fff $u0 calc(#{2*$u0} - #{$e0}), 
        #000 2*$u0);
  }
  
  &::après {
    arrière-plan: 
      repeating-conic-gradient(
        #000 0% $u1 - $e1, 
        #fff $u1 2*$u1 - $e1, 
        #000 2*$u1);
  }
}
Copier après la connexion

Then we can place them one on top of the other and set mix-blend-mode to exclusion or difference, as they both produce the same result here.

 div {
  &::before, &::after {
    /* same other styles minus the now redundant display */
    Position: absolue;
    mix-blend-mode: exclusion;
  }
}
Copier après la connexion

Wherever the top layer is black, the result of the blending operation is identical to the other layer, whether that's black or white. So, black over black produces black, while black over white produces white.

Wherever the top layer is white, the result of the blending operation is identical to the other layer inverted. So, white over black produces white (black inverted), while white over white produces black (white inverted).

However, depending on the browser, the actual result we see may look as desired (Chromium) or like the ::before got blended with the greyish background we've set on the body and then the result blended with the ::after (Firefox, Safari).

The way Chromium behaves is a bug, but that's the result we want. And we can get it in Firefox and Safari, too, by either setting the isolation property to isolate on the parent div (demo) or by removing the mix-blend-mode declaration from the ::before (as this would ensure the blending operation between it and the body remains the default normal, which means no blending) and only setting it on the ::after (demo).

Of course, we can also simplify things and make the two blended layers be background layers on the element instead of its pseudos. This also means switching from mix-blend-mode to background-blend-mode.

 $d: 15em;
$u0: 10%;
$e0: 1px;
$u1: 5%;
$e1: .2%;

div {
  width: $d;
  height: $d;
  arrière-plan: 
    repeating-radial-gradient(
      #000 0 calc(#{$u0} - #{$e0}), 
      #fff $u0 calc(#{2*$u0} - #{$e0}), 
      #000 2*$u0), 
    repeating-conic-gradient(
      #000 0% $u1 - $e1, 
      #fff $u1 2*$u1 - $e1, 
      #000 2*$u1);;
  background-blend-mode: exclusion;
}
Copier après la connexion

This gives us the exact same visual result, but eliminates the need for pseudo-elements, eliminates the potential unwanted mix-blend-mode side effect in Firefox and Safari, and reduces the amount of CSS we need to write.

Split screen

The basic idea is we have a scene that's half black and half white, and a white item moving from one side to the other. The item layer and the scene layer get then blended using either difference or exclusion (they both produce the same result).

When the item is, for example, a ball, the simplest way to achieve this result is to use a radial-gradient for it and a linear-gradient for the scene and then animate the background-position to make the ball oscillate.

 $d: 15em;

div {
  width: $d;
  height: $d;
  arrière-plan: 
    radial-gradient(closest-side, #fff calc(100% - 1px), transparent) 
      0/ 25% 25% no-repeat,
    linear-gradient(90deg, #000 50%, #fff 0);
  background-blend-mode: exclusion;
  animation: mov 2s ease-in-out infinite alternate;
}

@keyframes mov { to { background-position: 100%; }}
Copier après la connexion

We can also make the ::before pseudo the scene and the ::after the moving item:

 $d: 15em;

div {
  display: grid;
  width: $d;
  height: $d;
  
  &::before, &::after {
    grid-area: 1/ 1;
    background: linear-gradient(90deg, #000 50%, #fff 0);
    contenu: '';
  }
  
  &::après {
    place-self: center start;
    padding: 12.5%;
    Border-Radius: 50%;
    Contexte: #FFF;
    mix-blend-mode: exclusion;
    animation: mov 2s ease-in-out infinite alternate;
  }
}

@keyframes mov { to { transform: translate(300%); }}
Copier après la connexion

This may look like we're over-complicating things considering that we're getting the same visual result, but it's actually what we need to do if the moving item isn't just a disc, but a more complex shape, and the motion isn't just limited to oscillation, but it also has a rotation and a scaling component.

 $d: 15em;
$t: 1s;

div {
  /* same as before */
  
  &::après {
    /* same as before */
    /* creating the shape, not detailed here as
       it's outside the scope of this article */
    @include poly;
    /* the animations */
    animation: 
      t $t ease-in-out infinite alternate, 
      r 2*$t ease-in-out infinite, 
      s .5*$t ease-in-out infinite alternate;
  }
}

@keyframes t { to { translate: 300% } }
@keyframes r {
  50% { rotate: .5turn; }
  100% { rotate: 1turn;; }
}
@keyframes s { to { scale: .75 1.25 } }
Copier après la connexion

Note that, while Safari has now joined Firefox in supporting the individual transform properties we're animating here, these are still behind the Experimental Web Platform features flag in Chrome (which can be enabled from chrome://flags as shown below).

More examples

We won't be going into details about the “how” behind these demos as the basic idea of the blending effect using exclusion or difference is the same as before and the geometry/animation parts are outside the scope of this article. However, for each of the examples below, there is a link to a CodePen demo in the caption and a lot of these Pens also come with a recording of me coding them from scratch.

Here's a crossing bars animation I recently made after a Bees & Bombs GIF:

And here's a looping moons animation from a few years back, also coded after a Bees & Bombs GIF:

We're not necessarily limited to just black and white. Using a contrast filter with a subunitary value (filter: contrast(.65) in the example below) on a wrapper, we can turn the black into a dark grey and the white into a light grey:

Here's another example of the same technique:

If we want to make it look like we have a XOR effect between black shapes on a white background, we can use filter: invert(1) on the wrappers of the shapes, like in the example below:

And if we want something milder like dark grey shapes on a light grey background, we don't go for full inversion, but only for partial one. This means using a subunitary value for the invert filter like in the example below where we use filter: invert(.85):

It doesn't necessarily have to be something like a looping or loading animation. We can also have a XOR effect between an element's background and its offset frame. Just like in the previous examples, we use CSS filter inversion if we want the background and the frame to be black and their intersection to be white.

Another example would be having a XOR effect on hovering/ focusing and clicking a close button. The example below shows both night and light theme cases:

Bring me to life

Things can look a bit sad only in black and white, so there are few things we can do to put some life into such demos.

The first tactic would be to use filters. We can break free from the black and white constraint by using sepia() after lowering the contrast (as this function has no effect over pure black or white). Pick the hue using hue-rotate() and then fine tune the result using brightness() and saturate() or contrast().

For example, taking one of the previous black and white demos, we could have the following filter chain on the wrapper:

 filtre: 
  contrast(.65) /* turn black and white to greys */
  sepia(1) /* retro yellow-brownish tint */
  hue-rotate(215deg) /* change hue from yellow-brownish to purple */
  blur(.5px) /* keep edges from getting rough/ jagged */
  contrast(1.5) /* increase saturation */
  brightness(5) /* really brighten background */
  contrast(.75); /* make triangles less bright (turn bright white dirty) */
Copier après la connexion

For even more control over the result, there's always the option of using SVG filters.

The second tactic would be to add another layer, one that's not black and white. For example, in this radioactive pie demo I made for the first CodePen challenge of March, I used a purple ::before pseudo-element on the body that I blended with the pie wrapper.

 body, div { display: grid; }

/* stack up everything in one grid cell */
div, ::before { grid-area: 1/ 1; }

body::before { background: #7a32ce; } /* purple layer */

/* applies to both pie slices and the wrapper */
div { mix-blend-mode: exclusion; }

.a2d { background: #000; } /* black wrapper */

.pie {
  background: /* variable size white pie slices */
    conic-gradient(from calc(var(--p)*(90deg - .5*var(--sa)) - 1deg), 
      transparent, 
      #fff 1deg calc(var(--sa) var(--q)*(1turn - var(--sa))), 
      transparent calc(var(--sa) var(--q)*(1turn - var(--sa)) 1deg));
}
Copier après la connexion

This turns the black wrapper purple and the white parts green (which is purple inverted).

Another option would be blending the entire wrapper again with another layer, this time using a blend mode different from difference or exclusion. Doing so would allow us more control over the result so we're not limited to just complementaries (like black and white, or purple and green). That, however, is something we'll have to cover in a future article.

Finally, there's the option of using difference (and not exclusion) so that we get black where two identical (not necessarily white) layers overlap. For example, the difference between coral and coral is always going to be 0 on all three channels, which means black. This means we can adapt a demo like the offset and XOR frame one to get the following result:

With some properly set transparent borders and background clipping, we can also make this work for gradient backgrounds:

Similarly, we can even have an image instead of a gradient!

Note that this means we also have to invert the image background when we invert the element in the second theme scenario. But that should be no problem, because in this article we've also learned how to do that: by setting background-color to white and blending the image layer with it using background-blend-mode: exclusion!

Réflexions de clôture

Just these two blend modes can help us get some really cool results without resorting to canvas, SVG or duplicated layers. But we've barely scratched the surface here. In future articles, we'll dive into how other blend modes work and what we can achieve with them alone or in combination with previous ones or with other CSS visual effects such as filters. And trust me, the more tricks you have up your sleeve, the cooler the results you're able to achieve get!

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