No, it’s not about a lemon-flavored sugary drink. Today we will tell you about an interesting tech solution for the frontend — sprites.
Sprite is a 2D image, containing a collection of more images. Sprites are fairly often used in computer graphics, especially in video games. Here, for example, is the sprite of Megaman:
However, the sprite doesn’t render on the screen all at once, just its parts: either one after another within the same element if it’s an animation or through assigning different parts to different objects on the screen.
— Well, that’s how it worked for 8-bit consoles with their hardware limitations. What does it have to do with modern web frontend?
Thing is, sprites are put to a good use there as well. Web app interface often utilizes lots of small images and the first things coming to mind are surely icons.
If you store icons as separate graphics, the browser will have to make an HTTP request to get a file of each icon. The browser allows only a limited number of simultaneous HTTP-connections, so until the first few icons are received from the server, the following ones will not even start to be requested. It all leads to terrible delays and slows page loading, even if the size of these icons is minimal — it takes much more time to process the request than to transfer data.
Another problem with icons in web projects is about the need to support a large number of files. Writing the code, you will have to assign the file names, track the picture sizes, and organize the work with the source files somehow in case you need to edit the icons. And there are always a lot of them — easily over a hundred.
Here sprites come to save the day.
If you combine icons in a sprite file, you can get them from the server in one query. It is also much easier to store, connect and use a single picture than a few dozen. The main reason we use sprites is to keep the code and the file repository neat and clean.
Here is an icon sprite from one of our projects:
How to display a sprite icon on a screen? Relatively easy:
The trick is for all the icons to use the very same background image, which is moved around by background-position property so that the necessary part is visible:
If you have another look at the sprite, you can notice that there’s a grid there (in this case the grid step is 30 pixels).
First of all, such a grid teaches the designer order and precision — icons from the same set must have the same “visual weight”. Placing the icons into equal “boxes” makes it easier to achieve a visual match.
Secondly, it is easier to position the icons on the page relative to other elements. When all the icons are the same small squares of 30×30 pixels in size, they will move the text by the same distance, and everything will be perfectly aligned.
And thirdly, the grid helps to write CSS rules for icons: you do not need to measure the background offset in the graphics editor, it’s enough to count how many grid cells fit between it and the edge of the sprite. Look at the pencil icon: its offset is easy to calculate — 7 cells horizontally and 3 cells vertically, that is, 210 (30 × 7) and 90 (30 × 3) pixels, and the resulting code would be: background-position: -210px -90px;
Please, pay attention to the following area:
This group of icons is smaller than the others, but they stand on the same 30-pixel grid as the rest. Why so? To facilitate sprite support. If you ever need to replace the icons with those of a standard size (or just make them slightly larger), there will be no need to move the adjacent icons. And a value for the backround-position is easier to calculate.
For example, the code for the icon of a small handset will be as follows:
Here we specify the size, because it is non-standard.
If you don’t use the grid and just put the icons closer to each other, very soon the CSS rules will turn into some magic numbers and sprite editing — into the endless rounds of fixing the slipping icons.
Another advice: always leave a couple pixels of space around the icon. This rule applies to the icons in general, whether you put them into a sprite or store them in a bulk. Some icons take up less space than others, and therefore must be larger for optical compensation — in such cases it will be possible to use this additional space:
When it comes to sprites, this empty space is especially important. In image scaling (for example, when the user zooms in on their smartphone screen) a browser applies a certain filter to smooth the outcome. Therefore a pixel grid might appear around the icons’ edges due to the smoothing of adjoining icons. Here, for example, is a piece of navigation menu from bike-centre.ru:
— How do you suggest we work with all this? The picture changed — rebuild the whole sprite? Added a new icon — rebuild the whole sprite once again?
Of course not. We create the sprite as soon as we start coding and store its vector source code (it can be .psd, or .sketch, or anything else) directly in the repo, so that any developer is able to add icons if needed. Version control is also good for sprites.
— Icon fonts are always of perfect quality because they are vector assets. How do these sprites look on retina screens?
With their small size, icon fonts are sensitive to rasterization algorithms and render differently in different browsers and operating systems. Due to this, the icons can get distorted and look sloppy. It does not happen to raster graphics, they render pixel-perfect. This is important to perfectionists. You’re a perfectionist, aren’t you?
To make a sprite for retina devices, just create a copy of a double size sprite picture and add the following line to SCSS:
420px and 210px here are the sizes of a regular (1x) sprite.
— You build sprites manually? But there are web pack plugins!
Automated building of sprites solves only half of the problem: it allows you to load all images from the server in one request. But the developers still have to keep hundreds of small images in their repository and somehow work with them. If these pictures are of different sizes — the resulting icons will be of different sizes, with all the ensuing consequences. And if you need support for retina screens, you will have to support twice as many images or search for a smart collector plugin, which builds versions for retina and non-retina on its own. And you’ll have to hope that it does it right. Well, you know what I mean.
— Do you still use PNG? SVG icons can be inserted into the code, with no external files or additional calls to the server. And they can be recolored using style attributes. What do you say to that?
PNG can also be recolored directly in CSS, just set the sprite as mask-image, not background-image (and, obviously, adjust it using mask-position instead of background-position). Inline SVG has the same problem as the automated sprite building: you need to keep a lot of pictures in the repository in order to feed them to the collector. In addition, inlined images are not cached.
Also, you can build SVG-sprite and go with it.
— Sprites are a very old technology, why write about them in 2018?
Sprites existed before the web, but they are still useful. Experience shows that many frontend developers disregard sprites — as a result, design repositories resemble a garbage bin, and pages’ loading slows down even with the fastest connection. And we are all for a clean code and fast sites.