Rate this page

Hide part of an HTML or XHTML document when it is printed

Objective

To hide part of an HTML or XHTML document when it is printed, without affecting how it is normally displayed on screen.

Scenario

Suppose you have a website that is styled using a CSS stylesheet. The body of the document includes a panel of navigational links, which are contained within a div element with an ID of navigation:

<div id="navigation">
 <ul>
  <li><a href="/">Home</a></li>
  <!-- ... -->
 </ul>
</div>

These links are needed when the page is displayed in a browser window, but serve no purpose when the page is printed. You therefore wish to prevent them from being rendered in the latter instance.

Methods

Overview

CSS2 allows rules to be made specific to a particular ‘media type’, making it possible for documents to be formatted differently depending on whether they are being viewed or printed. In this scenario the required difference is for the navigational links to be displayed when viewed but not when printed. In the absence of any complicating factors, the latter condition can be achieved by setting the display property of the unwanted element to none using a rule such as:

#navigation {
  display: none;
}

All that then remains is for this rule to be made conditional on the appropriate media type, which for printing is print. There are a number of ways in which this can be done, three of which are described here:

  1. placing the rules within an @media rule;
  2. using an HTML link element with a media attribute; or
  3. using an @import rule that has been qualified with a media type.

All of these methods require CSS level 2 to work, but they should degrade gracefully if it is not available. For most purposes an @media rule is likely to be the most straightforward and efficient solution.

Possible complications are that:

Techniques for addressing these issues are considered in more detail below, but it is worth noting in advance that rules specific to printing should normally appear after any rules they are intended to override as this will help to ensure that they have a sufficiently high precedence.

Method (using @media)

Tested with:

Chrome (5, 10, 14, 18)
Firefox (3.0, 3.5, 3.6, 4, 7, 11)
IE (6, 7, 8, 9)
Opera (10, 11)
Safari (5)

An @media rule acts on a brace-delimited list of CSS rules and makes them specific to a given media type. It can be used to incorporate print-specific rules into an existing stylesheet (internal or external):

@media print {
  #navigation {
    display: none;
  }
}

As noted above, the print-specific rules should appear after any existing rules.

Method (using link)

Tested with:

Chrome (5, 10, 14, 18)
Firefox (3.0, 3.5, 3.6, 4, 7, 11)
IE (6, 7, 8, 9)
Opera (10, 11)
Safari (5)

One of the uses of an HTML link element is to add an external stylesheet to a document. Stylesheets linked in this way can be made specific to a particular media type by adding a media attribute to the element:

<link rel="stylesheet" href="/main.css" type="text/css"/>
<link rel="stylesheet" href="/print.css" type="text/css" media="print"/>

In this example there are two external stylesheets: one called main.css that is used for all media types, and a second called print.css that is used only when printing.

You might think that using separate stylesheets would reduce the amount of data fetched by the browser when initially loading the page, because stylesheets could then be loaded selectively if and when needed. In practice it would appear that most current browsers do not do this, instead loading the print stylesheet whether or not it is required immediately. Consequently, the outcome is more likely to be an increase in loading time than a reduction due to the need for an extra HTTP request.

Certainly for the example above (with only a single print-specific rule) there is little to gain and much to lose by adding an extra stylesheet. If the number of rules were greater then there may be a case for division on the grounds of modularity, but even then it is far from clear that you would want to partition by media type because of the high degree of coupling that would exist between modules.

Method (using @import)

Tested with:

Chrome (5, 10, 14, 18)
Firefox (3.0, 3.5, 3.6, 4, 7, 11)
IE (9)
Opera (10, 11)
Safari (5)

Fails on:

IE (6, 7, 8)

@import rules can similarly be made specific to a particular media type:

@import "/main.css";
@import "/print.css" print;

As when using a link element this theoretically allows the web browser to avoid downloading the rules for printing unless and until they are needed, but in practice this gain is unlikely to be realised and carries the cost of an extra HTTP request.

A minor drawback of this method is that it fails on some older versions of Internet Explorer that do support media types using @media or link.

CSS rule precedence

To be effective, the rules that are added for printing must be able to override any existing rules that apply to the document. Whether that happens will depend on their precedence. There are three relevant factors: the importance of the rules, the specificity of the selectors, and the order in which the rules appear. Importance is considered before specificity, and specificity is considered before ordering.

When overriding it is not desirable to use a selector with higher specificity, because the overriding rule would then apply in a narrower range of circumstances than the existing one. Marking all of the new rules as important would work (provided that the originals were not similarly marked), but this could be considered unnecessarily heavy-handed. The author’s recommendation is therefore to exactly match the selector and importance of each rule you need to override, relying on ordering to determine the precedence.

Other adjustments to the layout

The effect of setting the display attribute of an element to none is to cause the page to be rendered as if that element were absent. The resulting appearance of the page will depend on how flexible or brittle the original stylesheet was:

As an example of how margins might be adjusted, consider the following two-column layout where an element containing navigational links has been floated to the right:

#content {
  margin-right: 12em;
}

#navigation {
  display: float;
  float: right;
  width: 12em;
  margin-left: -12em;
}

@media print {
  #content {
    margin-right: 0;
  }

  #navigation {
    display: none;
  }
}

In the normal course of events the content is given a right margin of 12em in order to make space for the navigational links. This is unnecessary when printing and would leave an area of white space on the page, so the margin has been reset to its normal value of zero.

Testing

For testing it should be sufficient to use the print preview mode of a browser which has that capability. (The CSS specification explicitly states that the print media type is intended to apply to print preview mode as well as to actual printing. Most of the test results listed above were obtained in this manner.

See also

Further reading

Tags: css | html | xhtml