A client’s site had a white SVG logo on top of a color background.

<header style="background:black">
  <img src="https://fvsch.com/articles/css-print-background/white-logo.svg"
       alt="The site’s name">
</header>

When working on the print styles, we had a problem: browsers would disable background colors and print the logo white on white. And in this case we could not change the logo image or use a filter: invert(100%) on it.

We could have used the non-standard -webkit-print-color-adjust CSS property, but what about other browsers?

Faking a background with SVG

By default, browsers will print content images. We can inject one in our page and display it as a kind of background, in 3 steps:

  1. Use a pseudo-element (::before or ::after) and an image URL in the content property.
  2. For a solid color, we can make a simple SVG image, which works well as a data-URL.
  3. Finally, we use absolute positioning to place this pseudo-element in the background.
header {
  position: relative;
}
header > * {
  position: relative;
  z-index: 2;
}
header::before {
  position: absolute;
  z-index: 1;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  overflow: hidden;
  /*
    In the URL, change the background to your own color.
    Warning: the `#` character must be escaped as %23,
    for example: `background:%23FFFF00` (yellow).
  */
  content: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' style='background:YOUR_COLOR_HERE' />");
}

Here is a fully working example in an iframe. You can test it by using your browser’s Print Preview on this page, or on the example page directly.

As noted, it’s a nice trick but don’t overuse it: you could cost your users a lot of money in printer ink.

Browser support

  • Works on all modern desktop browsers (tested in Edge 14–16, Firefox 58–60, Chrome 61–63, Safari 11)
  • Not tested on mobile browsers
  • Does not work in IE11

Three things to watch out for

  1. The pseudo-element and the image are two separate entities. While the pseudo-element will cover its parent, the image will take the full width, and its height will depend on its aspect ratio. This means that the image will overflow its container, and we have to hide it with overflow:hidden.

  2. In this example, we use a square image (viewBox='0 0 10 10'); if you need a taller image, use a rectangle one (for example viewBox='0 0 10 50').

  3. Making sure that your url(…) is a valid data-URL can be tricky. In practice there is not a lot to escape, but if you are using double quotes to wrap your URL you will need single quotes for the XML attributes, and vice-versa. The # character identifies a fragment in URLs, so you will need to escape it using percent-encoding (%23).