Post Archive

› December 25, 2005

Printing CSS background images (sort of)

  • Reported by Andreas

So you've made a standards compliant site for your client, nicely separating content from layout, and even provided a print stylesheet. The client likes the site's visuals a lot, and decides to print out the front page... Confusion ensues - where did the page banner go, and why is there text instead? He asks you about it, and you explain that browsers cannot do not print CSS background images by default, but render the title's text instead. Some clients leave it like that, others insist you "fix" the problem. The usual solution then is to do it the old-school way: include the image via the <img /> tag instead of using one of the many image replacement techniques.

I found another, non-HTML based solution (example) though, and list-style-image is the keyword. I explain.

Instead of including our banner graphic via the background-image hook, we use CSS' "lists" functionality instead.

Suppose you want the browser to print an image in the place of an h1 with id="title", then the following piece of print CSS does the trick:

#ti\tle {                                  /* 6. */
	display: list-item;                /* 1. */
	list-style-image: url(banner.jpg); /* 2. */
	list-style-position: inside;       /* 3. */
	letter-spacing: -1000em;           /* 4. */
	font-size: 1pt;                    /* 5. */
	color: #fff;                       /* 5. */
	}

Some annotations:

  1. We give our h1 the characteristics of a list-item.
  2. We pretend our banner image is a list-style-image.
  3. Firefox wants you to put the image inside.
  4. We make the text disappear into a black hole by means of Malarkey's Image Replacement (MIR).
  5. As MIR doesn't work in Opera, we set the font-size to 1pt and make the text white. This works fine with Opera's default print settings. Other image replacement techniques rely on moving or hiding mechanisms, all of which would also hide our image. Hence small, white text.
  6. As list-style-image is not supported in IE5 and IE5.5, we exclude these browsers with a simple escaping hack.

That's all. It works in IE6, Firefox 1.0 and 1.5 and Opera 8.5 - don't know about Safari, but I expect no problems. Konqueror 3.5 shows a black "H" just below the banner - however, the letter disappears when "Printer friendly mode" (which prints all text in black) is turned off.

Comments and improvements welcome!

Update: there are still people pointing out problems with printing in Firefox - I've posted about this problem a while ago and it seems to be a bug. If you want to have the Firefox developers fix it, vote for the bug (or even better: fix it yourself!)

Comments

1. December 25, 2005 02:02 PM

Quote this comment

Roger Johansson Posted…

Neat trick! Looks like it works fine in Safari too. A minor note about printing CSS background images: browsers can print CSS background images, but the default setting in most (all?) browsers is to not print them.

2. December 25, 2005 02:10 PM

Quote this comment

Andreas Posted…

Roger, you're completely right - I changed the wording a bit. Thanks. And cool that it works in Safari :-)

3. December 25, 2005 03:23 PM

Quote this comment

Raanan Avidor Posted…

Why not use the img tag and hide it in the screen CSS?

4. December 25, 2005 09:55 PM

Quote this comment

Alex Giron Posted…

A very interesting solution... I will have to give this a try.
THanks!

5. December 26, 2005 05:31 AM

Quote this comment

Gregor Posted…

WOW! That's really fantastic ! We've that's really nice trick, we will use in our print reports! Thank you!

6. December 26, 2005 07:54 AM

Quote this comment

Diego Eis Posted…

Hmm, good idea.
Here, in my Firefox 1.5, is visible a horizontal bar. I fix this, putting an overflow:hidden; Only for experience, I change the letter-spacing for word-spacing. I guess better.

My code is this:

#ti\tle {
	display: list-item; 
	list-style-image:url(logo.gif);
	list-style-position: inside;
	word-spacing:-5000em; /* I guess better that letter-spacing */
	overflow:hidden; /* This fix the Horizontal Roller */
	font-size:1px; /* unhappily is necessary */
}

Sorry, please, for my english. I´m from Brazil! :-D

7. December 26, 2005 08:52 AM

Quote this comment

gerben Posted…

Sweet. Though I'm not sure a client would accept this sollution since it's not working in IE. But it's still cool.

8. December 26, 2005 06:06 PM

Quote this comment

Matt Posted…

Like Roger said, it is a preference of the user whether background images should be printed or not, and is set to not print them by default to save ink. Why should one force this upon a visitor?

