Back to Blog
CSSAspect RatioLayoutResponsive

CSS aspect-ratio Property

Master the CSS aspect-ratio property. From basic usage to responsive images to layout patterns.

B
Bootspring Team
Engineering
December 31, 2020
6 min read

The aspect-ratio property maintains element proportions without padding hacks. Here's how to use it.

Basic Usage#

1/* Simple aspect ratio */ 2.video { 3 aspect-ratio: 16 / 9; 4 width: 100%; 5} 6 7/* Square */ 8.avatar { 9 aspect-ratio: 1; 10 /* Same as: aspect-ratio: 1 / 1; */ 11 width: 100px; 12} 13 14/* Portrait */ 15.card { 16 aspect-ratio: 3 / 4; 17 width: 300px; 18} 19 20/* Common ratios */ 21.widescreen { 22 aspect-ratio: 16 / 9; /* 1.78:1 */ 23} 24 25.cinema { 26 aspect-ratio: 21 / 9; /* 2.33:1 */ 27} 28 29.standard { 30 aspect-ratio: 4 / 3; /* 1.33:1 */ 31} 32 33.golden { 34 aspect-ratio: 1.618 / 1; /* Golden ratio */ 35}

With Images#

1/* Maintain aspect ratio for images */ 2.image-container { 3 aspect-ratio: 16 / 9; 4 width: 100%; 5 overflow: hidden; 6} 7 8.image-container img { 9 width: 100%; 10 height: 100%; 11 object-fit: cover; 12} 13 14/* Different fit modes */ 15.cover { 16 object-fit: cover; /* Fills container, may crop */ 17} 18 19.contain { 20 object-fit: contain; /* Fits inside, may letterbox */ 21} 22 23.fill { 24 object-fit: fill; /* Stretches to fill */ 25} 26 27/* Position within container */ 28.image-container img { 29 object-fit: cover; 30 object-position: center top; /* Focus on top */ 31}

Responsive Patterns#

1/* Change aspect ratio at breakpoints */ 2.hero { 3 aspect-ratio: 16 / 9; 4 width: 100%; 5} 6 7@media (max-width: 768px) { 8 .hero { 9 aspect-ratio: 4 / 3; 10 } 11} 12 13@media (max-width: 480px) { 14 .hero { 15 aspect-ratio: 1 / 1; 16 } 17} 18 19/* With container queries */ 20.card-container { 21 container-type: inline-size; 22} 23 24.card-image { 25 aspect-ratio: 16 / 9; 26} 27 28@container (max-width: 300px) { 29 .card-image { 30 aspect-ratio: 1; 31 } 32}

Grid Layouts#

1/* Grid of consistent cards */ 2.grid { 3 display: grid; 4 grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); 5 gap: 1rem; 6} 7 8.grid-item { 9 aspect-ratio: 4 / 3; 10 background: #f0f0f0; 11 border-radius: 8px; 12} 13 14/* Grid with featured item */ 15.featured-grid { 16 display: grid; 17 grid-template-columns: repeat(3, 1fr); 18 gap: 1rem; 19} 20 21.featured { 22 grid-column: span 2; 23 grid-row: span 2; 24 aspect-ratio: 1; 25} 26 27.regular { 28 aspect-ratio: 1; 29} 30 31/* Masonry-like with aspect ratio */ 32.masonry { 33 display: grid; 34 grid-template-columns: repeat(3, 1fr); 35 gap: 1rem; 36} 37 38.tall { 39 aspect-ratio: 3 / 4; 40} 41 42.wide { 43 aspect-ratio: 4 / 3; 44 grid-column: span 2; 45} 46 47.square { 48 aspect-ratio: 1; 49}

Video Embeds#

1/* Responsive video container */ 2.video-wrapper { 3 aspect-ratio: 16 / 9; 4 width: 100%; 5} 6 7.video-wrapper iframe, 8.video-wrapper video { 9 width: 100%; 10 height: 100%; 11 border: none; 12} 13 14/* Different video formats */ 15.vertical-video { 16 aspect-ratio: 9 / 16; 17 max-width: 400px; 18} 19 20.standard-video { 21 aspect-ratio: 4 / 3; 22} 23 24.cinema-video { 25 aspect-ratio: 21 / 9; 26}

Card Components#

1/* Card with image */ 2.card { 3 display: flex; 4 flex-direction: column; 5 border-radius: 8px; 6 overflow: hidden; 7 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); 8} 9 10.card-image { 11 aspect-ratio: 16 / 9; 12} 13 14.card-image img { 15 width: 100%; 16 height: 100%; 17 object-fit: cover; 18} 19 20.card-content { 21 padding: 1rem; 22} 23 24/* Horizontal card */ 25.card-horizontal { 26 display: grid; 27 grid-template-columns: 200px 1fr; 28} 29 30.card-horizontal .card-image { 31 aspect-ratio: 1; 32} 33 34/* Card with overlay */ 35.card-overlay { 36 position: relative; 37 aspect-ratio: 16 / 9; 38} 39 40.card-overlay img { 41 width: 100%; 42 height: 100%; 43 object-fit: cover; 44} 45 46.card-overlay .overlay { 47 position: absolute; 48 inset: 0; 49 background: linear-gradient(to top, rgba(0,0,0,0.8), transparent); 50 display: flex; 51 align-items: flex-end; 52 padding: 1rem; 53}

Skeleton Loaders#

