Css trick – Preload images

The 2008 trick for preloading images with CSS went something like this:

#preloadedimages {
  width: 0px;
  height: 0px;
  background-image: url('path/to/image1.png');
  background-image: url('path/to/image2.png');
  background-image: url('path/to/image3.png');
}

Neat idea, quietly broken: in CSS, when the same property is declared multiple times in one rule, the last declaration wins and the others are discarded at parse time. Only image3.png was ever fetched. The earlier two lines did nothing. The variants that actually worked used one rule per image, or the JS new Image() approach below.

The dedicated solution: rel=”preload”

CSS was never the right tool for this. The platform now has a purpose-built mechanism — <link rel="preload">:

<link rel="preload" as="image" href="hero.avif">
<!-- responsive variant: -->
<link rel="preload" as="image" href="hero-narrow.avif"
      imagesrcset="hero-narrow.avif 480w, hero-wide.avif 1200w"
      imagesizes="100vw">

It fetches with the right priority, works for fonts and scripts too (as="font", as="script"), and the responsive form pairs with srcset. Preload only what’s needed for the current viewport — preloading everything a page might use is how you end up slower than preloading nothing.

When JS is the right tool

For hover states and other images needed “soon, on this page”, a tiny imperative preload still works fine:

function preload(...urls) {
  for (const url of urls) {
    const img = new Image();
    img.src = url;
  }
}
preload('/img/menu-open.png', '/img/tooltip.png');

The Image() constructor is equivalent to creating an <img> element via document.createElement — the fetch happens as soon as you set src. The browser caches the response, so the later hover or state change is instant. And if your original motivation was rolling a sprite sheet by hand — modern srcset, inline SVG, and HTTP/2 multiplexing have retired most of those reasons. Measure before you preload.

Leave a Reply

Your email address will not be published. Required fields are marked *