What CSS object-fit does and why you care
object-fit tells the browser how to resize the contents of a replaced element (usually an
<img> or <video>)
when the element’s box has a different aspect ratio than the media inside it.
In plain English: it’s how you choose between “crop to fill” (cover), “fit inside”
(contain), or “don’t resize” (none)
when an image is forced into a fixed-sized frame.
One important gotcha: object-fit does not apply to CSS background images.
If you’re styling background-image, you want background-size: cover or
background-size: contain instead.
Learn more about CSS backgrounds in the CSS Background Interactive Tutorial.
CSS object-fit property and options
The most common values are cover and contain, but there are a few more that are handy in
specific situations.
Object-fit values explained
-
fill(default): stretches the media to match the element’s width and height. This can distort the image. -
cover: fills the box while preserving aspect ratio. Crops the parts that don’t fit. -
contain: fits the entire media inside while preserving aspect ratio. Leaves empty space if needed. -
none: does not resize the media. Uses its intrinsic size. -
scale-down: picks the smaller result betweennoneandcontain.
Interactive object-fit switcher
This playground uses radio buttons to flip the value instantly (and yes, fill is included so you can
see the “squish”).
.media {
object-fit: cover;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
display: grid;
gap: 12px;
}
.card {
border: 3px solid #111;
border-radius: 18px;
overflow: hidden;
background: #fff;
box-shadow: 0 12px 0 #111;
}
.top {
height: 220px;
background: #f6f6f6;
}
.media {
width: 100%;
height: 100%;
display: block;
}
.body {
padding: 14px;
display: grid;
gap: 8px;
}
.body h4 {
margin: 0;
font-size: 18px;
}
.body p {
margin: 0;
line-height: 1.4;
}
![]()
Same frame, different fit
This image is forced into a fixed-height header. Your
object-fitchoice decides if it crops, letterboxes, stretches, or stays intrinsic.
CSS object-fit: cover
cover is the “make it look good in a card/hero” option. It preserves the image’s aspect ratio and fills
the box completely.
Anything that doesn’t fit gets cropped away.
If you’ve ever said “I want it to behave like a background image cover, but for an <img>”, this
is it.
.thumb img {
object-fit: cover;
}
.thumb img {
object-fit: cover;
object-position: 20% 40%;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
display: grid;
gap: 12px;
}
.row {
display: grid;
gap: 12px;
}
@media (min-width: 820px) {
.row {
grid-template-columns: 1fr 1fr;
align-items: start;
}
}
.thumb {
border: 3px solid #111;
border-radius: 18px;
overflow: hidden;
box-shadow: 0 12px 0 #111;
background: #f6f6f6;
height: 260px;
}
.thumb img {
width: 100%;
height: 100%;
display: block;
}
.note {
border: 2px dashed #111;
border-radius: 14px;
padding: 12px;
background: #fff;
}
Tip:
coverusually pairs withobject-positionwhen you want to “aim” the crop.![]()
With
object-fit: cover, the image fills the box. Since the photo is portrait and the frame is landscape, it must crop.Switch snippets to move the “focus point” using
object-position.
CSS object-fit: contain
contain is the “show me the entire image, no cropping” option.
It preserves aspect ratio and fits the whole media inside the box.
The trade-off is empty space (often called letterboxing or pillarboxing) when the aspect ratios don’t match. That’s not a bug, that’s the point.
.frame img {
object-fit: contain;
}
.frame img {
object-fit: contain;
background: #111;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
display: grid;
gap: 12px;
}
.frame {
width: min(560px, 100%);
height: 300px;
border: 3px solid #111;
border-radius: 18px;
overflow: hidden;
background: #f6f6f6;
box-shadow: 0 12px 0 #111;
margin: 0;
}
.frame img {
width: 100%;
height: 100%;
display: block;
}
.note {
border: 2px dashed #111;
border-radius: 14px;
padding: 12px;
background: #fff;
}
containis great for logos, product photos, screenshots, and anything where cropping would be inappropriate.![]()
CSS object-position with object-fit
object-position controls which part of the media is shown when the media doesn’t perfectly
match the element’s box.
It matters most when:
-
You use
object-fit: cover(because cropping happens). -
You use
object-fit: none(because the media can overflow and you’re choosing what stays visible).
Object-fit cover position and “center”
When people say “object-fit center”, they usually mean:
object-fit: cover plus object-position: center.
The default object-position is already 50% 50% (center), but changing it is how you aim
the crop.
Interactive object-position sliders
Drag the sliders to move the crop around. This playground edits the two values of object-position (x
and y).
.hero img {
object-fit: cover;
object-position: 50% 50%;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
display: grid;
gap: 12px;
}
.hero {
border: 3px solid #111;
border-radius: 18px;
overflow: hidden;
box-shadow: 0 12px 0 #111;
background: #f6f6f6;
height: 280px;
}
.hero img {
width: 100%;
height: 100%;
display: block;
}
.note {
border: 2px dashed #111;
border-radius: 14px;
padding: 12px;
background: #fff;
}
With
cover, changingobject-positionis like moving a camera window across a big photo.![]()
Notice that only Object Position Y has an effect here, because the photo is tall and the frame is wide. The X position doesn’t matter when the media fills the box horizontally.
CSS object-fit not working
When object-fit “does nothing”, it’s almost always one of these issues. Let’s make them visible.
1) The image doesn’t have a real box to fit into
object-fit matters when the element has a constrained size (especially height).
If your image is just width: 100% with height: auto, it will keep its natural aspect ratio
and there is nothing to “fit”.
2) You’re trying it on the wrong thing
-
Works on:
<img>,<video>, and other replaced elements. -
Does not work on: a regular
<div>withbackground-image. Usebackground-sizethere.
.bg {
background-size: cover;
background-position: center;
}
.bg {
background-size: contain;
background-position: center;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
display: grid;
gap: 12px;
}
.bg {
height: 260px;
border: 3px solid #111;
border-radius: 18px;
overflow: hidden;
box-shadow: 0 12px 0 #111;
background-color: #f6f6f6;
background-repeat: no-repeat;
background-image: url("https://picsum.photos/1200/800");
}
This is a background image, so we use
background-size, notobject-fit.
Quick “make it work” checklist
-
Give the element a constrained box: set both
widthandheight(or useaspect-ratio). -
Set the media to fill that box:
img { width: 100%; height: 100%; } -
Then apply:
object-fit: cover;orcontain. -
If the crop looks “wrong”, adjust:
object-position.
Practical patterns you’ll use all the time
Pattern: responsive thumbnail with aspect-ratio
A very clean approach is to define the frame using aspect-ratio, then let the image fill it with
object-fit.
.thumb {
aspect-ratio: 16 / 9;
}
.thumb img {
object-fit: cover;
}
.thumb {
aspect-ratio: 1 / 1;
}
.thumb img {
object-fit: cover;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
display: grid;
gap: 12px;
}
.thumb {
width: min(360px, 100%);
border: 3px solid #111;
border-radius: 18px;
overflow: hidden;
box-shadow: 0 12px 0 #111;
background: #f6f6f6;
}
.thumb img {
width: 100%;
height: 100%;
display: block;
}
.note {
border: 2px dashed #111;
border-radius: 14px;
padding: 12px;
background: #fff;
}
Switch snippets to change the frame shape. The image behavior stays consistent.![]()
Learn more about aspect-ratio in the CSS Aspect Ration Interactive Tutorial.
Pattern: avatar that never distorts
Avatars are the classic “circle crop” case. This is basically cover plus a round frame.
.avatar img {
object-fit: cover;
object-position: center;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
display: grid;
gap: 12px;
}
.row {
display: flex;
gap: 12px;
align-items: center;
}
.avatar {
width: 96px;
height: 96px;
border: 3px solid #111;
border-radius: 999px;
overflow: hidden;
background: #f6f6f6;
box-shadow: 0 10px 0 #111;
flex: 0 0 auto;
}
.avatar img {
width: 100%;
height: 100%;
display: block;
}
.card {
border: 3px solid #111;
border-radius: 18px;
padding: 12px 14px;
background: #fff;
display: grid;
gap: 6px;
width: min(520px, 100%);
}
.card h4 {
margin: 0;
font-size: 16px;
}
.card p {
margin: 0;
line-height: 1.4;
}
![]()
Avatar crop
object-fit: coverkeeps faces from becoming pancakes.
Wrap-up: the object-fit mental model
Remember the simple recipe:
-
Make a frame (set
heightoraspect-ratio). -
Make the media fill the frame (
width: 100%andheight: 100%). -
Choose the behavior:
coverto fill and crop,containto fit and letterbox. -
If the crop needs aiming, tweak
object-position(often “center” or a percentage).
