Complete CSS Course Module 11: Intermediate: Floats and Visual Effects

CSS Image Sprites

  • Beginner
  • Lesson 11.7
  • 6 min read
  • 48 of 77 in the course

In short

CSS image sprites combine many small images into one file and show each part with background-position. Learn how sprites work, build a sprite icon nav, and use modern SVG sprites. What is an image sprite and why was it used?

CSS image sprites combine many small images into one file and show each part with background-position. Learn how sprites work, build a sprite icon nav, and use modern SVG sprites.

What is an image sprite and why was it used?

An image sprite is one image file that holds many small pictures side by side, like a sheet of stickers. Instead of loading ten icon files, the page loads one sheet, and CSS shows only the part it needs for each element, like looking at one sticker through a small window.

Sprites became popular because of how the web used to work. With the old HTTP/1.1 protocol, each image file meant a separate request to the server, and browsers could only make a few requests at once. Ten small icons meant ten slow round trips. One sprite meant one. Games used the same idea for character animations, which is where the name comes from.

Today, HTTP/2 and HTTP/3 can download many small files in parallel, so the speed benefit is much smaller. But you'll still see sprites in older sites and some games, and the technique teaches you a lot about background-position.

The background-position technique

Here is a sprite sheet, described as a grid. Each icon is 32 by 32 pixels. The top row shows the gray "normal" versions, and the bottom row shows the colored "hover" versions:

x:  0px        32px       64px
  +----------+----------+----------+
  |  circle  |  square  | triangle |  y: 0px   (gray)
  +----------+----------+----------+
  |  circle  |  square  | triangle |  y: 32px  (colored)
  +----------+----------+----------+

To show one icon, you:

  1. Make an element exactly the size of one icon (32 by 32 pixels).
  2. Set the whole sprite as its background-image.
  3. Move the sheet with background-position so the icon you want sits in the "window".

The position values are usually negative, because you slide the sheet left and up. To show the square in the top row, slide the sheet 32px to the left: background-position: -32px 0;. For the colored triangle: background-position: -64px -32px;.

Iconbackground-position
Gray circle0 0
Gray square-32px 0
Gray triangle-64px 0
Colored circle0 -32px
Colored square-32px -32px
Colored triangle-64px -32px

Build a sprite-based icon navigation

Let's build it. To keep the example copy-paste ready, the sprite is a small SVG written straight into the CSS as a data URL. In a real project it would usually be a file like url("images/icons-sprite.png").

<nav class="sprite-nav">
  <a class="home" href="/">Home</a>
  <a class="shop" href="/shop">Shop</a>
  <a class="about" href="/about">About</a>
</nav>
.sprite-nav {
  display: flex;
  gap: 24px;
}

.sprite-nav a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px;
  color: #334155;
  text-decoration: none;
}

.sprite-nav a::before {
  content: "";
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='64'%3E%3Cg fill='%2394a3b8'%3E%3Ccircle cx='16' cy='16' r='10'/%3E%3Crect x='38' y='6' width='20' height='20'/%3E%3Cpolygon points='80,6 90,26 70,26'/%3E%3C/g%3E%3Ccircle cx='16' cy='48' r='10' fill='%23ef4444'/%3E%3Crect x='38' y='38' width='20' height='20' fill='%2322c55e'/%3E%3Cpolygon points='80,38 90,58 70,58' fill='%233b82f6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
}

.home::before  { background-position-x: 0; }
.shop::before  { background-position-x: -32px; }
.about::before { background-position-x: -64px; }

.sprite-nav a:hover::before,
.sprite-nav a:focus-visible::before {
  background-position-y: -32px;
}

You'll see three links, each with a gray icon in front: a circle for Home, a square for Shop, a triangle for About. When you hover over a link (or reach it with the Tab key), its icon changes to the colored version instantly. There's no flicker, because the hover image is already loaded: it's the same file. That instant hover was a big reason people loved sprites.

The code uses background-position-x and background-position-y, which set each direction separately. Each link sets only its column (x), and the hover rule changes only the row (y). One rule handles the hover for every icon.

Common mistake: Making the element bigger than one icon, for example 40px wide for 32px icons. Then the window shows part of the next icon too. The element (or its ::before) must match the icon size exactly, or use background-size carefully if you scale the sprite.

Note: For sharp sprites on high-resolution screens, people used to make the PNG twice as big and scale it down with background-size (for example a 192 by 128 file shown at background-size: 96px 64px). All the positions stay the same.

Modern alternative: SVG sprites with use

Today, the best way to bundle icons is an SVG sprite. You put all your icons once in a hidden <svg> as <symbol> elements, each with an id. Then you show any icon anywhere with <use>.

<svg width="0" height="0" style="position: absolute" aria-hidden="true">
  <symbol id="icon-heart" viewBox="0 0 24 24">
    <path d="M12 21s-7-4.5-9.5-9A5.5 5.5 0 0 1 12 6a5.5 5.5 0 0 1 9.5 6C19 16.5 12 21 12 21z"/>
  </symbol>
  <symbol id="icon-star" viewBox="0 0 24 24">
    <path d="M12 2l3 6.5 7 .8-5.2 4.8 1.5 7L12 17.6 5.7 21.1l1.5-7L2 9.3l7-.8z"/>
  </symbol>
</svg>

<button class="like">
  <svg class="icon"><use href="#icon-heart"></use></svg>
  Like
</button>
<button class="like">
  <svg class="icon"><use href="#icon-star"></use></svg>
  Favorite
</button>
.like {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  color: #64748b;
  background: white;
  border: 1px solid #e2e8f0;
  border-radius: 999px;
}

.like:hover {
  color: #e11d48;
}

.icon {
  width: 20px;
  height: 20px;
  fill: currentColor;
}

You'll see two pill buttons with a heart and a star. On hover, both the text and the icon turn pink, because the icon uses fill: currentColor, as you saw in the CSS Icons lesson. Each icon's path is written only once, in the hidden sprite, and reused with <use href="#icon-heart">.

Why SVG sprites beat image sprites:

  • Icons are sharp at every size, with no need for 2x images.
  • You change colors with CSS, so you don't need a second row of hover images.
  • No position math: you pick icons by name, not by pixel offset.

Tip: You can also keep the SVG sprite in a separate file and use <use href="icons.svg#icon-heart">. The file must come from the same website (same origin), and the browser caches it for every page.

Practice exercise

Design your own 3-icon sprite on paper first: decide the grid, icon size and every background-position. Then build a "social links" bar with three links that use the data-URL sprite from this lesson, and add a fourth link that uses an SVG sprite icon with <use>. Compare how much code each method needs to add a hover color.

Hint: write your position table first, like the one in this lesson, before you write any CSS.

Key takeaways

  • An image sprite is one image containing many icons; CSS shows one part through a small "window".
  • Use an element the size of one icon and negative background-position values to choose the icon.
  • background-position-x and -y let you set the column and row separately, which makes hover states easy.
  • Sprites saved server requests under HTTP/1.1; with HTTP/2 and HTTP/3 the benefit is small.
  • The modern choice is an SVG sprite with <symbol> and <use>, styled with currentColor.