1/* Loading placeholders */ 2.skeleton { 3 background: linear-gradient( 4 90deg, 5 #f0f0f0 25%, 6 #e0e0e0 50%, 7 #f0f0f0 75% 8 ); 9 background-size: 200% 100%; 10 animation: shimmer 1.5s infinite; 11} 12 13@keyframes shimmer { 14 0% { background-position: 200% 0; } 15 100% { background-position: -200% 0; } 16} 17 18.skeleton-image { 19 aspect-ratio: 16 / 9; 20 border-radius: 8px; 21} 22 23.skeleton-avatar { 24 aspect-ratio: 1; 25 border-radius: 50%; 26 width: 50px; 27} 28 29.skeleton-card { 30 aspect-ratio: 4 / 3; 31 border-radius: 8px; 32}

With Flexbox#

1/* Flex container with aspect ratio children */ 2.gallery { 3 display: flex; 4 flex-wrap: wrap; 5 gap: 1rem; 6} 7 8.gallery-item { 9 flex: 1 1 200px; 10 aspect-ratio: 1; 11 min-width: 150px; 12 max-width: 300px; 13} 14 15/* Flex with different ratios */ 16.mixed-gallery { 17 display: flex; 18 gap: 1rem; 19 height: 400px; 20} 21 22.portrait { 23 flex: 0 0 auto; 24 aspect-ratio: 3 / 4; 25 height: 100%; 26} 27 28.landscape { 29 flex: 1; 30 aspect-ratio: 16 / 9; 31 align-self: center; 32}

Min/Max Constraints#

1/* With size constraints */ 2.constrained { 3 aspect-ratio: 16 / 9; 4 width: 100%; 5 max-width: 800px; 6 min-width: 300px; 7} 8 9/* Height constraint */ 10.max-height { 11 aspect-ratio: 16 / 9; 12 width: 100%; 13 max-height: 400px; 14} 15 16/* Auto height fallback */ 17.flexible { 18 aspect-ratio: 16 / 9; 19 min-height: auto; /* Allows content to expand */ 20}

Intrinsic Sizing#

1/* Natural size with aspect ratio */ 2.natural { 3 aspect-ratio: 16 / 9; 4 width: max-content; 5} 6 7/* Fit content */ 8.fit { 9 aspect-ratio: 1; 10 width: fit-content; 11 max-width: 100%; 12} 13 14/* Clamp sizing */ 15.clamped { 16 aspect-ratio: 16 / 9; 17 width: clamp(300px, 50vw, 800px); 18}

Replaced Elements#

1/* Images with aspect ratio */ 2img { 3 aspect-ratio: attr(width) / attr(height); 4 width: 100%; 5 height: auto; 6} 7 8/* Prevent layout shift */ 9img[width][height] { 10 aspect-ratio: attr(width) / attr(height); 11} 12 13/* Video elements */ 14video { 15 aspect-ratio: 16 / 9; 16 width: 100%; 17 height: auto; 18} 19 20/* Canvas */ 21canvas { 22 aspect-ratio: 4 / 3; 23 width: 100%; 24}

Browser Support Fallback#

1/* Old padding-bottom hack as fallback */ 2.video-wrapper { 3 position: relative; 4 width: 100%; 5 padding-bottom: 56.25%; /* 16:9 */ 6} 7 8.video-wrapper iframe { 9 position: absolute; 10 top: 0; 11 left: 0; 12 width: 100%; 13 height: 100%; 14} 15 16/* Modern browsers */ 17@supports (aspect-ratio: 16 / 9) { 18 .video-wrapper { 19 padding-bottom: 0; 20 aspect-ratio: 16 / 9; 21 } 22 23 .video-wrapper iframe { 24 position: static; 25 } 26}

CSS Variables#

1/* Dynamic aspect ratios */ 2:root { 3 --ratio-square: 1; 4 --ratio-portrait: 3 / 4; 5 --ratio-landscape: 4 / 3; 6 --ratio-video: 16 / 9; 7 --ratio-cinema: 21 / 9; 8} 9 10.square { aspect-ratio: var(--ratio-square); } 11.portrait { aspect-ratio: var(--ratio-portrait); } 12.landscape { aspect-ratio: var(--ratio-landscape); } 13.video { aspect-ratio: var(--ratio-video); } 14.cinema { aspect-ratio: var(--ratio-cinema); } 15 16/* Per-element custom ratio */ 17.custom { 18 --custom-ratio: 5 / 3; 19 aspect-ratio: var(--custom-ratio); 20}

Best Practices#

Layout: ✓ Use for consistent image containers ✓ Combine with object-fit for images ✓ Set fallbacks for older browsers ✓ Consider content overflow Performance: ✓ Prevents layout shift (CLS) ✓ Reserve space before loading ✓ Use with width/height attributes ✓ Avoid unnecessary reflows Responsive: ✓ Change ratios at breakpoints ✓ Use container queries when appropriate ✓ Combine with clamp() for fluid sizing ✓ Test on various devices Accessibility: ✓ Ensure content remains visible ✓ Don't hide overflow important content ✓ Test with zoom/text scaling ✓ Maintain readability

Conclusion#

The aspect-ratio property simplifies responsive layouts by maintaining element proportions without padding hacks. Use it for images, videos, cards, and grids. Combine with object-fit for images and provide fallbacks for older browsers.

Share this article

Help spread the word about Bootspring