True printing with
CSS Section: workshop > web Author:
Steven Noble Posted: 02/12/2002

One of the best print-friendly features of CSS
(Cascading Style Sheets) is that they allow you to automatically format
your Web page using one style sheet whenever visitors view it on their
screen, and with another whenever they print it.
The code to do this is very simple. If you prefer the <link> tag, place the following in
the <head> area of your
HTML:
<link rel="stylesheet"
href="name_of_screen_styles.css" type="text/css"
media="screen"> <link rel="stylesheet"
href="name_of_print_styles.css" type="text/css" media="print">
If you favour the @import method, try this code instead:
<style
type="text/css"> <!-- @import url(name_of_screen_styles.css)
screen; @import url(name_of_print_styles.css)
print; --> </style>
If you're an intranet developer who can direct everyone in the company
to use the same Web browser, then this is all the code you need. A
standards-compliant Web browser like Mozilla will automatically toggle
between the screen- and print-orientated style sheets, depending on
context.
But if you're a Web developer, life is not so simple. Many of the
people who visit your site could be using browsers that don't
automatically select the right style sheet for each media. To
accommodate the general public, Web developers must still use a
server-side scripting language to build print-ready versions of each Web
page. But while Web developers cannot rely on CSS alone, they should find
that CSS simplifies the task of writing these server-side scripts. Here's
how:
First, drop the media attribute from the <link> to your screen-orientated style sheet in
the ordinary version of your Web page. Next, drop the <link> to the print-orientated style sheet
altogether. Last, write the server-side script that will generate
printer-ready pages for your Web site. If this script grabs the ordinary
version of each Web page and feeds it into a string variable to create the
printer-friendly version of the page, then it would take just one line of
PHP code to modify the <link> so that it points to your
print-orientated style sheet:
$output_string = str_replace
("name_of_screen_stylesheet.css", "name_of_print_stylesheet.css",
$input_string);
Print style makeover
At this point, your print-orientated style sheet is just an empty file,
and your printouts will be formatted as "vanilla" HTML. This is better
than printing Web designs straight off the screen, as common Web effects
like white-on-black text will chew through printer cartridges and be
near-impossible to read when the ink starts to bleed. But let's go one
better than vanilla HTML, and bring some paper-friendly pizazz to your
print-orientated style sheet.
Start with the font-family property. In all likelihood, your
screen-orientated style sheet specified typefaces that are designed for
comfortable reading onscreen. By contrast, your print-orientated style
sheet can specify any fonts you please. Just remember to provide a few
alternatives, for users who don't have your favourites on their computers.
h1 {font-family: 'lucida grande',
'gill sans', arial, sans-serif;}
If you specified absolute (rather than relative) font sizes in your
style sheet, then you used pixels as a unit of measurement. But there are
no pixels on paper, so use points instead:
p {font-size: 12pt;}
You can't click on a hyperlink in a printout, so highlighting them with
blue and underlines would simply be distracting. Make your hyperlinks look
like regular paragraph text by adding this rule to your print-orientated
style sheet:
a {text-decoration: none; color:
black;}
The CSS spec defines an after pseudo-element and a content property
that you can use to automatically print the URL in brackets after each
hyperlink, like this:
a:after {content: " (" attr(href) ")";
}
However, many Web browsers do not support these abilities at present.
If you're an intranet developer who can direct all employees to use a
standards-compliant browser like Mozilla, this is not a problem. If you're
a Web developer who really wants to emulate this effect, you'll have to
write yourself a server-side script. first-letter is another CSS
pseudo-element that could come in handy when formatting Web printouts. The
following code will create a "drop cap" after each major heading:
h1 + p:first-letter { font-size:
250%; font-weight: bold; float: left; padding-right: 2pt;
}
The h1 + p:first-letter
selector refers to the first letter of any paragraph <p> that immediately follows an <h1> headline.
The font-size: 250%;
declaration increases the first letter to 250% of the size of ordinary
<p> text, so it displaces but doesn't
completely fill three lines. That is, there will be some room between the
bottom of the drop cap and the top of the fourth line of the paragraph.
The padding-right: 2pt;
declaration puts a space between the drop cap and the first three lines
that sit to its right.
float: left; floats the drop cap to the left of the paragraph, so the
top of the drop cap aligns with the top of the paragraph. Without it, the
bottom of the first line of paragraph text would extend from the bottom of
the drop cap.
Dealing with images
Automatically removing all images from a printout using CSS is as easy
as everything else we've tried so far. Just add this rule to your
print-orientated style sheet:
img {display: none;}
It is also possible to use CSS to insert new, print-friendly images
into your printouts, but that requires a well-structured HTML document
plus a Web browser that provides exceptional support for Web standards.
CSS fanatics can attempt this by giving an uri value to the content
property of an after or before pseudo-element (see http://www.w3.org/TR/REC-CSS2/generate.html#before-after-content).
The rest of us will find it easier -- and more cross-browser compatible --
to write a server-side script that grabs the ordinary version of each
page, feeds it into a string variable, and modifies the string for print.
If all your <img> attributes
like height and width are in your CSS style sheet rather than your HTML
proper, then the PHP code that will swap your images could be this simple:
$output = str_replace
("name_of_screen_image", "name_of_print_alternative", $input);
Or, to remove every image from the string variable, you could use this
line of PHP:
$output =
eregi_replace("<img[^>]*>", "", $input);
In this example, PHP's eregi_replace() function will search a string ($input) for every instance of the first
regular expression ("<img[^>]*>") and replace it with the
second (""). The first regex will match every instance of <img ,
followed by any number of characters that are not >, followed by >.
The second regex is empty, so eregi_replace() will delete every string that matches
the first regex.
Precise page sizes
CSS allows for strict control over the size, shape and margins of the
printed page. At the centre of these controls is CSS's page model,
including the concept of the page box. The page model differs from the box
model (which CSS uses for onscreen display) because a page has finite edge
-- a printer cannot simply extend a sheet of paper whenever a GIF bleeds
off the edges.
While the page has a finite height and width, there does not have to be
a direct relationship between the dimensions of the page box and those of
the final sheet of paper. For example, both double-sided and two-up
printing involve mapping two page boxes to a single sheet. If you feel
it's important to set the height, width and margins for your printouts,
use the @page selector. Here is how you would use it to restrict the page
box to the size of one A4 sheet of paper:
@page {size: 210mm 297mm;} This is
the equivalent rule for US Letter: @page {size: 8.5in 11in;}
US Letter is wider (216mm) and shorter (279mm) than A4, so here's a
page box that will fit on paper of either size:
@page {size: 210mm 279mm;}
Note that millimetres and inches are the measurement, as we're
designing our Web site for print, not onscreen viewing. To describe your
page box in more general terms, try "landscape" or "portrait" as the value
of the size property.
When developing for a corporate intranet where you can control the
printer, the paper size and the Web browser, you can use the @page
selector to exercise more control. For example, if you require
double-sided printing with wide centre margins for ring binders, add these
two rules to your style sheet:
@page :left { margin-left:
4.5cm; margin-right: 2.5cm;} @page :right { margin-left:
2.5cm; margin-right: 4.5cm;}
The inner margin will now be 4.5cm, and the outer margin 2.5cm. You can
even add extravagant, 6cm margins to the first page with the first
pseudo-element (which overrides the left and right pseudo-elements used
above). Try this:
@page :first {margin: 6cm;}
A practical application of these abilities would be to ensure that
extra-wide diagrams fit on the page, even when the document is printed in
portrait mode. The first step is to assign every diagram to a class that
you created for this purpose (here, we've called the class wide).
Then, give the same name (here, that's turntofit) to every page that
includes an image of that class. Here's the CSS:
img.wide {page: turntofit;}
Now, simply rotate all pages called turntofit:
@page turntofit {size:
landscape;}
Perfect positioning
CSS positioning allows you to disrupt the normal top-to-bottom flow of
the text in a Web page.
You can use CSS positioning with a print-oriented style sheet's page
model much as you would use it with a screen-oriented style sheet's box
model. For example, you can modify an image's float and z-index properties
to use it as a watermark on every page of a printout. But generally it's
best to use CSS's paged media attributes to fine-tune printouts, instead.
Not only do these attributes retain the expected top-to-bottom flow of
a printout, but they focus squarely on the one thing that matters most
when printing long documents: where to put the page breaks. For example,
you probably don't want your major headlines to break over two pages, or
to sit at the bottom of any page of your printout. So, add the following
rule to your print-orientated style sheet:
h1 { page-break-inside:
avoid; page-break-after: avoid;}
In fact, it would be best if your major headlines did not even come
near the bottom of the page. A few dangling lines of text at the bottom of
a page are called "orphans". To avoid them add these rules to your
print-orientated style sheet:
h1 {page-break-before: always;} h2
+ p {orphans: 2;}
This tells the Web browser to always start a new line before a <h1> headline, and to avoid
printing two or fewer lines at the bottom of a page whenever a paragraph
of <p> text immediately
follows an <h2> headline.
Also, the page-break and orphan values tell the browser where to avoid
page breaks, not where to eliminate them. This is because a
print-orientated style sheet can have competing page-layout goals, which
the browser must reconcile.
As well as attempting to fulfil every request in the style sheet, the
browser will try to avoid page breaks within elements which have borders,
and it will try to equalise the lengths of each page not ending with a
forced break.
Web standards, like CSS, are designed to be "forward compatible". In
other words, if you design a Web site today using CSS2, it will display
correctly when the CSS3 spec is finalised and future Web browsers start to
support CSS3. Conversely, when future developers start building Web sites
using CSS3, their work will display adequately in today's CSS2 Web
browsers. The CSS3-only flourishes will be missing when the site is viewed
using today's CSS2 Web browser, but the browsers will not mangle the CSS3
layouts. To see which browsers support which print-related aspects of CSS2
today, consult CodeStyle's list: http://www.codestyle.org/css/media/print-BrowserSummary.shtml.
|