9. December 26, 2005 07:03 PM

Quote this comment

Sander Posted…

Matt: because this isn't a technique for regular background images, but instead for background images that are a replacement for regular textual content, so images that really should've been in <img> tags in the first place (and printed as such), but for one reason or another weren't. (Prettying up the looks of a large body of text with drop caps is one of the few really good uses I can think of for this; most everything else seems to stem from the belief that google puts more trust in plain text than the text in the alt attribute. That is, I personally find the image replacement technique from the example to be quite unnecessary. There's nothing wrong with "old-school" here.)

On the technique itself: CSS doesn't have any semantics of course, but even so this still seems like an abuse of CSS's semantics. *g* Despite that, Neat! Very well found indeed. :)

10. December 27, 2005 12:27 PM

Quote this comment

Björn Posted…

Neat solution to an issue I've run into a couple of times. Thanks!

11. December 27, 2005 02:30 PM

Quote this comment

Andreas Posted…

Thanks for all the comments, everybody :-)

Matt - interesting question. I think the technique has its (limited) uses though, especially in the business specific context I described - images determining the identity of a page (think the wg logo in the right corner, for instance) are preferably printed, even if they're included by means of an image replacement method. Also note that my technique doesn't allow for full-page background printing, as it is impossible to project letters on top of the list-style-image itself. In other words, we won't see ink slurping white-on-black print layouts anytime soon.

12. December 29, 2005 08:37 AM

Quote this comment

gaylover Posted…

the preview in ie and firefox is ok but the printing doesn't work ... ;-) the image is smaller

13. December 30, 2005 05:50 AM

Quote this comment

Andreas Posted…

Hmm - there is indeed a problem with Firefox' printing... The resulting image is much smaller. No problems in IE or Opera though. Could it be that this is a bug in Firefox?

14. December 30, 2005 06:28 PM

Quote this comment

Brad Posted…

The Mozilla/Firefox small image printing is a shame. I was trying to use this method to resolve Mozilla/Firefox's problem with printing png alpha transparency as black. It worked great except for the actual printing of the company logo as a tiny image. Nonetheless, it demonstrates another potential use for this trick besides background images.

15. January 3, 2006 09:26 AM

Quote this comment

WebDesPro Posted…

Finally, something I've been looking for.. THanks to your resource.

16. January 4, 2006 07:16 AM

Quote this comment

Jacobus Posted…

Anybody found a solution for the "Firefox small image" issue? Please let me know if you have. Thanks J

17. January 4, 2006 09:25 PM

Quote this comment

nick1presta Posted…

Would, text-indent: -5000em; work better than letter-spacing and elminate font-size: 1pt as text-indent works in Opera?

18. January 5, 2006 01:25 PM

Quote this comment

Andreas Posted…

Jacobus: working on it.

nick1presta: nope, text-indent: -5000em would remove the list-image too, and that is not what we want.

19. January 9, 2006 04:09 AM

Quote this comment

nick1presta Posted…

Using simple FIR (Phark Method Revisited), you can print background images.

A link to my site shows how you can print background images from a print stylesheet if you browser allows you too:
Click for my print stylesheet example

You need to specific the image in a print stylesheet noted by media="print".

In Firefox
  • File > Page Setup > Check Off "Print Background"
  • File > Print Preview
In IE
  • Tools > Internet Options > Advanced > Printing
  • Check Off "Print Background Images and Colors"
In Opera
  • File > Print Options > Check Off "Print Page Background"
  • File > Print Preview (You may have to scroll down/up to see it refresh)

With that, you can see how it's just plain text (since I didn't style anything except for that Print stylesheet) but becomes the image when you print-preview it.

However, I did notice that if you didn't specify, margin: 0; padding: 0; or some form of that declaration, you would get a sort of "double image" where the image would be at pixel point (0,0) but also on the page, affected by margins/padding.

20. January 9, 2006 04:28 AM

Quote this comment

Andreas Posted…

nick1presta, I don't get what you're at. You talk about "[printing] background images from a print stylesheet if you browser allows you to", but then you instruct to "check off" the "print background" checkboxes in IE, FF and Opera, which is exactly the opposite, right? Your technique doesn't work in any of these browsers - I don't see a single background image when in print preview with "print background" turned off.

