Images make or break a page. Product photos, profile pictures, blog thumbnails and hero banners all have to fit neatly into a design, but real photos come in every shape and size. Put a tall portrait and a wide landscape into the same card grid and, without CSS, one gets squashed and the other stretched.
Modern CSS gives you precise control. object-fit crops or fits a photo inside a box without distorting it, the way a photo frame works. object-position chooses which part of the photo stays visible. border-radius rounds the corners or makes a perfect circle, and filters such as grayscale(), blur() and brightness() change how an image looks without opening an image editor.
In this lesson you'll use all of these, plus overlays for captions on top of photos and smooth hover effects. The responsive images lesson then covers making images fluid and fast on every screen.
object-fit: fitting photos into boxes
| Value | Result |
|---|---|
fill | The default. The image stretches to the box's exact shape and may look distorted. |
cover | Fills the box completely and crops whatever doesn't fit. Best for thumbnails and banners. |
contain | Shows the whole image inside the box, leaving empty space if the shapes differ. Best for logos and product shots. |
none | Keeps the image's natural size and crops it. |
scale-down | Like contain, but never makes the image bigger than its natural size. |
object-fit only does something when the image box has a different shape from the photo, so pair it with a set width and height, or with aspect-ratio.
object-position
With object-fit: cover, the browser keeps the centre of the photo and crops the edges. object-position moves the focus:
img { object-fit: cover; object-position: top; } /* keep faces near the top */
img { object-fit: cover; object-position: 20% 80%; } /* a custom point */It works like background-position: keywords such as top, left and center, or percentages for exact control.
CSS filters
img { filter: grayscale(100%); }
img { filter: blur(4px); }
img { filter: brightness(1.2) contrast(1.1) saturate(1.3); }| Filter | What it does |
|---|---|
grayscale(100%) | Black and white |
sepia(100%) | Old-photo brown tone |
blur(4px) | Soft focus |
brightness(0.6) | Darker (below 1) or brighter (above 1) |
contrast(1.4) | More or less contrast |
saturate(2) | More or less colour |
hue-rotate(90deg) | Shifts every colour around the colour wheel |
drop-shadow(...) | A shadow that follows the shape of transparent PNGs and SVGs |
Combine several filters in one declaration, separated by spaces. backdrop-filter applies the same effects to whatever is behind an element, which creates the frosted glass look.
Rounded images and overlays
border-radius: 12px rounds the corners; border-radius: 50% on a square image makes a circle. For a caption on top of a photo, put the image and caption inside a position: relative wrapper, then place the caption with position: absolute. A dark gradient behind the caption keeps white text readable on any photo.
CSS Images Syntax
Image styling
.thumb { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; object-position: center; }
.logo { width: 120px; height: 60px; object-fit: contain; }
.avatar { width: 64px; height: 64px; border-radius: 50%; object-fit: cover; }
.muted { filter: grayscale(100%) brightness(0.9); }
.glass { backdrop-filter: blur(10px); }CSS Images Summary
object-fit: coverfills a box and crops;containfits the whole image inside.object-positiondecides which part of a cropped image stays visible.border-radius: 50%on a square image makes a circle.filterchanges how an image looks: grayscale, blur, brightness and more.- Overlays use a relative wrapper and an absolutely positioned caption.
CSS Images Examples
Each example runs in the page. Edit the code and press Run to see what changes.
object-fit compared
The same wide photo in three square boxes.
<div class="row">
<figure><img class="fill" src="https://picsum.photos/seed/lake/600/300" alt="Lake at sunrise" width="600" height="300"><figcaption>fill</figcaption></figure>
<figure><img class="cover" src="https://picsum.photos/seed/lake/600/300" alt="Lake at sunrise" width="600" height="300"><figcaption>cover</figcaption></figure>
<figure><img class="contain" src="https://picsum.photos/seed/lake/600/300" alt="Lake at sunrise" width="600" height="300"><figcaption>contain</figcaption></figure>
</div>.row { display: flex; gap: 12px; flex-wrap: wrap; font: 14px sans-serif; }
figure { margin: 0; text-align: center; }
img {
width: 140px;
height: 140px;
background: #e5e7eb;
border-radius: 10px;
}
.fill { object-fit: fill; }
.cover { object-fit: cover; }
.contain { object-fit: contain; }Line-by-line explanation
- Lines 5 to 6Each box is square, but the photo is twice as wide as it is tall.
- Line 11Fill squashes the photo into the square.
- Line 12Cover fills the square and crops the sides.
- Line 13Contain shows the whole photo with grey space above and below.
Filters and a hover effect
Hover over the photos.
<div class="gallery">
<img src="https://picsum.photos/seed/city/300/200" alt="City street" width="300" height="200">
<img src="https://picsum.photos/seed/forest/300/200" alt="Forest path" width="300" height="200">
<img src="https://picsum.photos/seed/beach/300/200" alt="Beach huts" width="300" height="200">
</div>.gallery { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; }
.gallery img {
width: 100%;
height: auto;
border-radius: 8px;
filter: grayscale(100%) brightness(0.9);
transition: filter 0.3s, transform 0.3s;
}
.gallery img:hover {
filter: none;
transform: scale(1.04);
}Line-by-line explanation
- Line 7Photos start in black and white and slightly darker.
- Line 8Filter and size changes animate smoothly.
- Lines 12 to 13On hover, the colour returns and the photo grows a little.
An avatar and a captioned card
<div class="person">
<img class="avatar" src="https://picsum.photos/seed/portrait/300/400" alt="Portrait of Ana" width="300" height="400">
<span>Ana Costa</span>
</div>
<figure class="card">
<img src="https://picsum.photos/seed/mountain/600/400" alt="Mountain lake" width="600" height="400">
<figcaption>Lake Bled, Slovenia</figcaption>
</figure>.person { display: flex; align-items: center; gap: 10px; font: 600 16px sans-serif; margin-bottom: 16px; }
.avatar {
width: 56px; height: 56px;
border-radius: 50%;
object-fit: cover;
object-position: top;
}
.card { position: relative; margin: 0; max-width: 360px; }
.card img { display: block; width: 100%; height: auto; border-radius: 12px; }
.card figcaption {
position: absolute; inset: auto 0 0 0;
padding: 24px 14px 12px;
color: white; font: 600 16px sans-serif;
background: linear-gradient(transparent, rgb(0 0 0 / 0.7));
border-radius: 0 0 12px 12px;
}Line-by-line explanation
- Lines 3 to 5A tall portrait becomes a neat circle without stretching.
- Line 6The top of the photo, where the face is, stays visible.
- Line 9The card is the positioning context for the caption.
- Line 12The caption sits along the bottom edge.
- Line 15A dark fade keeps the white text readable.
Common CSS Images Mistakes
Stretched thumbnails
.thumb { width: 200px; height: 200px; } /* photos of other shapes get distorted */.thumb { width: 200px; height: 200px; object-fit: cover; }Circle from a rectangle
.avatar { width: 80px; height: 60px; border-radius: 50%; } /* an oval */.avatar { width: 80px; height: 80px; border-radius: 50%; object-fit: cover; }A circle needs equal width and height.
Text in images instead of real text
/* a banner photo with "Summer sale" painted into the image */.banner { position: relative; }
.banner h2 { position: absolute; bottom: 20px; left: 20px; color: white; }Real text is searchable, translatable, readable by screen readers and sharp at any size.
CSS Images in Real Projects
Images on real sites
Online shops use object-fit: contain for product shots on white, so nothing is cropped, and cover for lifestyle photos. Social networks crop profile pictures into circles with object-fit: cover. News sites put headlines over photos with a gradient overlay, and photo galleries use grayscale-to-colour hover effects. backdrop-filter: blur() creates the frosted glass navigation bars seen in many modern apps.
CSS Images Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Fill the box and crop the image without stretching it.
.thumb {
object-fit: ;
}
cover fills the box and crops the extra.Which value shows the whole image without cropping?
How do you make a black and white image?
Which property keeps faces visible when a tall photo is cropped?
The avatar should be an 80px circle, cropped rather than stretched, and in black and white. Fix it.
<img class="av" src="https://picsum.photos/seed/av/200/300" alt="Avatar" width="200" height="300">.av {
width: 80px;
height: 60px;
border-radius: 5%;
object-fit: fill;
filter: sepia(100%);
}- Square 80px box
- Round
- Cropped, not stretched
- Black and white
CSS Images Quiz
5 questions to check what you learned.
What is the default object-fit value?
- cover
- fill
- contain
- auto
What does filter: brightness(0.5) do?
- Makes the image twice as bright
- Makes the image darker
- Removes colour
- Blurs the image
What does backdrop-filter affect?
- The element's own content
- Only images
- The page background colour
- What is behind the element
Why add a gradient behind a caption on a photo?
- It's required for figcaption
- It loads faster
- It keeps white text readable on light parts of the photo
- It makes the image smaller
Why add width and height attributes to img when CSS sets the size?
- The browser reserves space before the image loads, preventing layout jumps
- They override CSS
- They make the image sharper
- They're needed for object-fit
CSS Images Challenge
A product card image
- Make
.photowidth: 100%, with anaspect-ratioof1 / 1andobject-fit: cover - Round its corners with
border-radius: 12px - Make
.logouseobject-fit: contain - Make
.soldimagesgrayscale(100%)
<div style="width: 240px">
<img class="photo" src="https://picsum.photos/seed/shoe/400/300" alt="Running shoe" width="400" height="300">
<img class="photo sold" src="https://picsum.photos/seed/bag/400/300" alt="Leather bag" width="400" height="300">
<img class="logo" src="https://picsum.photos/seed/logo/300/100" alt="Brand logo" width="300" height="100" style="width: 120px; height: 120px">
</div>- Square cropped photo
- Fills the card width
- Rounded corners
- Logo is contained
- Sold photo is grey
height: auto for aspect-ratio to take over.