Maison > interface Web > tutoriel CSS > Différentes façons d'obtenir des ombres de gradient CSS

Différentes façons d'obtenir des ombres de gradient CSS

Lisa Kudrow
Libérer: 2025-03-09 10:03:14
original
426 Les gens l'ont consulté

Different Ways to Get CSS Gradient Shadows

Je pose souvent une question: Puis-je créer des ombres avec des couleurs dégradées au lieu de couleurs unies? Il n'y a pas de propriétés spéciales dans le CSS pour y parvenir (croyez-moi, je l'ai cherché), et tous les articles de blog que vous trouvez à ce sujet sont essentiellement des astuces CSS de gradient similaires. Nous couvrirons certains de ces conseils ensuite.

Mais d'abord ... est un autre article sur les ombres de gradient? Vraiment?

Oui, c'est un autre article sur ce sujet, mais c'est différent. Ensemble, nous allons repousser les limites et trouver une solution qui couvre quelque chose que je n'ai jamais vu ailleurs: Transparence . La plupart des conseils fonctionnent lorsque les éléments ont des arrière-plans non transparents, mais que se passe-t-il si nous avons des arrière-plans transparents? Nous discuterons de cette situation ici!

Avant de commencer, permettez-moi de présenter mon générateur d'ombre dégradé. Il vous suffit de régler la configuration et vous pouvez obtenir le code. Mais continuez à lire car je vous aiderai à comprendre toute la logique derrière la génération du code.

Catalogue

  • Solution non transparente
  • Solution transparente
  • Ajouter des coins arrondis
  • Résumé

Solution non transparente

Commençons par des solutions qui fonctionnent pour 80% des situations communes. Le cas le plus typique est que vous utilisez un élément avec un fond et que vous devez y ajouter une ombre dégradé. Il n'est pas nécessaire de considérer la transparence ici.

La solution consiste à s'appuyer sur un pseudo-élément qui définit le gradient. Vous le mettez derrière l'élément réel et y appliquez un filtre flou.

<code>.box {
  position: relative;
}
.box::before {
  content: "";
  position: absolute;
  inset: -5px; /* 控制扩散 */
  transform: translate(10px, 8px); /* 控制偏移量 */
  z-index: -1; /* 将元素置于后面 */
  background: /* 你的渐变色在这里 */;
  filter: blur(10px); /* 控制模糊 */
}</code>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Le code semble beaucoup, car il en a beaucoup. Voici comment utiliser Box-Shadow au lieu d'un dégradé si nous utilisons des couleurs unies au lieu de gradients.

<code>box-shadow: 10px 8px 10px 5px orange;</code>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Cela devrait vous donner une bonne idée de ce que fait la valeur du premier morceau de code. Nous avons des décalages x et y, un rayon flou et une distance de diffusion. Notez que nous avons besoin d'une valeur de distance de diffusion négative de la propriété d'encart.

Ceci est une démo montrant des ombres dégradées côte à côte avec un box-shadow classique:

Si vous regardez de près, vous remarquerez que les deux ombres sont légèrement différentes, en particulier les pièces floues. Ce n'est pas surprenant, car je suis presque sûr que l'algorithme pour les attributs de filtre est différent de celui de Box-Shadow. Ce n'est pas grave, car le résultat final est très similaire.

Cette solution est bonne, mais a toujours des inconvénients liés à la déclaration z-index: -1. Oui, il y a un "contexte de pile" là-bas!

