Cours CSS / images et vidéos adaptatives : aspect-ratio et object-fit

Les médias adaptatifs nécessitent à la fois une taille d'élément sensée et une règle délibérée pour ajuster son contenu. aspect-ratio aide à établir les proportions d'une boîte, tandis que object-fit: cover ou contain détermine si une image ou une vidéo remplit ou s'adapte à cette boîte.

Séparer les dimensions intrinsèques et la taille d'affichage

Si l'original fait 400×300, le rapport est de 4:3. Si la largeur d'affichage est de 288px et en gardant les mêmes proportions, la hauteur d'affichage est de 216px. Les attributs width et height en HTML fournissent des informations sur la taille et le rapport de l'image, et le CSS contrôle la taille à afficher sur la page. Plutôt que de résoudre le problème en supprimant la propriété de taille dans le HTML, vérifiez quelle valeur est écrasée dans le CSS.

img { max-width: 100%; height: auto; }
/* Instead of forcing the small original size to grow, it is reduced to fit the parent. */

max-width: 100% est une limite supérieure qui empêche qu'il devienne plus large que son parent et n'augmente pas de manière inconditionnelle le petit original. width: 100% est une spécification qui remplit la largeur du parent, donc il peut être agrandi au-delà de l'original. La netteté de la photo et la taille du téléchargement sont des problèmes distincts. Vous pouvez télécharger des fichiers volumineux même s'ils semblent petits avec CSS, et lorsque vous utilisez srcset · sizes, le navigateur sélectionne une image parmi les candidats, donc vous devez vérifier la taille affichée sur l'écran et le fichier réellement sélectionné.

Utilisez aspect-ratio pour le redimensionnement automatique

aspect-ratio: 16 / 9 utilise le rapport de 16 de largeur sur 9 de hauteur pour calculer la taille. Si la largeur est de 288px, la hauteur est de 162px. Au moins une dimension doit être automatique pour que des calculs proportionnels puissent être effectués, et si la largeur et la hauteur sont toutes deux fixes, cette taille fixe prévaut même si vous saisissez cette propriété. Vous pouvez également vérifier les conditions de calcul de la taille selon le ratio de MDN.

