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.