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.
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>
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>
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>
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>
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
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>
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>
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>
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
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>
J'utilise un élément personnalisé 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 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 Veuillez noter que la zone de l'élément 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.
Isoler l'élément 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 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. 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 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. 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. 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. <code>box-shadow: 10px 8px 10px 5px orange;</code>
<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>
<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>
<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>
<code>.box {
position: relative;
}
.box::before {
content: "";
position: absolute;
inset: -5px; /* 控制扩散 */
transform: translate(10px, 8px); /* 控制偏移量 */
z-index: -1; /* 将元素置于后面 */
background: /* 你的渐变色在这里 */;
filter: blur(10px); /* 控制模糊 */
}</code>
<code>box-shadow: 10px 8px 10px 5px orange;</code>
<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>
Résumé
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!