The Fluid Image Baseline
The single most important CSS rule for responsive images — include it in every project:
img, video, canvas, svg {
max-width: 100%; /* never wider than container */
height: auto; /* maintain aspect ratio */
display: block; /* remove inline gap below image */
}
max-width: 100% lets images shrink below their natural size but never grow beyond it. height: auto maintains the original aspect ratio as width changes.
object-fit – Controlling Image Display in a Box
object-fit controls how a replaced element (<img>, <video>) fills its container — the same way background-size works for background images.
/* fill — stretches to fill (default, may distort) */
img { object-fit: fill; }
/* cover — fills while maintaining ratio, may crop */
img { object-fit: cover; }
/* contain — fits entirely inside, may have empty space */
img { object-fit: contain; }
/* none — original size, clipped if overflows */
img { object-fit: none; }
/* scale-down — whichever of none/contain is smaller */
img { object-fit: scale-down; }
/* Most common pattern: fixed-size image thumbnail */
.avatar {
width: 64px;
height: 64px;
border-radius: 50%;
object-fit: cover; /* crop to circle, no distortion */
}
/* Card image with fixed height */
.card-image {
width: 100%;
height: 220px;
object-fit: cover; /* always fills the height, crops sides */
}
object-position – Focal Point Control
/* Default: center center */
img { object-fit: cover; object-position: center; }
/* Position the image within its box */
img { object-position: top; } /* show top of image */
img { object-position: bottom right; } /* show bottom-right of image */
img { object-position: 20% 30%; } /* 20% from left, 30% from top */
/* Person portrait — keep face visible when cropping */
.person-photo {
object-fit: cover;
object-position: top center; /* prioritize the face at the top */
}
aspect-ratio – Prevent Layout Shift
Setting a fixed aspect ratio reserves space for an image before it loads — preventing Cumulative Layout Shift (CLS), a Core Web Vital metric.
/* aspect-ratio: width / height */
.hero-image { aspect-ratio: 16 / 9; }
.thumbnail { aspect-ratio: 4 / 3; }
.avatar { aspect-ratio: 1 / 1; } /* square */
.banner { aspect-ratio: 3 / 1; } /* wide banner */
/* Combined with object-fit for responsive images */
.card-image {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
/* Reserve space before image loads (prevents CLS) */
img {
width: 100%;
aspect-ratio: attr(width) / attr(height); /* uses HTML width/height attrs */
}
Add width and height attributes to every <img> tag matching the image's natural dimensions. The browser uses these to reserve the correct space before the image loads, eliminating layout shift. With height: auto in CSS, the image still scales responsively — the attributes are just hints for the browser.
srcset – Serving Different Resolutions
The HTML srcset attribute lets you provide multiple image files for different screen sizes or resolutions. The browser picks the most appropriate one.
<!-- Width descriptors — browser chooses based on display width and DPR -->
<img
src="hero-800.jpg"
srcset="
hero-400.jpg 400w,
hero-800.jpg 800w,
hero-1200.jpg 1200w,
hero-1600.jpg 1600w
"
sizes="
(max-width: 600px) 100vw,
(max-width: 1200px) 80vw,
1200px
"
alt="Hero image"
width="1200"
height="675"
loading="lazy"
>
<!-- DPR (device pixel ratio) descriptors — for retina screens -->
<img
src="logo.png"
srcset="logo.png 1x, logo@2x.png 2x, logo@3x.png 3x"
alt="ylearner"
width="160"
height="40"
>
The <picture> Element – Art Direction
Use <picture> when you want to show a different image crop or composition at different screen sizes — not just different resolutions of the same image.
<picture>
<!-- WebP for modern browsers (smaller file size) -->
<source
type="image/webp"
srcset="hero-mobile.webp 400w, hero-desktop.webp 1200w"
sizes="(max-width: 768px) 100vw, 1200px"
>
<!-- JPEG fallback -->
<source
type="image/jpeg"
srcset="hero-mobile.jpg 400w, hero-desktop.jpg 1200w"
sizes="(max-width: 768px) 100vw, 1200px"
>
<!-- Fallback img (always required) -->
<img src="hero-desktop.jpg" alt="Hero" width="1200" height="600" loading="lazy">
</picture>
<!-- Art direction: different crop on mobile -->
<picture>
<source media="(max-width: 767px)" srcset="team-portrait.jpg">
<source media="(min-width: 768px)" srcset="team-landscape.jpg">
<img src="team-landscape.jpg" alt="The team" width="1200" height="630">
</picture>
Lazy Loading
<!-- Native lazy loading — supported in all modern browsers -->
<img src="image.jpg" alt="..." loading="lazy">
<!-- eager — load immediately (use for above-the-fold images) -->
<img src="hero.jpg" alt="..." loading="eager">
<!-- fetchpriority — hint for above-fold images (LCP) -->
<img src="hero.jpg" alt="..." fetchpriority="high" loading="eager">
The Largest Contentful Paint (LCP) image — usually the hero or first visible image — should have loading="eager" and fetchpriority="high". Lazy-loading it delays the page's most important visual element and hurts your Core Web Vitals score. Only use loading="lazy" on images below the fold.
Modern Image Formats
FORMAT COMPRESSION TRANSPARENCY ANIMATION BROWSER SUPPORT
JPEG Lossy No No Universal
PNG Lossless Yes No Universal
GIF Lossless 1-bit Yes Universal (avoid — use WebP/AVIF)
WebP Lossy/Loss. Yes Yes All modern browsers (2020+)
AVIF Lossy/Loss. Yes Yes Chrome/Firefox/Safari (2022+)
SVG Vector Yes Yes Universal
RECOMMENDATION:
- Photos: WebP (primary) + JPEG (fallback via <picture>)
- Icons/UI: SVG (scalable, tiny file size)
- Screenshots: WebP or PNG
- Animations: WebP or CSS animations (not GIF)
- Cutting edge: AVIF (50% smaller than WebP for photos)
📋 Summary
- Fluid baseline:
img { max-width: 100%; height: auto; display: block; } - object-fit: cover — fills fixed-size container without distortion, crops if needed.
- object-position — controls crop focal point (default: center).
- aspect-ratio — reserves space before image loads, prevents layout shift.
- srcset + sizes — serve different resolutions; browser picks the best one.
- <picture> — serve different crops (art direction) or different formats (WebP/JPEG).
- loading="lazy" — defer off-screen images. Use
eagerfor above-fold. - fetchpriority="high" — prioritize the LCP image.
- WebP — use as primary format for photos. Smaller than JPEG, transparent like PNG.
Frequently Asked Questions
They work the same way but apply to different things. object-fit applies to replaced elements — <img>, <video>, <canvas> — controlling how the element's content fills its box. background-size applies to CSS background images. Both support the same values: cover, contain, explicit sizes. Use <img> with object-fit for content images (accessible, indexable by search engines, can be lazy-loaded). Use background-image for purely decorative images.
Use srcset + sizes (on a regular <img>) when you have the same image at different resolutions — the browser picks the best size for the screen. Use <picture> when: (1) you want to serve different image formats (WebP with JPEG fallback), or (2) you want art direction — a different crop or composition at different screen sizes. In practice, most images need srcset for resolution switching and picture for format selection.
Three things: (1) Always set width and height attributes on <img> tags matching the image's natural dimensions. (2) Add height: auto in your CSS reset so the image still scales responsively. (3) Optionally add aspect-ratio in CSS as a backup. The browser uses the HTML dimensions to reserve the correct space in the layout before the image loads, eliminating the reflow that causes CLS.