Créez des effets d'image réactifs avec des dégradés CSS et un rapport d'aspect
Publié: 2022-03-10aspect-ratio
nouvellement prise en charge en combinaison avec object-fit
fournit un remède à ce casse-tête du passé ! Apprenons à utiliser ces propriétés, en plus de créer un effet d'image dégradé réactif pour plus de style.Pour préparer nos futurs effets d'image, nous allons configurer un composant de carte comportant une grande image en haut, suivie d'un titre et d'une description. Le problème commun avec cette configuration est que nous n'avons pas toujours un contrôle parfait sur ce qu'est l'image, et plus important encore pour notre mise en page, quelles sont ses dimensions . Et bien que cela puisse être résolu en recadrant à l'avance, nous pouvons toujours rencontrer des problèmes dus à des conteneurs de taille adaptée. Une conséquence est des positions inégales du contenu de la carte qui se démarquent vraiment lorsque vous présentez une rangée de cartes.
Une autre solution précédente en plus du recadrage aurait pu être de passer d'un img
en ligne à un div
vide qui n'existait que pour présenter l'image via background-image
. J'ai implémenté cette solution plusieurs fois moi-même dans le passé. L'un des avantages que cela présente est d'utiliser une astuce plus ancienne pour le rapport d'aspect qui utilise un élément de hauteur nulle et définit une valeur padding-bottom
. La définition d'une valeur de remplissage en pourcentage donne une valeur calculée finale relative à la largeur de l'élément. Vous avez peut-être également utilisé cette idée pour conserver un ratio 16:9 pour les intégrations vidéo, auquel cas la valeur de rembourrage est trouvée avec la formule : 9/16 = 0.5625 * 100% = 56.26%
. Mais nous allons explorer deux propriétés CSS modernes qui n'impliquent pas de mathématiques supplémentaires, nous donnent plus de flexibilité et permettent également de conserver la sémantique fournie en utilisant un vrai img
au lieu d'un div
vide.
Définissons d'abord la sémantique HTML, y compris l'utilisation d'une liste non ordonnée comme conteneur des cartes :
<ul class="card-wrapper"> <li class="card"> <img src="" alt=""> <h3>A Super Wonderful Headline</h3> <p>Lorem ipsum sit dolor amit</p> </li> <!-- additional cards --> </ul>
Ensuite, nous allons créer un ensemble minimal de styles de base pour le composant .card
. Nous définirons quelques styles visuels de base pour la carte elle-même, une mise à jour rapide du titre h3
attendu, puis des styles essentiels pour commencer à styliser l'image de la carte.
.card { background-color: #fff; border-radius: 0.5rem; box-shadow: 0.05rem 0.1rem 0.3rem -0.03rem rgba(0, 0, 0, 0.45); padding-bottom: 1rem; } .card > :last-child { margin-bottom: 0; } .card h3 { margin-top: 1rem; font-size: 1.25rem; } img { border-radius: 0.5rem 0.5rem 0 0; width: 100%; } img ~ * { margin-left: 1rem; margin-right: 1rem; }
La dernière règle utilise le combinateur général des frères et sœurs pour ajouter une marge horizontale à tout élément qui suit l' img
puisque nous voulons que l'image elle-même soit alignée avec les côtés de la carte.
Et nos progrès jusqu'à présent nous amènent à l'apparence de carte suivante :
Enfin, nous allons créer les styles .card-wrapper
pour une mise en page réactive rapide à l'aide de la grille CSS. Cela supprimera également les styles de liste par défaut.
.card-wrapper { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(30ch, 1fr)); grid-gap: 1.5rem; }
Remarque : Si cette technique de grille ne vous est pas familière, consultez l'explication de mon tutoriel sur les solutions modernes pour la grille à 12 colonnes.
Avec cela appliqué et avec toutes les cartes contenant une image avec un chemin source valide, nos styles .card-wrapper
nous donnent la disposition suivante :
Comme le montre l'image d'aperçu, ces styles de base ne suffisent pas pour contenir correctement les images compte tenu de leurs dimensions naturelles variables. Nous avons besoin d'une méthode pour contraindre ces images de manière uniforme et cohérente.
Activer les tailles d'image uniformes avec object-fit
Comme indiqué précédemment, vous avez peut-être précédemment effectué une mise à jour dans ce scénario pour modifier les images à ajouter via background-image
à la place et utilisé background-size: cover
pour gérer correctement le redimensionnement de l'image. Ou vous avez peut-être essayé d'appliquer le recadrage à l'avance (toujours un objectif louable puisque toute réduction de la taille de l'image améliorera les performances !).
Maintenant, nous avons la propriété object-fit
disponible qui permet à une balise img
d'agir comme conteneur pour l'image. Et, il est également livré avec une valeur de cover
qui donne un effet similaire à la solution d'image d'arrière-plan, mais avec l'avantage de conserver la sémantique d'une image en ligne. Appliquons-le et voyons comment cela fonctionne.
Nous devons l'associer à une dimension de height
pour obtenir des indications supplémentaires sur la façon dont nous voulons que le conteneur d'image se comporte (rappelez-vous que nous avions déjà ajouté width: 100%
). Et nous allons utiliser la fonction max()
pour sélectionner 10rem
ou 30vh
selon ce qui est le plus grand dans un contexte donné, ce qui empêche la hauteur de l'image de trop rétrécir sur des fenêtres plus petites ou lorsque l'utilisateur a défini un grand zoom.
img { /* ...existing styles */ object-fit: cover; height: max(10rem, 30vh); }
Astuce Accessibilité Bonus : Vous devriez toujours tester vos mises en page avec un zoom de 200% et 400% sur le bureau. Bien qu'il n'y ait pas actuellement de requête de zoom
multimédia, des fonctions telles que max()
peuvent aider à résoudre les problèmes de mise en page. Un autre contexte dans lequel cette technique est utile est l'espacement entre les éléments.
Avec cette mise à jour, nous avons définitivement amélioré les choses, et le résultat visuel est comme si nous utilisions l'ancienne technique d'image d'arrière-plan :
Dimensionnement d'image cohérent et réactif avec aspect-ratio
Lorsque vous utilisez object-fit
seul, un inconvénient est que nous devons encore définir des indications de dimension.
Une propriété à venir (actuellement disponible dans les navigateurs Chromium) appelée aspect-ratio
améliorera notre capacité à dimensionner les images de manière cohérente.
En utilisant cette propriété, nous pouvons définir un ratio pour redimensionner l'image au lieu de définir des dimensions explicites. Nous continuerons à l'utiliser en combinaison avec object-fit
pour nous assurer que ces dimensions n'affectent que l'image en tant que conteneur, sinon l'image pourrait apparaître déformée.
Voici notre règle d'image entièrement mise à jour :
img { border-radius: 0.5rem 0.5rem 0 0; width: 100%; object-fit: cover; aspect-ratio: 4/3; }
Nous allons commencer avec un rapport d'image de 4 ⁄ 3 pour notre contexte de carte, mais vous pouvez choisir n'importe quel rapport. Par exemple, 1 ⁄ 1 pour un carré ou 16 ⁄ 9 pour les intégrations vidéo standard.
Voici les cartes mises à jour, bien qu'il soit probablement difficile de remarquer la différence visuelle dans ce cas particulier, car le rapport d'aspect correspond étroitement à l'apparence que nous avons obtenue en définissant la height
uniquement pour object-fit
.
La définition d'un "rapport d'aspect" permet de maintenir le rapport au fur et à mesure que les éléments grandissent ou rétrécissent, alors qu'en définissant uniquement "object-fit" et "height", le rapport d'image sera constamment en évolution à mesure que les dimensions du conteneur changent.
"
Ajout d'effets réactifs avec des dégradés et des fonctions CSS
OK, maintenant que nous savons comment configurer des images de taille cohérente, amusons-nous avec elles en ajoutant un effet de dégradé !
Notre objectif avec cet effet est de donner l'impression que l'image se fond dans le contenu de la carte. Vous pourriez être tenté d'envelopper l'image dans son propre conteneur pour ajouter le dégradé, mais grâce au travail que nous avons déjà fait sur le dimensionnement de l'image, nous pouvons déterminer comment le faire en toute sécurité sur le .card
principal.
La première étape consiste à définir un dégradé . Nous allons utiliser une propriété personnalisée CSS pour ajouter les couleurs du dégradé afin de permettre de permuter facilement l'effet de dégradé, en commençant par un bleu à rose. La dernière couleur du dégradé sera toujours blanche pour maintenir la transition vers l'arrière-plan du contenu de la carte et créer le bord « en plumes ».
.card { --card-gradient: #5E9AD9, #E271AD; background-image: linear-gradient( var(--card-gradient), white max(9.5rem, 27vh) ); /* ...existing styles */ }
Mais attendez - est-ce une fonction CSS max()
? En dégradé ? Oui, c'est possible, et c'est la magie qui rend ce dégradé efficace en responsive !
Cependant, si je devais ajouter une capture d'écran, nous ne verrions pas encore le dégradé avoir d'effet sur l'image. Pour cela, nous devons intégrer la propriété mix-blend-mode
et, dans ce scénario, nous utiliserons la valeur overlay
:
img { /* ...existing styles */ mix-blend-mode: overlay; }
La propriété mix-blend-mode
est similaire à l'application des styles de fusion de calques disponibles dans les logiciels de manipulation de photos tels que Photoshop. Et la valeur de overlay
aura pour effet de permettre aux tons moyens de l'image de se fondre avec le dégradé derrière, conduisant au résultat suivant :
Maintenant, à ce stade, nous nous appuyons uniquement sur la valeur aspect-ratio
pour redimensionner l'image. Et si nous redimensionnons le conteneur et que la mise en page de la carte se redistribue, la modification de la hauteur de l'image provoque des incohérences dans l'endroit où le dégradé devient blanc.
Nous ajouterons donc également une propriété max-height
qui utilise également la fonction max()
et contient des valeurs légèrement supérieures à celles du dégradé. Le comportement résultant est que le dégradé s'alignera (presque toujours) correctement avec le bas de l'image.
img { /* ...existing styles */ max-height: max(10rem, 30vh); }
Il est important de noter que l'ajout d'une `max-height` modifie le comportement `aspect-ratio`. Au lieu de toujours utiliser le rapport exact, il ne sera utilisé que lorsqu'il y aura suffisamment d'espace alloué compte tenu de la nouvelle contrainte supplémentaire de `max-height`.
"
Cependant, aspect-ratio
continuera à garantir que les images sont redimensionnées de manière cohérente, comme c'était le cas par rapport object-fit
uniquement. Essayez de commenter le aspect-ratio
dans la démo finale de CodePen pour voir la différence qu'il fait entre les tailles de conteneur.
Étant donné que notre objectif initial était d'activer des dimensions d'image toujours réactives , nous avons tout de même atteint le but. Pour votre propre cas d'utilisation, vous devrez peut-être jouer avec les valeurs de rapport et de hauteur pour obtenir l'effet souhaité.
Alternative : mix-blend-mode
et ajout d'un filtre
L'utilisation de overlay
comme valeur mix-blend-mode
était le meilleur choix pour l'effet de fondu au blanc que nous recherchions, mais essayons une autre option pour un effet plus dramatique.
Nous allons mettre à jour notre solution pour ajouter une propriété personnalisée CSS pour la valeur mix-blend-mode
et également mettre à jour les valeurs de couleur pour le dégradé :
.card { --card-gradient: tomato, orange; --card-blend-mode: multiply; } img { /* ...existing styles */ mix-blend-mode: var(--card-blend-mode); }
La valeur de multiply
a un effet d'assombrissement sur les tons moyens, mais conserve le blanc et le noir tels quels, ce qui donne l'apparence suivante :
Bien que nous ayons perdu le fondu et que nous ayons maintenant un bord dur au bas de l'image, la partie blanche de notre dégradé est toujours importante pour garantir que le dégradé se termine avant le contenu de la carte.
Une modification supplémentaire que nous pouvons ajouter est l'utilisation de filter
et, en particulier, utiliser la fonction grayscale()
pour supprimer les couleurs de l'image et donc faire du dégradé la seule source de coloration de l'image.
img { /* ...existing styles */ filter: grayscale(100); }
L'utilisation de la valeur de niveaux de grayscale(100)
entraîne la suppression complète des couleurs naturelles de l'image et sa transformation en noir et blanc. Voici la mise à jour pour comparaison avec la capture d'écran précédente de son effet lors de l'utilisation de notre dégradé orange avec multiply
:
Utiliser aspect-ratio
comme une amélioration progressive
Comme mentionné précédemment, aspect-ratio
n'est actuellement pris en charge que dans la dernière version des navigateurs Chromium (Chrome et Edge). Cependant, tous les navigateurs prennent en charge object-fit
et cela, avec nos contraintes de height
, donne un résultat moins idéal mais toujours acceptable, vu ici pour Safari :
Sans le fonctionnement du aspect-ratio
, le résultat ici est qu'en fin de compte, la hauteur de l'image est plafonnée, mais les dimensions naturelles de chaque image entraînent toujours une certaine variance entre les hauteurs d'image de la carte. Vous voudrez peut-être plutôt ajouter une max-height
ou utiliser à nouveau la fonction max()
pour aider à rendre une max-height
plus réactive sur différentes tailles de carte.
Extension des effets de dégradé
Puisque nous avons défini les arrêts de couleur de dégradé comme une propriété personnalisée CSS, nous avons un accès facile pour les modifier dans différents contextes. Par exemple, nous pouvons modifier le dégradé pour mettre davantage en valeur l'une des couleurs si la carte est survolée ou si l'un de ses enfants est mis au point.
Tout d'abord, nous allons mettre à jour chaque carte h3
pour qu'elle contienne un lien, tel que :
<h3><a href="">A Super Wonderful Headline</a></h3>
Ensuite, nous pouvons utiliser l'un de nos nouveaux sélecteurs disponibles - :focus-within
- pour modifier le dégradé de la carte lorsque le lien est mis au point. Pour une couverture supplémentaire des interactions possibles, nous couplerons ceci avec :hover
. Et, nous réutiliserons notre idée max()
pour attribuer une seule couleur pour prendre en charge la couverture de la partie image de la carte. L'inconvénient de cet effet particulier est que les arrêts de dégradé et les changements de couleur ne sont pas animables de manière fiable - mais ils le seront bientôt grâce à CSS Houdini.
Pour mettre à jour la couleur et ajouter le nouvel arrêt de couleur, il nous suffit de réaffecter la valeur de --card-gradient
dans cette nouvelle règle :
.card:focus-within, .card:hover { --card-gradient: #24a9d5 max(8.5rem, 20vh); }
Nos valeurs max()
sont inférieures à l'original utilisé pour white
afin de maintenir le bord biseauté. Si nous utilisions les mêmes valeurs, cela rencontrerait le white
et créerait une séparation clairement rectiligne.
Lors de la création de cette démo, j'ai initialement essayé un effet qui utilisait la transform
avec scale
pour un effet de zoom avant. Mais j'ai découvert qu'en raison de l'application mix-blend-mode
, le navigateur ne repeignait pas systématiquement l'image, ce qui provoquait un scintillement désagréable. Il y aura toujours des compromis à demander au navigateur d'effectuer des effets et des animations CSS uniquement, et même si c'est très cool ce que nous pouvons faire, il est toujours préférable de vérifier l'impact de vos effets sur les performances .
Amusez-vous à expérimenter !
Le CSS moderne nous a donné des outils impressionnants pour mettre à jour nos boîtes à outils de conception Web, aspect-ratio
étant le dernier ajout. Alors allez-y et expérimentez avec object-fit
, aspect-ratio
et ajoutez des fonctions comme max()
dans vos dégradés pour des effets réactifs amusants ! Assurez-vous simplement de vérifier les choses entre les navigateurs (pour l'instant !) Et dans différentes fenêtres d'affichage et tailles de conteneurs.
Voici le CodePen, y compris les fonctionnalités et les effets que nous avons examinés aujourd'hui :
Vous en voulez plus ? Assurez-vous de consulter notre guide CSS ici sur Smashing →