Cross-Fading Elements? There’s a Quirky CSS Trick for That

Reading Jake Archibald’s deep dive into why cross-fading two DOM elements is “currently impossible” got me thinking. Sure, you can animate both opacities, but that’s not a true cross-fade. It turns out Chrome and WebKit have a CSS function called -webkit-cross-fade() that does exactly that. MDN says it’s specced, but the implemented version differs, so it’s a bit messy—still, it exists and works.

.el {
  background: -webkit-cross-fade(url(img1.svg), url(img2.svg), 50%);
}

The first thing that hit me: if one image is just a blank transparent GIF, wouldn’t that apply partial transparency to the other? That makes it a kind of proxy for background-opacity, which doesn’t exist but feels like it should. I tested it, and it works.

Here’s the core technique:

.el {
  background-image: -webkit-cross-fade(
    url(image.jpg),
    url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7),
    50%
  );

That’s a 1px transparent GIF, Base64-encoded. It doesn’t work in Firefox, but everywhere else it’s fine. Plus, you can test for support right in CSS and fall back to something else if this is only an enhancement.

@supports (background: -webkit-cross-fade(url(), url(), 50%)) {

  /* Only apply the idea if supported, do the Firefox fallback outside of this */

}