21. January 9, 2006 01:34 PM

Quote this comment

nick1presta Posted…

I mean you need to make sure those options are checked (sorry for my bad wording). I have successfully printed the background image on that page in all three browsers.

It should be a small 40px by 40px cookie.

22. January 13, 2006 03:34 PM

Quote this comment

thinsoldier Posted…

nick1presta:

hmm...I can't seem to find where to turn on the printing of backgrounds in FF 1.5/mac.

Anyway, I really really hope the w3c and browser makers address the whole background image printing issue soon.

In my opinion it's a quite simple solution. Simple never print background images or colors ever, EXCEPT, when the AUTHOR SPECIFIES the background images/colors in a PRINT MEDIA STYLE SHEET.

All the ancient web pages with nasty pointless backgrounds remain unaffected and their backgrounds never print. Meanwhile those of us who put some time into our print stylesheets can have our cake and eat it too.

BTW, this is fun, put in your print stylesheet a rule that gives all H1's a black top border of 800px!

For anyone who has a site with a black background and white text and deviously wished it printed with the same black bg and white text, just have an empty div on the page with that rule and position it with some z-index to be behind all your content when printed.

23. January 13, 2006 03:41 PM

Quote this comment

thinsoldier Posted…

ok, now that I've actually rtfa. Congratulations on coming up with a very very imaginative workaround to a problem that I know we've all faced at least twice.

But honestly, there's too many hacks in CSS already.

We need to get more people and make more test cases and get on the mailing lists and nagg the hell out of the browser makers and the people who come up with the CSS standards until the implement this very simple, basic, NEEDED functionality.

Oh and I'm using FF1.5/mac and the articles example page didn't work like it said it would.

24. January 16, 2006 06:06 PM

Quote this comment

Matthew Posted…

I was worried about how to include images in the banner of my site before I found this solution.

25. January 19, 2006 11:02 AM

Quote this comment

Jann Posted…

It does not work with the current Firefox-Browser 1.5 (Windows). If I want to print your example-site with your CSS hack, I only get a tiny image printed out (and not the original size of the header graphic).

26. April 3, 2006 10:38 PM

Quote this comment

mpercy Posted…

Awesome idea! Consider using generated content to print in FF.

Works in FF:
@media print {
  #title { letter-spacing:-1000px; }
  #title:before { content: url(banner.jpg); }
}

Deliver the OP's solution to IE6+ only and you may have something that works in all major browsers. I have not tested the above code in Safari or Opera but I would bet it works for the most part.

27. April 19, 2006 04:41 PM

Quote this comment

Rebecca Posted…

Thanks so much for this article! If you have any thoughts on how to get a background image which is a gif with transparency to print with said transparency I'd be forever grateful.

28. May 10, 2006 10:16 AM

Quote this comment

Jordan Posted…

Just one suggestion: you could use overflow: none; as suggested above, and then try setting the line-height property to some massive value. This is generally how I hide text which should never display on the screen (since I read about it on another blog!), and it might get rid of the visible 'H' in Konqueror.

29. May 22, 2006 10:57 AM

30. May 24, 2006 11:15 PM

Quote this comment

Posted…

Please put your comments in paragraph tags, no auto-line-breaking anymore.

31. May 24, 2006 11:28 PM

Quote this comment

toltec7 Posted…

I have worked around this a slightly different way, by replacing the background repeat with a set sized image for printing only, and forcing a div back over the image for text output. This way, one image can be used as a header, and different headings without multiple images with text put in.

<table>
<tr>
<td class="headerCenter" background="images/Back.gif">
<p class="headerImg"><img src="images/Print.gif" border="0" align="top"></p>
<p class="headerText">April 2006</p>
</td>
</tr>

</table>

the print css

.headerImg {
position:relative;
left:0px;
top:16px;
z-index:-20;
}
.headerText {
position:relative;
left:0px;
top:-16px;
color:#FFFFFF;
font-size:16px;
z-index:800;
}
the relative positioning depends upon the image size

the web css

.headerImg {
display:none;
}
.headerText {
color:#FFFFFF;
font-size:16px;
z-index:800;
position:relative;
left:0px;
top:2px;
}

most of this is for visual alignment

only tested in ie6