J'ai appliqué une transformation à l'élément principal, puis l'ombre n'est plus en dessous de l'élément. Ce n'est pas une erreur, mais un résultat logique des contextes d'empilement. Ne vous inquiétez pas, je ne commencerai pas à donner des explications ennuyeuses des contextes d'empilement (je l'ai fait dans des threads de débordement de pile), mais je vais toujours vous montrer comment le réparer.

La première solution que je recommande est d'utiliser la conversion 3D:

<code>.box {
  position: relative;
}
.box::before {
  content: "";
  position: absolute;
  inset: -5px; /* 控制扩散 */
  transform: translate(10px, 8px); /* 控制偏移量 */
  z-index: -1; /* 将元素置于后面 */
  background: /* 你的渐变色在这里 */;
  filter: blur(10px); /* 控制模糊 */
}</code>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Nous n'utilisons pas z-index: -1, mais utilisons une traduction négative le long de l'axe z. Nous avons tout mis dans tradlate3d (). N'oubliez pas d'utiliser le style Transform: Preserve-3D sur l'élément principal; Sinon, la conversion 3D ne prendra pas effet.

Pour autant que je sache, cette solution n'a pas d'effets secondaires ... mais peut-être que vous en verrez un. Si oui, veuillez partager la section des commentaires et essayons de trouver une solution!

Si, pour une raison quelconque, vous ne pouvez pas utiliser la conversion 3D, une autre solution consiste à s'appuyer sur deux pseudo-éléments - :: avant et :: After. L'un crée une ombre dégradée, les autres copies l'arrière-plan principal (et les autres styles dont vous pourriez avoir besoin). De cette façon, nous pouvons facilement contrôler l'ordre d'empilement de deux pseudo-éléments.

<code>box-shadow: 10px 8px 10px 5px orange;</code>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Il est important de noter que nous obligeons le à créer un contexte d'empilement en déclarant Z-Index: 0 sur celui-ci ou tout autre attribut qui fait de même. N'oubliez pas non plus que le pseudo-élément traite la boîte de remplissage de l'élément principal comme référence. Par conséquent, si l'élément principal a des frontières, cela doit être pris en compte lors de la définition du style pseudo-élémentaire. Vous remarquerez que j'utilise le coffre-fort: -2px sur :: After pour considérer les frontières définies sur les éléments principaux.

Comme je l'ai dit, cette solution peut être assez bonne dans la plupart des cas tant que vous n'avez pas besoin de soutenir la transparence, vous voulez une ombre de dégradé. Mais nous sommes venus défier et repousser les limites, donc même si vous n'avez pas besoin de ce dont vous voulez parler ensuite, veuillez continuer à faire attention. Vous pouvez apprendre de nouveaux conseils CSS que vous pouvez utiliser ailleurs.

Solution transparente

Commençons où nous terminons par transformation 3D et supprimons l'arrière-plan de l'élément principal. Je vais commencer par une ombre où le décalage et la distance de diffusion sont égaux à 0.

L'idée est de trouver un moyen de recadrer ou de cacher tout dans une zone de l'élément (dans une bordure verte) tout en conservant le contenu externe. Nous utiliserons Clip Path pour cela. Mais vous vous demandez peut-être comment Clip Path peut être recadré à l'intérieur d'un élément

. En effet, il n'y a aucun moyen de le faire, mais nous pouvons le simuler avec un motif de polygone spécifique:

Regardez! Nous obtenons une ombre dégradée qui prend en charge la transparence. Tout ce que nous avons fait était d'ajouter un chemin de clip au code précédent. Voici un diagramme pour illustrer la partie polygone.
<code>.box {
  position: relative;
  transform-style: preserve-3d;
}
.box::before {
  content: "";
  position: absolute;
  inset: -5px;
  transform: translate3d(10px, 8px, -1px); /* (X, Y, Z) */
  background: /* .. */;
  filter: blur(10px);
}</code>
Copier après la connexion
Copier après la connexion
Copier après la connexion

La zone bleue est la partie visible après avoir appliqué le chemin de clip. Je n'utilise que le bleu pour illustrer le concept, mais en réalité, nous ne voyons que des ombres dans la région. Comme vous pouvez le voir, nous définissons quatre points et leurs valeurs sont très grandes (b). Ma grande valeur est 100VMax, mais cela peut être la grande valeur que vous voulez. L'idée est de s'assurer que nous avons suffisamment d'espace d'ombre. Nous avons quatre points supplémentaires qui sont les points d'angle du pseudo-élément.

Les flèches indiquent le chemin qui définit le polygone. Nous commençons de (-b, -b) et jusqu'à ce que nous atteignions (0,0). Au total, nous avons besoin de 10 points. Pas 8 points, car les deux points ((-b, -b) et (0,0)) sont répétés deux fois dans le chemin.

Nous devons également faire la dernière chose , qui est de considérer la distance de diffusion et le décalage. La démonstration ci-dessus fonctionne simplement parce qu'il s'agit d'un cas spécial, le décalage et la distance de diffusion sont égaux à 0.

Définissons la diffusion et voyons ce qui se passe. N'oubliez pas que nous utilisons un insert de valeur négative pour ce faire:

Le pseudo-élément est désormais plus grand que l'élément principal, donc le clip Clip Path est plus que ce dont nous avons besoin. N'oubliez pas que nous devons toujours recadrer la partie de l'élément principal

à l'intérieur (la zone à l'intérieur de la bordure verte de l'exemple). Nous devons ajuster la position des quatre points du chemin à clip.

<code>.box {
  position: relative;
}
.box::before {
  content: "";
  position: absolute;
  inset: -5px; /* 控制扩散 */
  transform: translate(10px, 8px); /* 控制偏移量 */
  z-index: -1; /* 将元素置于后面 */
  background: /* 你的渐变色在这里 */;
  filter: blur(10px); /* 控制模糊 */
}</code>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Nous avons défini une variable CSS --S pour la distance de diffusion et mis à jour les points de polygone. Je n'ai pas touché où j'ai utilisé la grande valeur. Je met à jour uniquement les points qui définissent l'angle de l'élément pseudo-élémentaire. J'augmente toutes les valeurs zéro - s et réduit 100% des valeurs - s.

Le décalage est la même logique. Lorsque nous convertissons les pseudo-éléments, les ombres sont mal alignées et nous devons à nouveau corriger le polygone et déplacer les points dans la direction opposée.

<code>box-shadow: 10px 8px 10px 5px orange;</code>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Il y a deux autres variables pour les décalages: --x et --y. Nous les utilisons à l'intérieur de la transformation et nous avons également mis à jour la valeur de Path Clip. Nous ne touchons toujours pas les points de polygone avec de grandes valeurs, mais nous compensons tous les autres points - nous réduisons --x à partir des coordonnées x et --y des coordonnées Y.

Maintenant, nous devons seulement mettre à jour certaines variables pour contrôler l'ombre du gradient. Lorsque nous faisons cela, transformons également le rayon flou en une variable:

avons-nous encore besoin de compétences de conversion 3D?

Tout dépend de la frontière. N'oubliez pas que la référence pour les pseudo-éléments est la boîte de remplissage, donc si vous appliquez des frontières à l'élément principal, vous aurez le chevauchement. Vous pouvez conserver l'astuce de conversion 3D ou mettre à jour la valeur d'encart pour considérer les frontières.

Il s'agit de la version utilisée pour remplacer la conversion 3D par la valeur d'encart mise à jour dans la démonstration précédente:

Je pense que c'est une approche plus appropriée, car la distance de diffusion sera plus précise, car elle commence par la boîte de bordure au lieu de la boîte de padding. Mais vous devez ajuster la valeur d'encart en fonction de la bordure de l'élément principal. Parfois, la bordure de l'élément est inconnue et vous devez utiliser la solution précédente.

En utilisant la solution non transparente précédente, vous pouvez rencontrer des problèmes de contexte d'empilement. Avec des solutions transparentes, vous pouvez rencontrer des problèmes de frontières. Vous avez maintenant des options et des moyens de résoudre ces problèmes. L'astuce de conversion 3D est ma solution préférée car elle résout tous les problèmes (les générateurs en ligne le considéreront aussi)

Ajouter des coins arrondis

Si vous essayez d'ajouter le radius frontalier aux éléments lorsque nous utilisons la solution non transparente que nous avons commencé, c'est une tâche assez simple. Il vous suffit de hériter de la même valeur à partir de l'élément principal et vous avez terminé.

Définition du radius frontalier: L'héritage est une bonne idée même si vous n'avez pas de coins arrondis. Cela considère les coins arrondis potentiels que vous voudrez peut-être ajouter dans les coins futurs ou arrondis d'ailleurs.

La situation de gérer des solutions transparentes est différente. Malheureusement, cela signifie trouver une autre solution car Clip Path ne peut pas gérer la courbe. Cela signifie que nous ne pourrons pas recadrer la zone à l'intérieur de l'élément principal.

Nous ajoutons l'attribut de masque au mélange.

Cette partie est très fastidieuse et j'ai du mal à trouver une solution générale qui ne dépend pas des numéros magiques. Je me suis retrouvé avec une solution très complexe qui n'utilise qu'un seul pseudo-élément, mais le code est un gâchis et ne couvre que quelques situations spécifiques. Je ne pense pas que cela vaut la peine d'explorer ce chemin.

Pour simplifier le code, j'ai décidé d'insérer un élément supplémentaire. Voici les marques:

<code>.box {
  position: relative;
}
.box::before {
  content: "";
  position: absolute;
  inset: -5px; /* 控制扩散 */
  transform: translate(10px, 8px); /* 控制偏移量 */
  z-index: -1; /* 将元素置于后面 */
  background: /* 你的渐变色在这里 */;
  filter: blur(10px); /* 控制模糊 */
}</code>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

J'utilise un élément personnalisé pour éviter tout conflit potentiel avec le CSS externe. Je peux utiliser

, mais parce que c'est un élément commun, il est facile d'être positionné par une autre règle CSS d'ailleurs, ce qui peut briser notre code. La première étape consiste à localiser l'élément et à créer délibérément le débordement:
<code>box-shadow: 10px 8px 10px 5px orange;</code>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Le code peut sembler un peu étrange, mais nous expliquerons la logique derrière elle étape par étape. Ensuite, nous utilisons le pseudo-élément de pour créer une ombre dégradé.

<code>.box {
  position: relative;
  transform-style: preserve-3d;
}
.box::before {
  content: "";
  position: absolute;
  inset: -5px;
  transform: translate3d(10px, 8px, -1px); /* (X, Y, Z) */
  background: /* .. */;
  filter: blur(10px);
}</code>
Copier après la connexion
Copier après la connexion
Copier après la connexion

Comme vous pouvez le voir, le pseudo-élément utilise le même code que tous les exemples précédents. La seule différence est que la transformation 3D est définie sur l'élément , pas sur l'élément pseudo-élémentaire. Actuellement, nous avons une ombre dégradé sans fonction de transparence:

Veuillez noter que la zone de l'élément est définie avec un contour noir. Pourquoi est-ce que je fais ça? Pour cette raison, je peux appliquer un masque dessus pour cacher les pièces à l'intérieur de la zone verte et garder la partie débordante où nous devons voir l'ombre.

Je sais que c'est un peu délicat, mais contrairement à Clip Path, l'attribut de masque ne prend pas en compte la zone de l'élément à l'extérieur pour afficher et masquer le contenu. C'est pourquoi j'ai dû introduire des éléments supplémentaires - pour simuler la zone "extérieure".

Aussi, notez que j'utilise une combinaison de bordures et d'inscription pour définir la zone. Cela me permet de garder la boîte de rembourrage de l'élément supplémentaire comme l'élément principal afin que le pseudo-élément ne nécessite pas de calculs supplémentaires.

Une autre chose utile qui obtient de l'utilisation d'éléments supplémentaires est que les éléments sont fixés et que seuls les pseudo-éléments se déplacent (en utilisant tradlate). Cela me permettra de définir facilement le masque, qui est la dernière étape de cette astuce.

terminé! Nous avons des ombres de gradient, et elle prend en charge Border-Radius! Vous pourriez vous attendre à une valeur de masque complexe avec beaucoup de gradients à l'intérieur, mais pas! Nous n'avons besoin que de deux gradients simples et d'une composite de masque pour compléter la magie.
<code>.box {
  position: relative;
  z-index: 0; /* 我们强制创建一个堆叠上下文 */
}
/* 创建阴影 */
.box::before {
  content: "";
  position: absolute;
  z-index: -2;
  inset: -5px;
  transform: translate(10px, 8px);
  background: /* .. */;
  filter: blur(10px);
}
/* 复制主元素样式 */
.box::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  /* 继承在主元素上定义的所有装饰 */
  background: inherit;
  border: inherit;
  box-shadow: inherit;
}</code>
Copier après la connexion

