Reference guide · images · Published 2026-08-16 · 4 min read
CSS object-fit and object-position for images
CSS object-fit cover, contain, fill, none and scale-down explained with object-position, aspect-ratio pairing and the CLS pitfalls to avoid.
- ·The five values
- ·Cropping with position
- ·Reserve the height
What object-fit does
object-fit tells the browser how to display an image inside its content box: cover, contain, fill, none, and scale-down. The image element keeps its layout size (the box from width/height/aspect-ratio) and object-fit decides what part of the image renders into that box.
| Value | Behaviour | Common use |
|---|---|---|
cover | Scale the image to fill the box; crop overflow so no box is empty | Card thumbs, hero, avatar, gallery tile |
contain | Scale to fit entirely inside the box, possibly leaving letterbox space | Product shots where nothing may be cut |
fill | Stretch/squash the image to the exact box size | The old default; distorts at odd ratios |
none | Ignore scaling; render at the image's natural size, clip the box | Mood pieces at natural detail |
scale-down | Equivalent of none or contain, whichever is smaller | Icons/logos |
An <img> with object-fit: contain does not re-layout the page; it only paints a smaller version inside the box, which is what the aspect-ratio article complements with the opposite technique (matching the box to the source).
Cropping with cover and object-position
The crop point defaults to the center. object-position moves it:
.thumb { object-fit: cover; object-position: 50% 20%; }
Percentages are positions in the box, not margins: 0% 0% is the top-left, 100% 100% the bottom-right, 50% 20% near the top center. Lining up a portrait face or a logo in the top-left of every card is the classic use. The background-position pairing article covers the background sibling for CSS backgrounds, which is the same positioned-crop concept on a different plate.
The cover vs contain trade-off
For a card with a fixed box, cover guarantees the box is full (no letterbox) at the cost of cropping; contain guarantees the entire image is visible at the cost of empty space. The choice is aesthetic unless the image is a screenshot or portrait where part of it matters: then contain is the honest answer and cover crops data, not just pixels.
The aspect-ratio pairing
object-fit sits well with a fixed aspect ratio so the box does not change with the source:
.card img {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
The aspect-ratio property reserves the height before the image loads. That removes the layout shift a tall/short image would otherwise cause when it pops in and the browser reflows the text below, which is exactly the CLS the metric punishes.
The shift trap
If you skip aspect-ratio and the source files differ in ratio, the box height jumps when each image loads: the classic card mesh that visibly rearranges. The two-part fix is always:
- Reserve the space:
aspect-ratio(or fixed height) on the element. - Fill it gracefully:
object-fit: coverso a wide and a tall image both fill the same box.
Where the exact intrinsic width is the old story, the srcset candidates should include a file close to the rendered width, and sizes matched to the box, so cover crops from a sensible source rather than from a scaled-down master (explained in the picker article).
When background is better
background-image with background-size: cover and background-position: center gives the same crop for decorative images, but none of the accessibility or SEO value of an img with alt. Choose img + object-fit for meaningful content, and background only for texture that never carries meaning. The background LCP article covers how background images cannot be preloaded and load late, which is a real LCP cost when one fills the hero.