.thumbnail { width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
.gallery { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-start; }

L'alignement Flexbox, le retour à la ligne, l'espacement (gap), l'agrandissement (grow) et la réduction (shrink) peuvent égaler la hauteur des images sur la même ligne. Pour calculer automatiquement la hauteur lors du placement d'images avec des ratios originaux différents côte à côte, vérifiez également le align-items: flex-start du parent ou le align-self de l'élément. Si le ratio semble identique après avoir changé uniquement la hauteur en automatique, la règle d'alignement du parent peut en être la cause.

En pratique, la propriété box-sizing est unifiée en border-box. Lors de l'ajout de bordures ou de marges internes, il devient important de mesurer la taille et les proportions de la boîte. Les images dans les exemples de comparaison ci-dessous n'ont ni bordures ni marges internes pour éviter toute confusion.

Comparer le comportement d'ajustement et de recadrage

valeur de l'attribut ratio d'origine zone d'affichage détail
fill Peut être agrandi pour s'adapter à la zone Remplit la boîte Distorsion possible selon l'original
cover maintenir Remplir sans espace vide Si le rapport est différent, certaines parties sont coupées.
contain maintenir Ajuster pour que tout tienne Si le rapport est différent, un espace vide reste

Adapter une image 4:3 dans une boîte 16:9 avec cover coupe le haut et le bas. Le positionnement centré partage la coupe entre les deux ; object-position: center top préserve le haut et coupe davantage en bas. Vérifiez le contenu important sur les bords avant de choisir une coupe. Les arrière-plans CSS utilisent des choix d'ajustement similaires mais ont un rôle de contenu et d'accessibilité différent des images HTML. Voir Couleurs et images de fond CSS : cover et contain.

Le schéma suivant illustre la même image de pratique géométrique à son ratio original, avec cover, contain et cover aligné en haut. Comparez les bandes de bord vertes et rouges ainsi que l'espace vide sur les côtés. Le cercle central reste visible dans ces exemples, donc les bandes de bord facilitent l'identification du recadrage. L'exemple HTML complet ci-dessous vous permet de reproduire la comparaison.

La même image 4:3 est entière au ratio d’origine ; cover centré coupe les bandes du haut et du bas, contain conserve toute l’image avec des marges latérales, et cover aligné en haut conserve la bande verte.

Exécutez la comparaison des quatre images

Enregistrez cet exemple sous image-ratio.html et ouvrez-le. L’image originale est fournie sous forme de données SVG dans le fichier, sans ressource externe. Les attributs HTML width et height conservent les dimensions d’origine 400×300 ; les règles CSS déterminent les dimensions et les proportions de la boîte affichée.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>image-ratio.html</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font: 1rem/1.6 sans-serif; color: #243447; }
h1, h2, p { margin-top: 0; } a { color: #145f8f; }
a:focus-visible, button:focus-visible, input:focus-visible { outline: 3px solid #ac4100; outline-offset: 3px; }
main { width: min(100%, 65rem); margin-inline: auto; padding: 1rem; }
.gallery { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-start; }
.sample { width: min(100%, 18rem); margin: 0; }
.sample img { display: block; width: 100%; height: auto; background: #e2e2e2; }
.sample p { margin: .5rem 0 0; } .cover, .contain { aspect-ratio: 16 / 9; }
.cover { object-fit: cover; } .contain { object-fit: contain; }
.top { object-position: center top; }
</style>
</head>
<body>
<main><h1>Compare the size and cropping of the same picture</h1><div class="gallery"><div class="sample"><img class="" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="Top green band, bottom red band and center orange circle"><p>Original 4:3</p></div>
<div class="sample"><img class="cover" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="Top green band, bottom red band and center orange circle"><p>16:9 cover, center</p></div>
<div class="sample"><img class="contain" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="Top green band, bottom red band and center orange circle"><p>16:9 contain</p></div>
<div class="sample"><img class="cover top" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="Top green band, bottom red band and center orange circle"><p>16:9 cover, top</p></div>
</div></main>
</body>
</html>
  1. Sur les écrans larges, assurez-vous que la largeur de chaque image est limitée à 18rem. Avec une police racine de 16px, cela fait 288px de large, l'original mesure 216px de haut, et la zone restante au format 16:9 mesure 162px de haut.
  2. Modifiez uniquement la hauteur de .sample img à 300px. Même si le ratio 16:9 est appliqué, vérifiez que la zone est de 288×300px en raison de la hauteur fixe, et restaurez-la à auto.
  3. Modifiez uniquement l'align-items de .gallery à stretch. Assurez-vous que la hauteur du conteneur pour la même ligne est la même, mais que les proportions de l'image à l'intérieur du conteneur sont maintenues, puis revenez à flex-start. Dans cet exemple, l'élément Flex est un conteneur d'exemple, pas une image. Dans les configurations où les images sont placées directement comme éléments Flex, la hauteur automatique peut augmenter, donc l'alignement doit être vérifié.
  4. Changez uniquement object-position de .top en center bottom. Cette fois, assurez-vous que la bande rouge reste et que la bande verte soit coupée, puis rétablissez-la en center top.

Le SVG dans l'exemple a également la caractéristique de maintenir les proportions des formes. Si la zone d'affichage d'un élément image est incorrecte et crée un espace vide, le cercle ne sera pas nécessairement déformé. Au lieu de se limiter à regarder la forme, vérifiez la largeur et la hauteur de l'élément img dans les outils de développement.

Redimensionnez le contenu vidéo à l'intérieur de sa boîte d'affichage

Dans l'exercice ci-dessous, le fichier vidéo d’exemple de 400×300, sans son, est affiché avec object-fit: contain dans une zone 16:9. Il n'y a pas d'audio ni d'informations de sous-titres dans la vidéo, seulement le mouvement du cercle orange, qui est utilisé pour vérifier les espaces en haut, en bas et sur les côtés ainsi que les opérations de lecture. L'adresse du fichier vidéo WebM pour la pratique est incluse dans l'exemple. Dans un environnement sans réseau, téléchargez ce fichier et placez-le dans le même dossier que le HTML, en remplaçant l'adresse source par le nom du fichier.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>video-ratio.html</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font: 1rem/1.6 sans-serif; color: #243447; }
h1, h2, p { margin-top: 0; } a { color: #145f8f; }
a:focus-visible, button:focus-visible, input:focus-visible { outline: 3px solid #ac4100; outline-offset: 3px; }
main { width: min(100%, 34rem); margin-inline: auto; padding: 1rem; }
video { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: contain; background: #111; }
</style>
</head>
<body>
<main><h1>Video display ratio</h1>
<p id="video-description">This silent sample video shows an orange circle moving on a blue background. Play and pause it to compare aspect ratios.</p>
<video controls preload="metadata" width="400" height="300" aria-describedby="video-description">
  <source src="https://www.codingfactory.net/wp-content/uploads/css-media-ratio-motion-v1.webm" type="video/webm">
  <a href="https://www.codingfactory.net/wp-content/uploads/css-media-ratio-motion-v1.webm">Download the sample video</a>
</video></main>
</body>
</html>

L’attribut controls permet à l'utilisateur d'utiliser les opérations du navigateur telles que lecture/pause, et preload="metadata" est un indice qui demande que les informations méta soient lues avant la lecture. La méthode de téléchargement réelle est déterminée par votre navigateur. Comme nous n'avons pas inclus la lecture automatique, appuyez sur le bouton de lecture pour confirmer. Si vous ne changez que object-fit en cover, vous pouvez voir la différence dans le fait que la zone reste la même et que le contenu du haut et du bas est coupé. Après confirmation, rétablissez à contain.

object-fit ajuste le contenu dans les éléments remplacés tels que les images et les vidéos. Il ne dimensionne pas le contenu iframe d'une vidéo intégrée de la même manière : donnez à cet iframe un conteneur correctement proportionné et dimensionnez-le à l'intérieur du conteneur. Contrairement à cet exemple décoratif silencieux, une vidéo avec un son significatif nécessite des alternatives appropriées, comme des sous-titres. Voir MDN : object fit, MDN : video.