Replacing images when printing

It isn’t all that uncommon that, after you’ve polished your print stylesheet to make a site look well on paper as well as on screen, you realise that the logo really doesn’t look its best. It may look blurry or pixelated on paper due to having a pixel density intended for screen viewing, of course. But even worse, its edges may look ugly or it may actually be invisible because whatever is behind it when viewed on screen isn’t printed.

Applying a background colour to the logo image or its containing element in the print CSS isn’t going to help either since most browsers by default do not print backgrounds at all. If you can’t change the image used for screen so that it will look good in print as well, you need to somehow make browsers use a different image when printing. One way of doing that is by using CSS generated content.

Hide the screen image, insert one for printing

A pretty straightforward way to exchange the images is to hide the screen image and use the print image as content for a CSS pseudo-element.

Assume you have the following HTML:

<div id="logo">
	<img src="screen-logo.png" width="200" height="35" alt="The Awesome Logo" />
</div>

To hide that image and insert another one, all you need is this CSS:

@media print {
	#logo img {
		display:none;
	}
	#logo:after {
		content:url(print-logo.png);
	}
}

This works in most browsers. Chrome, IE 9+, Opera, and Safari all print the image content of the pseudo-element. Unfortunately, Firefox versions older than 20 do not, and neither does IE 8. (Neither does IE 7 since it doesn’t support CSS generated content, but let’s not worry about that right now.)

The problem browsers

IE 8 apparently treats pseudo-element content images as backgrounds when printing, since it does print the image if you check “Print Background Colors and Images” in the Page Setup dialog. So that explains that problem.

Firefox (19 and older) is more of a mystery, however. Whether the image is printed or not seems a bit random. It seems as if the page is fetched from cache, the image is printed, but if you do a full refresh it is not. It also gets printed if you do a print preview, cancel printing, then do a print preview again. As far as I can tell the behaviour is similar for both Mac and Windows versions of Firefox.

Possibly even more confusing, changing the media type to all also makes Firefox always print the replacement image:

@media all {
	#logo img {
		display:none;
	}
	#logo:after {
		content:url(print-logo.png);
	}
}

But you don’t want that since that would display the print image on screen.

Reverse the process

You may or may not (most likely not—yet) be able to ignore the problem for IE8, but probably not for Firefox 19 and older just yet. A workaround is to reverse the process: reference the print image in the HTML and replace it with the screen image in the screen CSS.

The HTML:

<div id="logo">
	<img src="print-logo.png" width="200" height="35" alt="The Awesome Logo" />
</div>

The CSS:

@media screen {
	#logo img {
		display:none;
	}
	#logo:after {
		content:url(screen-logo.png);
	}
}

No print CSS is needed to make the print image appear this time. And it works in IE 8 and Firefox 19- in addition to the other browsers. The drawbacks are that browsers without CSS support will display the print image on screen, and that browsers without support for the :after pseudo-element will display nothing. To avoid the second problem, which mainly affects IE7 and older, you can use you favourite IE CSS patching method to override the display:none declaration for the image.

The Replacing images when printing demo page contains an example of each method. In the demo I’ve used a screen image that contains white text on a transparent background and a print image that has a black background. In the screen CSS I’ve given the element containing the logo a background colour to make the logo text visible.

Use cases

So when would you want to replace images like this?

There may be more use cases as well as other methods, of course.

Posted on May 14, 2013 in CSS