Chapter 13: CSS Image Styling, Modals, Filters, Shapes & Masking
Images are central to web storytelling and visual impact. Mastering responsive scaling, aspect-ratio preservation with object-fit, real-time CSS graphics filters (blur, drop-shadow, grayscale), complex geometry clipping (clip-path), CSS gradient masking, and pure CSS image modals unlocks studio-grade image handling.
13.1 Responsive Images & object-fit / object-position
Making images responsive requires scaling down to fit small viewports while preventing aspect ratio distortion. The object-fit and object-position properties dictate how an image resizes inside a fixed container box.
| object-fit Value | Behavior & Aspect Ratio | Best Used For |
|---|---|---|
fill (Default) |
Stretches image to fill container; distorts aspect ratio! | Not recommended for photos. |
contain |
Scales image to fit inside container; preserves aspect ratio (letterboxing). | Logos, product thumbnails, diagrams. |
cover (Recommended) |
Fills entire container, cropping overflow; preserves aspect ratio. | Hero banners, user avatars, card thumbnails. |
none |
Ignores container dimensions; maintains original size. | Fixed 1:1 pixel assets. |
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
h3 { margin-top: 0; color: #38bdf8; }
.grid { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 14px; }
.card { background: #1e293b; border-radius: 10px; padding: 12px; flex: 1; min-width: 180px; }
.label { font-size: 11px; color: #64748b; font-family: monospace; display: block; margin-bottom: 8px; }
/* Fixed container size */
.img-box { width: 100%; height: 120px; border-radius: 8px; overflow: hidden; background: #334155; }
.img-box img { width: 100%; height: 100%; }
/* object-fit variations */
.fit-cover { object-fit: cover; object-position: center; }
.fit-contain { object-fit: contain; background: #0f172a; }
.fit-fill { object-fit: fill; }
</style>
</head>
<body>
<h3>object-fit & object-position Comparison</h3>
<p style="font-size:12px;color:#64748b;">Same 1:1 square SVG rendered inside a 16:9 fixed container box:</p>
<div class="grid">
<div class="card">
<span class="label">object-fit: cover (cropped, clean)</span>
<div class="img-box">
<img class="fit-cover" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Crect width='200' height='200' fill='%236366f1'/%3E%3Ccircle cx='100' cy='100' r='60' fill='%2338bdf8'/%3E%3C/svg%3E" alt="Demo" />
</div>
</div>
<div class="card">
<span class="label">object-fit: contain (letterboxed)</span>
<div class="img-box">
<img class="fit-contain" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Crect width='200' height='200' fill='%236366f1'/%3E%3Ccircle cx='100' cy='100' r='60' fill='%2338bdf8'/%3E%3C/svg%3E" alt="Demo" />
</div>
</div>
<div class="card">
<span class="label">object-fit: fill (stretched/distorted)</span>
<div class="img-box">
<img class="fit-fill" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Crect width='200' height='200' fill='%236366f1'/%3E%3Ccircle cx='100' cy='100' r='60' fill='%2338bdf8'/%3E%3C/svg%3E" alt="Demo" />
</div>
</div>
</div>
</body>
</html>
13.2 Image Filters & Visual Effects (filter)
The CSS filter property applies real-time graphical adjustments such as blurring, color shifting, brightness adjustments, and transparent PNG drop shadows directly GPU-accelerated by the browser.
| Filter Function | Syntax Example | Visual Effect Description |
|---|---|---|
blur(px) |
filter: blur(4px); |
Applies Gaussian blur (great for background frosted glass). |
grayscale(%) |
filter: grayscale(100%); |
Converts image to black & white (great for team member photo hover states). |
brightness(%) |
filter: brightness(150%); |
Increases or decreases image luminance. |
drop-shadow() |
filter: drop-shadow(0 4px 10px #38bdf8); |
Transparent SVG/PNG Shadow! Unlike box-shadow, follows actual transparent graphic outline shapes! |
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
h3 { margin-top: 0; color: #818cf8; }
.filter-grid { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 14px; }
.filter-card { text-align: center; background: #1e293b; border-radius: 10px; padding: 16px; flex: 1; min-width: 140px; }
.filter-label { font-size: 11px; color: #64748b; font-family: monospace; display: block; margin-top: 8px; }
.fx-normal { filter: none; }
.fx-blur { filter: blur(3px); }
.fx-gray { filter: grayscale(100%); transition: filter 0.3s; cursor: pointer; }
.fx-gray:hover{ filter: grayscale(0%); }
.fx-bright { filter: brightness(140%) contrast(120%); }
.fx-shadow { filter: drop-shadow(0 0 12px #38bdf8); }
</style>
</head>
<body>
<h3>CSS filter Property Gallery</h3>
<div class="filter-grid">
<div class="filter-card">
<svg class="fx-normal" width="60" height="60" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="%236366f1" /><polygon points="50,20 65,70 35,70" fill="%23f59e0b"/></svg>
<span class="filter-label">filter: none</span>
</div>
<div class="filter-card">
<svg class="fx-blur" width="60" height="60" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="%236366f1" /><polygon points="50,20 65,70 35,70" fill="%23f59e0b"/></svg>
<span class="filter-label">filter: blur(3px)</span>
</div>
<div class="filter-card">
<svg class="fx-gray" width="60" height="60" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="%236366f1" /><polygon points="50,20 65,70 35,70" fill="%23f59e0b"/></svg>
<span class="filter-label">grayscale(100%) (Hover me!)</span>
</div>
<div class="filter-card">
<svg class="fx-shadow" width="60" height="60" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="%236366f1" /><polygon points="50,20 65,70 35,70" fill="%23f59e0b"/></svg>
<span class="filter-label">drop-shadow(cyan glow)</span>
</div>
</div>
</body>
</html>
13.3 CSS Shapes & Clipping Paths (clip-path)
The clip-path property clips an element into geometric vector shapes (circles, ellipses, polygons, or SVG paths) without modifying the original image file.
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
h3 { margin-top: 0; color: #10b981; }
.shape-grid { display: flex; flex-wrap: wrap; gap: 20px; margin-top: 14px; }
.shape-box {
width: 110px; height: 110px;
background: linear-gradient(135deg, #6366f1, #38bdf8);
display: flex; align-items: center; justify-content: center;
font-weight: bold; font-size: 11px; text-align: center; color: #fff;
}
.label { font-size: 11px; color: #64748b; font-family: monospace; display: block; text-align: center; margin-top: 6px; }
/* clip-path shapes */
.clip-circle { clip-path: circle(50% at 50% 50%); }
.clip-triangle{ clip-path: polygon(50% 0%, 0% 100%, 100% 100%); }
.clip-star { clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%); }
.clip-hexagon { clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); }
</style>
</head>
<body>
<h3>clip-path Geometric Shapes</h3>
<div class="shape-grid">
<div>
<div class="shape-box clip-circle">Circle</div>
<span class="label">circle(50%)</span>
</div>
<div>
<div class="shape-box clip-triangle">Triangle</div>
<span class="label">polygon(triangle)</span>
</div>
<div>
<div class="shape-box clip-star">Star</div>
<span class="label">polygon(star)</span>
</div>
<div>
<div class="shape-box clip-hexagon">Hexagon</div>
<span class="label">polygon(hexagon)</span>
</div>
</div>
</body>
</html>
13.4 CSS Masking (mask-image & -webkit-mask-image)
CSS Masking uses an alpha channel gradient or PNG/SVG mask graphic to hide or reveal parts of an element based on transparency levels.
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
h3 { margin-top: 0; color: #f59e0b; }
/* Gradient Mask — fades element out towards bottom */
.masked-box {
width: 100%; max-width: 380px; height: 130px;
background: linear-gradient(135deg, #4f46e5, #06b6d4);
border-radius: 12px; padding: 20px;
-webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,1) 30%, rgba(0,0,0,0) 100%);
mask-image: linear-gradient(to bottom, rgba(0,0,0,1) 30%, rgba(0,0,0,0) 100%);
}
</style>
</head>
<body>
<h3>mask-image Alpha Gradient Masking</h3>
<p style="font-size:12px;color:#64748b;">The container below uses a linear-gradient mask to smoothly fade into transparency at the bottom:</p>
<div class="masked-box">
<h4 style="margin:0;color:#fff;">Fade Out Mask Effect</h4>
<p style="font-size:13px;color:#a5b4fc;margin-top:6px;">Notice how the text and background color gracefully fade away towards the bottom boundary using mask-image!</p>
</div>
</body>
</html>
13.5 Pure CSS Image Modal Lightbox Pattern
You can create a full-screen image lightbox popup using pure CSS :target selectors without writing any JavaScript code!
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
h3 { margin-top: 0; color: #38bdf8; }
/* Thumbnail trigger */
.thumb {
width: 120px; height: 90px;
background: linear-gradient(135deg, #6366f1, #38bdf8);
border-radius: 8px; display: inline-flex; align-items: center; justify-content: center;
color: #fff; font-weight: bold; font-size: 12px; text-decoration: none;
cursor: pointer; transition: transform 0.2s;
}
.thumb:hover { transform: scale(1.05); }
/* Pure CSS Modal overlay via :target */
.modal-overlay {
position: fixed; inset: 0;
background: rgba(15, 23, 42, 0.85);
backdrop-filter: blur(8px);
display: flex; align-items: center; justify-content: center;
opacity: 0; pointer-events: none; transition: opacity 0.3s;
z-index: 9999;
}
/* When URL hash matches modal ID (e.g. #img-modal), reveal overlay */
.modal-overlay:target {
opacity: 1; pointer-events: auto;
}
.modal-box {
background: #1e293b; border: 2px solid #38bdf8; border-radius: 12px;
padding: 24px; max-width: 380px; text-align: center; position: relative;
}
.close-btn {
position: absolute; top: 10px; right: 14px;
color: #ef4444; text-decoration: none; font-size: 20px; font-weight: bold;
}
</style>
</head>
<body>
<h3>Pure CSS Modal Lightbox (:target Pattern)</h3>
<p style="font-size:12px;color:#64748b;">Click the thumbnail to open modal popup without JavaScript:</p>
<a href="#img-modal" class="thumb">Click Thumbnail</a>
<!-- Target Modal Popup -->
<div id="img-modal" class="modal-overlay">
<div class="modal-box">
<a href="#" class="close-btn" title="Close">×</a>
<h4 style="margin-top:0;color:#38bdf8;">Modal Lightbox Popup</h4>
<p style="font-size:13px;color:#cbd5e1;">Opened using pure CSS <code>:target</code> rule when URL hash changes to #img-modal! Click × to close.</p>
</div>
</div>
</body>
</html>
13.5 Component Project: Glassmorphic Modal Dialog with Backdrop Blur
This component combines CSS filters, backdrop-filter: blur(), and gradient masks into a production modal popup overlay:
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body {
font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; margin: 0; padding: 24px;
min-height: 100vh; display: flex; align-items: center; justify-content: center;
background-image: radial-gradient(circle at 20% 30%, rgba(99,102,241,0.4), transparent 50%),
radial-gradient(circle at 80% 70%, rgba(16,185,129,0.3), transparent 50%);
}
.modal-overlay {
position: fixed; inset: 0; background: rgba(15, 23, 42, 0.6);
backdrop-filter: blur(8px); display: flex; align-items: center; justify-content: center; padding: 20px;
}
.glass-modal {
background: rgba(30, 41, 59, 0.7); backdrop-filter: blur(16px);
border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 16px;
padding: 32px; max-width: 420px; text-align: center;
box-shadow: 0 20px 50px rgba(0,0,0,0.5); filter: drop-shadow(0 10px 20px rgba(0,0,0,0.3));
}
.modal-title { margin: 0 0 12px; color: #38bdf8; font-size: 1.4rem; }
.modal-desc { font-size: 13px; color: #94a3b8; margin: 0 0 24px; line-height: 1.6; }
.btn-confirm {
background: linear-gradient(135deg, #6366f1, #06b6d4); color: #fff; border: none;
padding: 10px 24px; border-radius: 8px; font-weight: 700; font-size: 13px; cursor: pointer;
}
</style>
</head>
<body>
<div class="modal-overlay">
<div class="glass-modal">
<h3 class="modal-title">Confirm Action</h3>
<p class="modal-desc">Are you sure you want to apply these CSS backdrop filter transformations to your component library?</p>
<button class="btn-confirm">Confirm & Apply</button>
</div>
</div>
</body>
</html>
13.6 Interactive Sandbox — Image Styling & FX
Test clip-path, filter: drop-shadow, and mask-image live in the code playground below: