Images, Filters, and Blend Modes
Prerequisites: Backgrounds, gradients, and shadows, Sizing elements
object-fit and object-position
When an image is given a size with a different aspect ratio,
object-fit decides how it fills the box:
.thumb {
width: 100%;
aspect-ratio: 1;
object-fit: cover;
object-position: center 30%;
}
.logo {
width: 10rem;
height: 4rem;
object-fit: contain;
}
| Value | Result |
|---|---|
fill (default) |
Stretch to the box — distorts |
cover |
Fill the box, cropping the overflow |
contain |
Fit entirely inside, leaving empty space |
none |
Natural size, cropped |
scale-down |
The smaller of none and contain |
Works on img, video, and other replaced elements.
Filters
.muted { filter: grayscale(100%); }
.muted:hover { filter: none; }
.soft { filter: blur(2px) brightness(1.1); }
.icon-shadow { filter: drop-shadow(0 2px 4px rgb(0 0 0 / 30%)); }
.glass {
background: rgb(255 255 255 / 60%);
backdrop-filter: blur(12px);
}
filterfunctions:blur(),brightness(),contrast(),grayscale(),sepia(),saturate(),hue-rotate(),invert(),opacity(),drop-shadow().backdrop-filterblurs what's behind a translucent element — the "frosted glass" effect. Keep text contrast in mind.
Blend modes and masks
.duotone { background: url("/img/team.jpg") center / cover, teal; background-blend-mode: multiply; }
.headline-over-image { mix-blend-mode: difference; color: white; }
.fade-bottom { mask-image: linear-gradient(to bottom, black 70%, transparent); }
.avatar { clip-path: circle(50%); }
.ribbon { clip-path: polygon(0 0, 100% 0, 90% 50%, 100% 100%, 0 100%); }
background-blend-modeblends an element's background layers;mix-blend-modeblends the element with what's under it.mask-imagehides parts of an element using the alpha channel of an image or gradient.clip-pathcuts the element to a shape.
image-set()
Choose background images by resolution or format:
.hero {
background-image: image-set(
url("/img/hero.avif") type("image/avif"),
url("/img/hero.jpg") type("image/jpeg")
);
}
Checking the result
<style>
img { width: 200px; height: 200px; object-fit: cover; filter: grayscale(1) contrast(1.2); }
</style>
<img src="photo.jpg" alt="Example" width="400" height="300">
<script>
const s = getComputedStyle(document.querySelector("img"));
console.log(s.objectFit, s.width, s.height, s.filter);
</script>
cover 200px 200px grayscale(1) contrast(1.2)
CSS width and height override the HTML attributes for display, but
keeping the attributes still gives the browser the aspect ratio early.