Multics > About
06 Dec 2020

Using CSS Sprites

History | People | Library | Sites | About Search

Tom Van Vleck

Multiple pages on multicians.org display picture galleries as a set of thumbnails. Clicking on any thumbnail picture opens a new page, or opens a bigger picture by calling a Javascript function.

Examples

Thumbnail Galleries

multicians.org uses thumbnails that occupy 75x75 CSS pixels on the gallery pages. As described in High DPI Pictures, we use 150x150 image pixels to ensure that the thumbnails will look sharp on high-dpi screens such as smartphones and Retina displays.

A user visiting a page with e.g. 400 thumbnails will be delayed, because the user's browser has to request the page, wait for the page's HTML to come back, parse the HTML to find 400 IMG tags, and then request 400 graphics and wait for each, before the page is completely displayed.

We can speed up page display by specifying WIDTH and HEIGHT (in CSS pixels) on each IMG tag, so that browsers don't need to wait to read the image in and get its size to determine its effect on the layout of other elements. Doing this enables a browser to lay out the page and text elements quickly, and then send requests to fetch the graphics and insert their contents as they arrive from the web server. (On a slow connection, this result is very noticeable.)

Using Sprites

To make gallery pages load faster, we combine all the thumbnails into a packed file and display each thumbnail as a CSS sprite; that is, the HTML display for each thumbnail shows a transparent 1x1 GIF, with a CSS class that selects a 150x150 pixel background slice from the right place in the packed file.

Doing it this way makes page loading and transition faster. For a page with 400 thumbnails, the browser loads the HTML, the 1x1 graphic (which will probably be cached), and the packed file: three waits instead of 401.

When is it worth doing this extra work? It depends on the visitors' perceptions and the speed of their connections. For a page with less than 20 images, it's probably not worth doing... unless visitors are loading your site over a satellite connection or are impatient. Google penalizes pages that load slowly, ranking them lower in search results.

For a home page whose responsiveness is critical, or a page with lots of images, do some research to see if it's worth speeding up. To see how long it takes a page to load, you can use Google Chrome: choose View => Inspect Elements => Network and reload the page to see what elements are loaded and what takes the longest. Or you can select the Lighthouse tab and audit the page; Performance should be near 100.

For an example of a page where sprites are is used, see multics-images.html. Instead of loading 642 small graphics, it loads five large ones, which is much faster.

Maintaining a Web Page

When a gallery page changes, something must

The multicians.org build process does these steps automatically. Pages with galleries generate the packed graphics when the HTML page is made from .htmx and .sql source, and use macros to create IMG tags that reference the packed file. See Using Unix tools with expandfile for more info.

Graphics

Generating Thumbnails

The shell script gth2x generates 150x150 thumbnail graphics from JPG and GIF files using a free program called ImageMagick (available for Mac, Windows, and Linux).

#!/bin/sh
# square thumb 150x150
# requires ImageMagick tool convert
# THVV 2011-04-07
# THVV 2016-06-07 add sharpen
# THVV 2017-03-29 make 2x version

#  Permission is hereby granted, free of charge, to any person obtaining
#  a copy of this software and associated documentation files (the
#  "Software"), to deal in the Software without restriction, including
#  without limitation the rights to use, copy, modify, merge, publish,
#  distribute, sublicense, and/or sell copies of the Software, and to
#  permit persons to whom the Software is furnished to do so, subject to
#  the following conditions:

#  The above copyright notice and this permission notice shall be included
#  in all copies or substantial portions of the Software.

#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
#  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
#  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
#  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
#  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
#  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 

f=$1
grav=$2
if test -z "$f"
then
  echo "usage: gth2x filename [center|north|northeast|...]"
  exit 1
fi
if test -z "$grav"
then
  grav=center
fi
echo convert -thumbnail x300 -resize '300x<' -resize 50% -gravity $grav -crop 150x150+0+0 -sharpen 0x1.0 +repage $f thumb2-$f
convert -thumbnail x300 -resize '300x<' -resize 50% -gravity $grav -crop 150x150+0+0 -sharpen 0x1.0 +repage $f thumb2-$f

Given the file name foo.jpg, this script uses ImageMagick's convert program to create a thumbnail thumb2-foo.jpg, which I then move into the thumbnails150 directory. The macro accepts an optional argument to specify which part of a non-square input will be kept: "center" is the default, and "northwest" and other compass points can also be given. Usually I generate the default and then if a thumbnail is really ugly, I try the script with other arguments. In extreme cases I generate a better thumbnail using an image editor to isolate the key details of a photo.

Generating Many Thumbnails

The site convention is to have a subdirectory called mulimg with full size photos, and another subdirectory called thumbnails150 containing the corresponding thumbnails, with the full size and thumbnail files named the same.

The Makefiles of other sites I maintain use the Perl program genthumbs to scan an image directory and a thumbnails directory and create any missing thumbnails, by invoking convert in a similar way to gth2x.

Concatenating Thumbnails

The ImageMagick tool convert has a way to concatenate thumbnails. The simplest way is to make one thumbnail with a height of 150 and a width of (150 * N) for N thumbnails. Addressing the individual images from CSS is then easy. Execute

  convert x.jpg y.jpg z.jpg ... -append thumbspack.jpg

to create a combined image from a list of individual images.

The maximum dimension of a JPEG file is 65536 pixels in either dimension .. so this method will only work for up to 436 thumbnails. To go beyond this one can make a 2-dimensional packed file with more complex addressing, or create multiple packed files. Either of these methods requires corresponding changes to the CSS sprite definitions. (For example, multics-images.html divides its 642 images into 5 files, divided by topic: the largest is almost at the limit of 436, and I will have to rework the generation process if I get another 13 pictures of people. I'll divide the "people" section into 1960-1999 and 2000-on packed files.)

HTML Code

IMG tags

An IMG tag that displays a particular sprite looks like

  <img src="mulimg/clearpix.gif" width="75" height="75" alt="" class="thumbspacksprite003">

The WIDTH and HEIGHT in the IMG tag are measured in CSS layout pixels (standardized at 96 DPI). clearpix.gif is a 1x1 transparent GIF file: it will be stretched to whatever dimensions are in WIDTH and HEIGHT. Since it is transparent, the background will show through it. The CLASS attribute specifies a particular class for the image to be shown, and is different for each image.

CSS definitions

The CSS class definitions go inside a STYLE tag in the HEAD section of the web page. There will be one class definition for each image in the concatenated file. The CSS class definition for a particular sprite image, say the third one, looks like

  .thumbspacksprite003 {
    width: 75px;
    height: 75px;
    background: url(mulimg/thumbspack.jpg) no-repeat 0px -150px;
    background-size: 75px;
  }

The first element is the class name, which matches the CLASS attribute in an IMG tag. The WIDTH and HEIGHT attributes in the CSS definition are measured in CSS pixels. The relative URL of the packed JPG file is in the URL() value of the BACKGROUND attribute, which then positions the background by specifying the vertical and horizontal offset of the background (basically the background is shifted left and then a 75x75 window for the sprite is applied.. this is why the offset is negative). The BACKGROUND-SIZE attribute is the width of the image in CSS pixels; I think it can be omitted since it is the same as WIDTH.

In this example, the image being displayed is twice as big as the layout space it is shown in, in order to show sharp images on high DPI screens, as mentioned above.

Generating IMG Tags

I use macros in htmxlib.htmi to generate appropriate elements in a list of IMG tags for displaying thumbnails that pop up a full size image. These macros are described in Expandfile Macros:

(I used to arrange thumbnails with a TABLE element, but tables don't work well on small screens. It is simpler to just have a list of IMG tags with the INLINE attribute, and let the browser decide how many to put on a row depending on the screen width.)

Home Page Slider

The web page multicians.html displays a sliding panel of fifteen 600x488 pixel images, using the jQuery plugin "EasySlider." Using sprites for the slider images was an easy upgrade, requiring a change to the IMG tag to show a 1x1 clear GIF with a CSS class for the sprite, and generation of the packed JPG file and the CSS class definitions whenever the home page or the slider definitions change. I decided to use sprites for this display to make the site's home page load as fast as possible, to make sure Google didn't penalize the page.