I’ve been working on a method to fade a page background image sequence, like the current Twitter login page. Usually, these effects are “faked” using a background and cover layer, but I was interested in manipulating true background images with blend modes.

Quite by accident, I found that Webkit-derived browsers, such as Chrome, Safari and Opera, will actually cross-fade images in the background, given the right combination of CSS. In the interests of that, I’ve presented the basic code here, with more detail to come in a future article. You can also see a fullscreen version and inspect the code at CodePen.

Technically you don’t need any HTML content to make this example work, as the background images are applied to the <html> root element. Surprisingly, you don’t even need the blend mode, as Webkit will transition the images without it: I’ve left the property in place for the next article, which will use the feature to a greater extent.

html {
	background-size: cover;
	background: url("lone-tree.jpg") no-repeat center center fixed;
	background-blend-mode: darken;
	transition: 3s;
}
html * { transition: none; }

This sets up the basic background: note the transition, and the combination of universal and descendant selector and declaration, used to ensure that nothing inside the body will inherit the transition.

The animation is handled with a script placed at the bottom of the page. It starts with an array of the image filenames you want to use, together with an indication of where they are, relative to the page itself:

var bgImageArray = ["lone-tree.jpg", "lonely.jpg", "carezza-lake.jpg", "batu-bolong-temple.jpg"],
base = "",
secs = 6;

The empty value for the base variable in this example assumes that the images are right beside the page. secs is the amount of time in seconds each background should remain on the page: in production it’s value would usually be around 12 ~ 30.

Chrome does a very good job of caching the images before they are used, but other browsers do not, causing white flashes as each image is loaded and replaced. To get around that issue, we can preload the images:

bgImageArray.forEach(function(img){
    new Image().src = base + img; 
});

Next, the function to show the images in the background:

function backgroundSequence() {
window.clearTimeout();
	var k = 0;
	for (var i = 0; i < bgImageArray.length; i++) {
		setTimeout(function(){
document.documentElement.style.background = "url(" + base + bgImageArray[k] + ") no-repeat center center fixed";
document.documentElement.style.backgroundSize ="cover";
			if ((k + 1) === bgImageArray.length) {
				setTimeout(function() {
					backgroundSequence() }, (secs * 1000))
			} else { k++; }
		}, (secs * 1000) * i) 
	}
}
backgroundSequence();

Note that this script replaces the embedded or linked style from the CSS with an inline style for the <html> element.

There are a few conditions and improvements to be aware of:

  • each image should be the same aspect ratio for the cross-fade to work effectively; otherwise you’ll see a slight transitioned “stretch” as each image submits to background-size: cover.
  • Firefox and Internet Explorer do not yet cross-fade the background images, simply substituting one for the other.
  • secs needs to be higher than the transition value (an even multiple works well).
  • The script could use some optimisation and improvements, including a fade-to-black option: I’ll put it up on Github for contributions presently.

Photographs by Marco Carmassi and Francesco Alamia, licensed under Creative Commons.

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/qEoKzZ