Written by Ivy Walobwa✏️
Reducing the number of page components in your application is essential to optimizing its performance. Images, for instance, can be combined into a single file to keep the number of components low.
CSS sprites are a combination of several images into a single larger image, also known as a sprite sheet. CSS styles are then used to display relevant images on the sprite sheet. Using CSS sprites in your application reduces the number of image components that need to be loaded, thus building your pages faster.
This tutorial will review how to create a sprite generator tool that can be used in combining images for your application. See the full code for this post here on GitHub.
Jump ahead:
- Understanding CSS sprites
- Create a CSS sprite generator tool
- Create the sprite sheet
- Download the sprite sheet
- Use the sprite sheet
Understanding CSS sprites
CSS sprite sheets combine several images into one file, also known as a sprite sheet. Images on a sprite sheet can be arranged horizontally, vertically, diagonally, or in rows and columns.
A single sprite sheet, instead of multiple images, is loaded into your application and the images on the file can be accessed using CSS positioning styles. The x
and y
coordinates of an image on the sprite sheet are determined and the image is displayed on the webpage using some styling.
Making an HTTP request is costly, and fetching several images from the server is costlier, which may affect the performance of your app, especially on heavy-traffic sites. Using CSS sprites is a common technique to optimize your site’s performance by reducing the number of requests made to fetch image components.
Some of the benefits of using CSS sprites include:
- Faster loading speed of your application because server requests are reduced: one sprite sheet request is made instead of several image requests
- The performance of your application is improved and an increased loading speed means a better user experience
- Reducing requests saves bandwidth, which is important for users with restricted data plans or slower internet connections
The image below shows an example of a sprite sheet used on Wikipedia’s homepage. The sprite elements are arranged vertically on the sheet: The sprite elements are then displayed on the page using background-image
and background-position
styles, as shown below: To generate sprites, you can make use of a CSS sprite generator tool. In the next section, I’ll walk you through the steps of creating such a tool.
Create a CSS sprite generator tool
We’ll create a simple CSS generator tool that allows you to upload several image files and generate a sprite sheet. The sprite sheet can then be downloaded and used to display images needed on your site.
The images below show the application preview. Images uploaded and the sprite sheet generated are previewed; we also generate the CSS styling needed to display a sprite element:
Getting started
In your HTML file, add the code snippet below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="author" content="Ivy Walobwa">
<meta name="description" content="CSS Sprite Generator">
<meta name="keywords" content="html, html5, css, javascript, sprite sheet, image map, icon map, generator, tool, online, converter">
<link rel="stylesheet" href="style.css">
<script src="index.js"></script>
<title>CSS Sprite Generator</title>
</head>
<body>
<h1>CSS Sprite Generator Tool</h1>
<div>
<p> Please upload your files</p>
<h3>Uploaded files</h3>
<input type="file" id="fileUploaderInput" name="file" multiple accept="image/png, image/jpeg, image/webp, image/gif, image/x-icon, image/bmp, image/tiff" >
<div id="sprite-preview">
</div>
</div>
<div class="section">
<h3>Sprite Preview</h3>
<button id="generateSpriteSheetButton">Generate Sprite Sheet</button>
<div id="sprite-sheet">
</div>
</div>
<div class="section">
<h3>Sprite Download</h3>
<button id="spriteSheetDownloadButton"> Download Sprite</button>
</div>
<div class="section">
<h3>CSS Styling</h3>
<div id="cssCode">
</div>
</body>
</html>
>
We’ve now added the elements needed to upload images, generate, and download the sprite sheet to the file. The image below shows the preview of our HTML file: Next, we’ll add some functionality to our app. Create an index.js
file and add the code snippet below. Here, we access elements in the DOM and add event listeners to the interactive elements. The createSpriteSheet
, downloadSprite
, and fileUploaderOnchange
methods will be described in the sections below:
let fileUploaderInput;
let generateSpriteSheetButton;
let spritePreview;
let spriteSheetContainer;
let spriteSheetDownloadButton;
let loadedImages = [];
let generatedSpriteSheet;
let cssCode;
window.onload = () => {
fileUploaderInput = document.getElementById('fileUploaderInput');
generateSpriteSheetButton = document.getElementById('generateSpriteSheetButton');
spritePreview = document.getElementById('sprite-preview');
spriteSheetContainer = document.getElementById('sprite-sheet');
spriteSheetDownloadButton = document.getElementById('spriteSheetDownloadButton');
cssCode = document.getElementById('cssCode');
generateSpriteSheetButton.addEventListener('click', (event) => createSpriteSheet(loadedImages))
spriteSheetDownloadButton.addEventListener('click', (event) => downloadSprite())
if (fileUploaderInput) {
fileUploaderInput.addEventListener('change', fileUploaderOnchange);
}
}
Upload images
In the index.js
file, create a fileUploaderOnchange
function and add the code snippet below:
const fileUploaderOnchange = (event) => {
const loadedFiles = Array.from(fileUploaderInput.files);
loadedFiles.forEach((file) => {
const reader = new FileReader();
reader.onload = (event) => {
// Create new image element and give it the source of our file and alt
const image = new Image();
image.src = event.target.result;
// When the image is loaded, create a canvas element and draw the image on it
image.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Set the canvas width and height
canvas.width = image.width * (100 / image.width);
canvas.height = image.height * (100 / image.height);
// Draw the image on the canvas
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
// Create a new image element and give it the source of our canvas
const newImage = new Image();
newImage.src = canvas.toDataURL();
newImage.alt = file.name.replace(/\.(png|jfif|pjpeg|jpeg|pjp|jpg|webp|gif|ico|bmp|dib|tiff|tif)$/, "");
spritePreview.appendChild(newImage);
loadedImages.push(image);
}
}
reader.readAsDataURL(file);
})
}
In this code block, we create an array of image files from the uploaded files. We then loop through each image and create a new FileReader
object.
Next, we create a new image from the uploaded file and create a 2D canvas and draw the image on it. Finally, we append a new image to our DOM and give it the canvas source.
Create the sprite sheet
Now that we have our image files uploaded, we can generate a sprite sheet. In the index.js
file, create the function createSpriteSheet
and add the code snippet below:
const createSpriteSheet = (images) => {
// Determine Sprite Sheet Dimensions
const totalImages = images.length;
// Calculate the minimum required dimensions for the sprite sheet
const cols = Math.ceil(Math.sqrt(totalImages));
const spriteHeight = Math.ceil(totalImages / cols) * images[0].height;
const spriteWidth = cols * images[0].width;
// Create Canvas
const canvas = document.createElement('canvas');
canvas.width = spriteWidth;
canvas.height = spriteHeight;
const ctx = canvas.getContext('2d');
// Arrange Images on Canvas
let x = 0;
let y = 0;
for (const image of images) {
ctx.drawImage(image, x, y);
x += image.width;
if (x >= spriteWidth) {
x = 0;
y += image.height;
}
}
// Generate CSS Styles
let cssStyles = '';
x = 0;
y = 0;
for (let i = 0; i < totalImages; i++) {
const image = images[i];
const className = `sprite-image-${i}`;
cssStyles += `
.${className} {
background-image: url('sprite-sheet.png')
background-position: ${x * -1}px ${y * -1}px;
width: ${image.width}px;
height: ${image.height}px;
}
<br>
`;
x += image.width;
if (x >= spriteWidth) {
x = 0;
y += image.height;
}
}
const newImage = new Image();
newImage.src = canvas.toDataURL();
newImage.alt = 'sprite-sheet';
spriteSheetContainer.appendChild(newImage);
generatedSpriteSheet = newImage
cssCode.innerHTML = cssStyles;
}
In the code block above, we determine the dimensions of our canvas by calculating the number of columns needed and the sprite width and height of our canvas. Our generator currently works best with square images of equivalent width and height.
Next, we create a 2D canvas with the dimensions we calculated and arrange the images on the canvas. We also generate the CSS styles to use for each image.
Finally, we create a new image and give it a URL of our sprite canvas. The sprite sheet image and CSS styles are added to the DOM.
Download the generated sprite sheet
To download the generated sprite, we’ll create a link
element and add the sprite image source as its href
, and invoke the link click:
const downloadSprite = () => {
// Create a link element
const link = document.createElement('a');
link.download = 'sprite-sheet.png';
// Add the image source to the link href
link.href = generatedSpriteSheet.src;
// Invoke the link click
link.click();
}
The image below shows the downloaded sprite sheet:
Use the sprite sheet
Now that you have generated your sprite sheet, you can load it into your app and use CSS styles to display the images. The background-image
, background-position
, width
, and height
properties are set to select a specific image on the sprite sheet:
<div class="sprite-image-0"></div>
<div class="sprite-image-1"></div>
.sprite-image-0 {
background-image: url('sprite-sheet.png');
background-position: 0px 0px;
width: 500px;
height: 500px;
}
.sprite-image-1 {
background-image: url('sprite-sheet.png');
background-position: -500px 0px;
width: 500px;
height: 500px;
}
Conclusion
In this tutorial, we discussed what a CSS sprite is and some of its benefits in improving app performance. We also created a simple CSS generator tool and learned how to use the generated sprite sheet in our app. The complete code used in this article is available on GitHub.
The technique used in this article is just one of many methods that can be used to reduce image components. By experimenting with different methods, you can decide which ones you prefer to optimize your app performance. Happy coding!
Is your frontend hogging your users' CPU?
As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web and mobile apps — Start monitoring for free.
Top comments (0)