CSS Image Sprites
Optional Advanced just covered !important — a rare override flag. This session is a different optional topic: image sprites. You will see them in older stylesheets and some legacy icon sets. The idea is simple: one picture file, many icons, with background-position choosing which tile peeks through a small window.
Direct answer
A CSS image sprite is a single sheet image that stores several icons (or button states) side by side. Each UI element gets a fixed width and height, the same background-image, and a background-position that slides the sheet until the wanted tile fills that box. Sprites cut request counts in the old “one file per icon” web. For new work, prefer SVG icons, inline SVG, or a small icon system — keep sprites when you maintain an existing sheet or must match a legacy design.
Why sprites existed
Years ago, every icon often meant another HTTP round-trip. Combining twenty tiny PNGs into one sheet meant one download and one cache entry. Browsers then painted different “windows” onto that sheet with CSS. HTTP/2 and modern bundling reduced that pain, and scalable vector icons usually look sharper — but the positioning pattern is still useful literacy when you open old CSS.
The three pieces
You need:
- One sheet — e.g.
icons.pngwith tiles laid out in a row or grid - A box —
widthandheightmatching one tile (often withdisplay: inline-blockor a block link) - An offset —
background-positionso the correct tile sits under the box
background-repeat: no-repeatkeeps the sheet from tiling. You are not loading a separate file per icon; you are cropping by position.
First tile on a shared sheet
Imagine a sheet where each icon is 32×32 pixels. The first icon sits at the top-left. The element’s box is 32×32, and the background starts at 0 0:
.icon {
display: inline-block;
width: 32px;
height: 32px;
background-image: url("icons.png");
background-repeat: no-repeat;
background-position: 0 0;
}
The box acts like a viewport. Only the top-left 32×32 of icons.png is visible. The rest of the sheet is there — just clipped by the element’s size.
Second icon: slide the sheet
If the next icon starts 32px to the right, move the background left by 32px (negative X). Same image, same box size, different window:
.icon-home {
display: inline-block;
width: 32px;
height: 32px;
background-image: url("icons.png");
background-repeat: no-repeat;
background-position: 0 0;
}
.icon-search {
display: inline-block;
width: 32px;
height: 32px;
background-image: url("icons.png");
background-repeat: no-repeat;
background-position: -32px 0;
}
Negative X pulls the sheet left so the second tile fills the window. A second row of icons would also change the Y value (for example -32px -32px). Measure from your real sheet — do not guess offsets from memory.
Hover from another tile
Button sets often put default and hover (or active) states on the same sheet. On :hover, change only background-position:
.btn-icon {
display: inline-block;
width: 40px;
height: 40px;
background-image: url("btn-sheet.png");
background-repeat: no-repeat;
background-position: 0 0;
}
.btn-icon:hover {
background-position: -40px 0;
}
No second image file — just another crop. Keep the box size stable so the control does not jump.
Calm sheet habits
Always pair the sheet with an explicit box and no-repeat. Name classes by role, not by pixel math alone:
.sprite {
display: inline-block;
background-image: url("icons.png");
background-repeat: no-repeat;
}
.sprite--mail {
width: 24px;
height: 24px;
background-position: 0 -48px;
}
.sprite--bell {
width: 24px;
height: 24px;
background-position: -24px -48px;
}
Document the tile grid in a short comment (tile size, row order) so the next maintainer is not reverse-engineering magic numbers.
Sprites then vs icons now
📊 Sprite sheets vs modern icon approaches
| Approach | Best when | Watch out |
|---|---|---|
| CSS image sprite (PNG sheet) | Legacy UI you must keep; one cached sheet already in the project | Raster scales poorly; offsets break if the sheet changes |
| Inline SVG / SVG sprite | Crisp UI icons at any size; easy theming with currentColor |
Slightly more markup or build setup |
| Icon font | Very old stacks that already ship one | Accessibility and ligature quirks; harder to theme than SVG |
| Separate PNG per icon | Rare one-off graphics | Many requests on old HTTP/1 connections |
Real <img> photos |
Content images, galleries, product shots | Not a job for background-position sprites |
Image gallery and responsive images lessons use real <img> (flex thumbs, object-fit, srcset). Sprites are usually decorative chrome in the background — not a substitute for meaningful content pictures with alt text.
Prefer modern icons for new UI
For a fresh interface, start with SVG (inline or a small SVG sprite system). You get sharper edges, simpler color changes, and no fragile pixel offsets. Reach for a classic PNG sprite only when the design pack is already a sheet, or when you are patching CSS that already depends on one.
/* Content photo — use <img>, not a sprite crop */
.hero-photo {
max-width: 100%;
height: auto;
}
/* UI chrome — sprite OK only if the sheet already exists */
.toolbar .icon-save {
width: 16px;
height: 16px;
background-image: url("legacy-toolbar.png");
background-repeat: no-repeat;
background-position: -64px 0;
}
Try it yourself
- Sketch a 3-icon row on paper (or open a real sprite). Note tile width (e.g. 32px).
- Create
.icon-awithbackground-position: 0 0and a matching box. - Add
.icon-bwith-32px 0(or your real second offset). - Add a hover rule that moves to a third tile without changing width/height.
- Write one sentence in a comment: why this sheet still exists (legacy) or why you would use SVG instead next time.
Common mistakes
- Putting content photos in a sprite and losing proper
alt/ semantics - Forgetting width and height so the whole sheet shows or nothing crops cleanly
- Using positive offsets when you meant to slide the sheet the other way
- Leaving
background-repeaton so tiles duplicate inside the box - Building a brand-new app on PNG sprites by default instead of SVG
- Copying offsets from a tutorial without measuring your sheet
Summary
- A sprite is one sheet;
background-positionchooses which tile fills a fixed box - Historically this reduced HTTP requests for many tiny icons
- Keep
no-repeat, stable sizes, and named roles; document the grid - Prefer SVG (or similar) for new UI; keep sprites for legacy sheets
- Content images stay real
<img>— galleries and responsive images are a different job - Optional Advanced continues next with multiple columns (
multi-column)
🧠 Test Your Knowledge
Test Your Knowledge
Challenge yourself with this interactive quiz and see how well you understand the topic
📝 Instructions
- Read each question carefully
- Select the best answer for each question
- You can retake the quiz as many times as you want
- Your progress will be shown at the top