Isoler l'élément

pour comprendre ce qui se passe là-bas:

Voici les résultats que nous avons obtenus:
<code>clip-path: polygon(-100vmax -100vmax,100vmax -100vmax,100vmax 100vmax,-100vmax 100vmax,-100vmax -100vmax,0 0,0 100%,100% 100%,100% 0,0 0)</code>
Copier après la connexion

Remarquez comment le rayon interne correspond au rayon frontalier de l'élément principal. J'ai défini une grande bordure (150px) et un radius frontalier égal à la grande bordure

plus

Rayon principal de l'élément. Extérieurement, j'ai un rayon égal à 150px R. En interne, j'ai 150px r - 150px = R. Nous devons cacher la partie intérieure (bleue) et nous assurer que la partie (rouge) (rouge) est toujours visible. Pour ce faire, j'ai défini deux couches de masque - l'une couvrant uniquement la zone de boîte de contenu et l'autre couvrant la zone de la boîte de bordure (par défaut). J'en excluons ensuite l'un des autres pour montrer la frontière.

<code>.box {
  position: relative;
}
.box::before {
  content: "";
  position: absolute;
  inset: -5px; /* 控制扩散 */
  transform: translate(10px, 8px); /* 控制偏移量 */
  z-index: -1; /* 将元素置于后面 */
  background: /* 你的渐变色在这里 */;
  filter: blur(10px); /* 控制模糊 */
}</code>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

J'utilise la même technique pour créer des bordures qui soutiennent les gradients et le radius frontalier. Ana Tudor a également un bon article sur la composition du masque, et je vous invite à le lire.

y a-t-il des inconvénients de cette méthode?

Oui, ce n'est certainement pas parfait. Le premier problème que vous pouvez rencontrer est lié à l'utilisation des frontières sur l'élément principal. Si vous ne le considérez pas, cela peut conduire à un léger désalignement du rayon. Ce problème existe dans notre exemple, mais vous pouvez avoir du mal à le remarquer.

Correction relativement facile: ajoutez la largeur de la bordure à l'encart de l'élément .

<code>box-shadow: 10px 8px 10px 5px orange;</code>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Un autre inconvénient est la grande valeur que nous utilisons pour les bordures (150px dans l'exemple). Cette valeur doit être suffisamment grande pour contenir des ombres, mais pas trop grande pour éviter les problèmes de débordement et de défilement. Heureusement, le générateur en ligne prendra compte de tous les paramètres pour calculer la valeur optimale.

Le dernier inconvénient que je me rends compte, c'est lorsque vous utilisez un rayon de frontière complexe. Par exemple, si vous souhaitez appliquer un rayon différent à chaque coin, vous devez définir une variable pour chaque côté. Ce n'est pas un véritable inconvénient, je pense, mais cela peut rendre votre code un peu plus difficile à entretenir.

<code>.box {
  position: relative;
  transform-style: preserve-3d;
}
.box::before {
  content: "";
  position: absolute;
  inset: -5px;
  transform: translate3d(10px, 8px, -1px); /* (X, Y, Z) */
  background: /* .. */;
  filter: blur(10px);
}</code>
Copier après la connexion
Copier après la connexion
Copier après la connexion

Pour plus de simplicité, le générateur en ligne ne considère que un rayon uniforme, mais vous savez maintenant comment modifier le code si vous souhaitez envisager des configurations de rayon complexes.

Résumé

Nous avons atteint la fin! La magie derrière l'ombre dégradé n'est plus un mystère. J'essaie de couvrir toutes les possibilités et tous les problèmes que vous pourriez avoir. Si j'ai manqué quelque chose ou si vous avez trouvé des problèmes, n'hésitez pas à le signaler dans la section des commentaires et je vais le vérifier.

Encore une fois, étant donné que la solution de facto couvrira la plupart de vos cas d'utilisation, beaucoup d'entre eux peuvent être redondants. Cependant, il est bon de comprendre le «pourquoi» et le «comment» derrière la technique et comment surmonter ses limites. De plus, nous avons eu une excellente pratique pour jouer à l'édition CSS et Matte.

Bien sûr, vous pouvez toujours utiliser le générateur en ligne pour éviter les problèmes.

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
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal