CSS Object-fit and Object-position
object-fit controls how replaced elements like <img> and <video> scale inside their container. object-position sets where that scaled content is positioned within the same space.
Theory
TL;DR
- Picture a photo frame:
covercrops the image to fill the frame;containshrinks it so you see all of it, with empty space on the sides object-fithandles the sizing strategy;object-positionhandles alignment (same idea asbackground-position, but for<img>)- Only works on replaced elements (
<img>,<video>), not on<div> - Default is
fill, which stretches the image and distorts aspect ratio - Decision rule: hero images use
cover; thumbnails usecontain
Quick example
.card-image {
width: 300px;
height: 200px;
object-fit: cover; /* Scale up, crop overflow */
object-position: center; /* Keep the center of the image visible */
}A 400x400 square image in this 300x200 box scales up, crops equally from top and bottom, and stays centered. No distortion. This is the core pattern.
Key difference
object-fit picks the scaling strategy: stretch, shrink-to-fit, crop-to-fill, or keep original size. object-position then shifts the result inside the box using coordinates like 50% 30% or keywords like top right. Without explicit object-fit, the browser uses fill by default, which ignores aspect ratio. object-position only has an effect after the fit is applied.
When to use
- Hero banner, no distortion:
object-fit: cover; object-position: center - Gallery thumbnails, full image visible:
object-fit: contain; object-position: center - Profile avatar cropped to face:
object-fit: cover; object-position: 50% 30%(eyes near top) - Video in letterbox mode:
object-fit: contain - Logo at original size, no upscale:
object-fit: none
Comparison table
| Value | Scales | Aspect ratio | Crops | Fills box | Use when |
|---|---|---|---|---|---|
fill | Stretches to 100% | Distorts | No | Yes | Pixel art where distortion is acceptable |
contain | Fits fully inside | Preserved | No (letterbox) | No | Thumbnails, full-image previews |
cover | Scales to fill | Preserved | Yes (overflow hidden) | Yes | Hero images, cards, avatars |
none | No scaling | Preserved | Possible | No | Logos, original size matters |
scale-down | Caps at original size | Preserved | No | No | Large images that should not upscale |
Common mistakes
1. Applying object-fit to a <div>
/* Wrong: object-fit is ignored on non-replaced elements */
.box {
object-fit: cover;
background: url(img.jpg); /* Has no effect */
}
/* Right: use background-size for divs */
.box {
background: url(img.jpg) center / cover no-repeat;
}2. Forgetting width and height on the image
/* Wrong: no dimensions, object-fit has nothing to work with */
.container { height: 200px; }
img { object-fit: cover; }
/* Right */
img {
width: 100%;
height: 100%;
object-fit: cover;
}The image needs explicit dimensions. Without them, it renders at its natural size and object-fit does nothing visible. This is the top reported bug for this property.
3. Portrait image in a landscape box with cover - unexpected side crop
cover crops whichever dimension overflows. A tall portrait in a wide box loses the sides. Fix: object-position: center top to keep heads in frame.
Real-world usage
- Next.js
<Image>withfilllayout usesobject-fit: coverinternally for responsive crops - TailwindCSS ships
object-cover,object-contain,object-centerclasses, used across hundreds of thousands of projects - Video.js uses
object-fit: containfor responsive video embeds - For decorative backgrounds on divs, use
background-size: cover.object-*is reserved for semantic images withalttext
Follow-up questions
Q: What is the default value of object-fit?
A: fill. It stretches the image to match width and height exactly, which distorts aspect ratio.
Q: How does object-position: bottom differ from object-position: 50% 100%?
A: They are the same. Keywords map to percentages: top = 50% 0%, bottom = 50% 100%, center = 50% 50%.
Q: Does object-fit work on <canvas> or <svg>?
A: On <svg> inserted as a replaced element via <img src="icon.svg">, yes. <canvas> requires manual scaling in JavaScript.
Q: What happens when the browser does not know the image's intrinsic size yet, for example during lazy load?
A: The browser defaults to 300x150px. object-fit computes on that placeholder, then recomputes when the image loads. Without aspect-ratio on the container, you get layout shift. Pair object-fit with aspect-ratio on the wrapper to prevent it.
Examples
Hero banner with cover
.hero {
width: 100%;
height: 500px;
overflow: hidden;
}
.hero img {
width: 100%;
height: 100%;
object-fit: cover; /* Fill without distortion */
object-position: center; /* Center the crop point */
}The image fills the full width at any viewport size. Whatever the original dimensions are, the browser scales and crops automatically. This is the pattern behind every full-width banner you see.
User avatar with face focus
.avatar {
width: 80px;
height: 80px;
border-radius: 50%;
overflow: hidden;
}
.avatar img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center 30%; /* Crop point in upper third - eyes stay in the circle */
}The 30% from top shifts the crop upward. A face stays centered in the circle instead of showing forehead or chin.
Gallery with aspect-ratio lock
.gallery-item {
width: 100%;
aspect-ratio: 16 / 9; /* Box shape independent of image dimensions */
overflow: hidden;
}
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
transition: transform 0.3s;
}
.gallery-item:hover img {
transform: scale(1.05);
}Pairing aspect-ratio with object-fit: cover removes fixed height values entirely. The box holds its 16:9 shape; the image fills it at any viewport size.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.