CSS has a well supported mechanism for applying changes only when the user is printing a document, print stylesheets. They allow you to alter the presentation of a web page for the printer by applying rules that will only be interpreted for printing. This is great for common tasks like hiding non-essential content, using more print friendly typography, and adjusting the layout to better suit the size and shape of paper.
onbeforeprint and onafterprint
onafterprint events before and after the user requests the page to be printed.
1 2 3 4 5 6
These events are not part of any specification but they are very convenient. Because of this Firefox added support for both events in version 6. However, WebKit and Opera do not support the events. Therefore, for cross browser compatibility these events aren’t going to cut it.
WebKit has a bug (#19937) out there to implement these events, but progress has stopped because the implementation of another API made this functionality possible already -
1 2 3 4 5
You can also use this API to add listeners that will be fired whenever the result of the media query changes. In the above example the
matches criteria will be met whenever the viewport is at least 600px wide. If you wanted to receive notifications whenever the viewport crossed the 600px threshold you could use the following.
1 2 3 4 5 6 7 8
If your browser supports window.matchMedia you can see this behavior live below by resizing your browser window under 600px on the following demo:
matchMedia ExampleOpen in New Window
Interestingly, it turns out you can also use this same technique to listen for the
1 2 3 4 5 6 7 8
This works great in Chrome 9+ and Safari 5.1 (with the exception of the fact that the listeners fire twice in Chrome). However, it doesn’t work in Firefox or IE10, even though they both support
Update (July 16th, 2012)
I created a bug on Firefox’s issue tracker for this defect - https://bugzilla.mozilla.org/show_bug.cgi?id=774398. I’ll update this post when I hear back.
Combining the Approaches
If you combine the two approaches you can detect print requests in IE 5+, Firefox 6+, Chrome 9+, and Safari 5.1+ (unfortunately Opera doesn’t support either approach).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Note that your event handlers might potentially have to deal with the fact that they’re going to be called twice per print request in Chrome.
Why Would I Use This?
Responsive Print Images
One use is substituting a higher quality image for the purposes of printing. Traditionally web browsers have displayed images at 72dpi and most printers can handle 300dpi+. While some newer devices are able to display images at much higher resolutions, most users are still using a screen that will show web images at much lower resolutions than their printer can handle.
Therefore an image that might look just fine on the user’s screen might look fuzzy and grainy when printed out. For most images this is acceptable, but it might be an issue for prominent images on regularly printed documents, like a company logo. You probably want that to look crisp when printed out.
The technique to work around this involves loading both images, showing only the lower quality one by default, then hiding the low quality image and showing the high quality one in the print stylesheet. The main downfall of this approach is that the end user has to download both images regardless of whether they’re going to print the page. Users on 3G devices that have no intention or capability of printing the document will still have to download your high resolution logo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
The nice thing about this approach is that users that never print will not have to download the high quality image. This technique also degrades nicely; users with browsers that don’t support the print events will simply print the lower quality image.
Tracking Print Requests
Print events can also be used to track the number of times users print pages within a site or application. Because of the lack of total browser support you wouldn’t capture every print request, but this would be sufficient for getting a rough idea of how often people are printing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
So can I use this in a “real” application?
Sure, just make sure what you’re doing degrades nicely for users using a browser in which the event will not be fired.
Update (July 16th, 2012)
Per the comments I’ve found that in addition to all the bugs mentioned above, certain browsers trigger the after print event early (with either
onafterprint or the
window.matchMedia handler implementation).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
When printing the above document you would expect Stack Overflow’s favicon to print, when in actuality Google’s favicon prints. Both events fire, but the after print event fires before the printing actually occurs, which in this case reverts the changes made in the before print event.
I was able to recreate this problem in Chrome and Firefox.
Therefore do not do anything that relies on the after print event to fix what the before print event did. For responsive print images this shouldn’t be an issue because there should be no harm leaving the higher quality image in place; the user has already downloaded it.