• Designing For Print With CSS
  • By Rachel Andrew
  • The Nuggets translation Project

In this article, we’ll explore CSS modules that are not intended for use in web browsers, but for use in print and paged media. I’ll explain how the selectors, attributes, and values introduced here work. At the end I’ll give you a practical example that you can use as a training tool. In this example, the proxy service file is used for this particular CSS style. I’m going to use Prince, which is a commercial product but there’s a free version available for non-commercial use, and it’s a great tool to practice with.

Why print files with HTML and CSS

It may seem odd that even content that is not intended for publication on a web page is formatted using HTML and CSS. But look at the mainstream ebook formats, such as EPUB and MOBI, which are based on HTML and CSS. In addition, even though some manuscripts and table of contents will most likely not be posted to a web site, using HTML as a standardized typesetting tool is much more convenient and easy to process than using traditional desktop document editing tools, such as Word documents.

The difference between CSS styles on a web page and those used for printing

The biggest difference, and conceptual shift, is that printed files are meant to use a fixed page size. We don’t usually limit the viewport size on web pages, but for printed documents, fixing the size of each page is a crucial step. Because of the fixed size of the pages, we must think of our documents as collections of pages — paged media, rather than a single page of continuous web documents.

Paging media introduces the concept of meaningless web pages. For example, page numbers are generated in paging media, section titles are generated in the margins, content is segmented so that it does not depart from the description headings, and so on. You may need to create cross-references and footnotes, indexes, and table of contents for your content. You can do this manually in a desktop layout tool step by step, only to repeat the process the next time you update the content. This is where CSS comes in, and its specification is designed to create paged media.

Because of these specifications for paging media, we won’t consider browser compatibility in this article, because it doesn’t make much sense. Later, we’ll look at a proxy service that uses these specifications to convert HTML – and CSS-BASED documents to PDF.

specification

The following CSS style features are useful for typography, including the “paged media module” and “paged Media CSS generation content” specifications. Here’s how they work:

@ page rules

The @page rule allows you to regulate every aspect of a page frame. For example, you want to specify the page size. The following example uses this rule to specify a default page size of 5.5×8.5. If you want to print a book on demand, it’s crucial to find a size you can use.

@page {
  size: 5.5 in 8.5 in;
}
Copy the code

In addition to specifying size with specific values, you can also use certain paper size keywords, such as “A4”, “legal”.

@page {
  size: A4;
}
Copy the code

You can also specify the direction of the page using the page orientation keywords – “portrait”, “landscape”.

@page {
  size: A4 landscape;
}
Copy the code

Understanding the page model

Before we go any further, we need to understand how the page model works in paging media, because it works a little differently than it does on screen.

The page model defines a page area with 16 margin box models. You can control the size of the page area and the margin between the edge of the page area and the end of the page itself. The size of these boxes is well explained by the following specification table.

A page area is the space on a page where your content flows, and when that space runs out, the next page is created. These margin boxes can only be used for CSS generated content.

“Left” and “right” pages

Another use of the page model is that it defines pseudo-class selectors for “left page” and “right page.” If you can take a close look at any printed book you have, you will probably notice that the margins on the left and right pages are different in size and content.

We can use these selectors to define the margin size of our page.

@page :left {
  margin-left: 3cm;
}

@page :right {
  margin-left: 4cm;
}
Copy the code

There are two other pseudo-class selectors. The :first selector locates the first page of the document.

@page :first {

}
Copy the code

The :blank pseudo-class selector will locate pages with “white space”. To add the following text, use the top-center margin box to locate it at the top center of the page.

@page :blank {
  @top-center { content: "This page is blank."}}Copy the code

Paging media and content generation

In the code example above, we used CSS content generation to add text to the top center margin box of the page. As you can see, content generation is very important in creating our book. This is the only way we can add content to the page margin box. For example, if we want to add a title to the bottom left margin box on the right side of the page, we can use CSS content generation.

@page:right{ 
  @bottom-left {
    margin: 10pt 0 30pt 0;
    border-top:.25pt solid # 666;
    content: "My Book";
    font-size: 9pt;
    color: # 333; }}Copy the code

Page break

Information on how to control page breaks is also part of the “paging media” specification, which, as mentioned earlier, moves content to a new page whenever it fills a page space. When you want to put a title on a page, and the title is at the end of the page, and the content related to the title moves to the next page, that’s what you want to avoid when printing a book. In another case, you want to avoid breaking tables or images with their descriptions.

At the beginning of a new chapter in a book, it is common to use the h1 as the heading style. To make the title always at the beginning of a page, set the page-break-before property to always.

h1 {
  page-break-before: always;
}
Copy the code

To avoid page breaks after headings, use the page-break-after property and set the value to avoid.

h1.h2.h3.h4.h5 {
  page-break-after: avoid;
}
Copy the code

To avoid page breaks within elements such as tables and images, use the page-break-inside property and set the value to avoid.

table.figure {
  page-break-inside: avoid;
}
Copy the code

counter

Books have many things to count — page numbers, chapter numbers, etc. We can add these numbers using CSS to help us not have to renumber the rest of the content by adding a new number halfway through. CSS counters help us do this.

First, page numbers are the most obvious. CSS provides a predefined page counter that starts at 1 and increments with each new page created. In your stylesheet, you will use this counter as the value of the generated content, placing the page counter in one of your blank boxes. In the following example, add a page number to the bottom right of the right page and the bottom left of the left page.

@page:right{
  @bottom-right {
    content: counter(page); }}@page:left{
  @bottom-left {
    content: counter(page); }}Copy the code

We can also create a counter called Pages, which will be the total page number of the document. Can be used in display such as “Page 3 of 120” (total Page 120 – Page 3) :

@page:left{
  @bottom-left {
    content: "Page " counter(page) " of " counter(pages); }}Copy the code

If necessary, you can also create your own custom named counters and reset increments as needed. To create a timer, use the counter-reset property to reset the counter value and use the counter-increment to increment the counter value by a given value. The following example creates a counter named chapternum for chapters in CSS and increments each h1 style heading (the beginning of each chapter) when used. The value of this timer is then used in content generation, and the actual title of each chapter is automatically preceded by the chapter number and.

body {
  counter-reset: chapternum;
}

h1.chapter:before {
  counter-increment: chapternum;
  content: counter(chapternum) ".";
}
Copy the code

We can apply the same method to some of the descriptive charts in the book. A common approach is to encode diagrams with chapternum.figurenum. For example, “Figure 3-2” represents the second icon in Chapter 3. In the header with style H1, we will reset the figurenum so that in each chapter the counter will count from the beginning.

body {
  counter-reset: chapternum figurenum;
}

h1 {
  counter-reset: figurenum;
}

h1.title:before {
  counter-increment: chapternum;
  content: counter(chapternum) ".";
}

figcaption:before {
  counter-increment: figurenum;
  content: counter(chapternum) "-" counter(figurenum) ".";
}
Copy the code

Default string

Look at a paper book. When you flip through a chapter in a book, you may see the title of the chapter printed on the top left or right. The “content generation of paged media” specification in CSS allows us to do this.

We’ll use a property called string-set in the selector to set what we want to get. To set to the section title, the selector is H1. The value of the string-set property is the title you want to set (doctitle for example) plus content(). You can use string() wherever you want.

h1 { 
  string-set: doctitle content(a); }@page :right {
  @top-right {
    content: string(doctitle);
    margin: 30pt 0 10pt 0;
    font-size: 8pt; }}Copy the code

When your paged media is generated, each time an H1 tag is generated, the content is written to the corresponding doctitle, which is then printed in the upper right part of the right page, and only changes as another H1 is written.

Footnotes

footnotes

Footnotes are also part of the CSS paging media content generation specification. The way a footnote works is that the text of the footnote is added inline to the footnote, wrapped with an HTML (which can be a SPAN) tag, and the class defined as FN indicates that it is the tag used for the footnote. When rendered to a page, the contents of the “footnote element” are automatically converted to a predefined style footnote.

In your CSS stylesheet, create a rule for your footnote class selector with the float property set to footnote.

.fn {
  float: footnote;
}
Copy the code

Use this selector to wrap all the footer text in your HTML document.

<p>Footnotes<span class="footnotes">Footnotes and notes placed in the footer of a document to reference the text. The footnote will be removed from the flow  when the page is created.</span> are useful in books and printed documents.</p>
Copy the code

Footnotes have a predefined counter that works the same way as the page count counter mentioned above. In general, you’ll want to increase the counter count by one each time an FN class appears and reset the counter at the beginning of each chapter.

.fn {
  counter-increment: footnote;
}

h1 {
  counter-reset: footnote;
}
Copy the code

Sections of footnotes can be located using CSS pseudo-elements. Footnote-call is a numeric anchor in the text, indicating that this is a footnote content that will be generated using the count of the footnote counter.

.fn::footnote-call {
  content: counter(footnote);
  font-size: 9pt;
  vertical-align: super;
  line-height: none;
}
Copy the code

Footnote-markers are numeric markers placed in front of the footnote text of a document. These markers count in a similar way to the numbers generated for ordered lists in CSS.

.fn::footnote-marker {
  font-weight: bold;
}
Copy the code

The footnote itself is placed in the margin, in a special area of the page called @footnote. You can use this area as a target and style, as shown below.

@page {
  @footnote {
    border-top: 1ptsolid black; }}Copy the code

Cross reference

Before putting everything we’ve learned into practice, let’s take a look at cross-referencing. On the web content, we cross-reference material by adding links. In a book or other printed document, you will usually list the page number of the reference. Because page numbers can change depending on the print format and edition of a book, using CSS saves us the trouble of changing all the page numbers.

We use another new property, target-counter, to add the numeric text. Start by creating links in your document and giving them an href, which is the identity of the target content of that element in your document. Also, add a class selector to indicate that they are cross-references, not external links; You can use the Xref attribute.

<a class="xref" href="#ch1" title="Chapter 1">Chapter 1</a>
Copy the code

Then, after the link, output the generated content again (page X), where x is the numbered ID of the location in the book where the content can be found (corresponding to the href set above).

a.xref:after {
  content: " (page " target-counter(attr(href, url), page) ")";
}
Copy the code

A similar operation is used in practice when creating a directory for a document.

Put it all together: Write a book

We’ve looked at a lot of different technologies before, but putting them into practice will give you a deeper understanding.

To actually write a book using print style CSS, you need a user agent service that supports it. Currently, there are few services that implement this specification well. The easiest to get started with was Prince. Prince’s independent commercial license is expensive, however, you can use Prince for free for non-commercial projects. Which means, if you want to try Prince, Also, if you do have a non-commercial use for this technology, you can use Prince to format these books.

I took some excerpts from one of my favorite books on Project Gutenberg, Harrison Weill’s Our Cat. I chose this book because I love cats and it has pictures and footnotes THAT I can use to demonstrate formatting.

You can find the files I used and the resulting PDF on GitHub. If you want to experiment with CSS and make the book yourself, you’ll need to download and install Prince. Prince is a command-line tool for Mac, and I like the command line because it’s really simple, even though there’s a Windows version of the graphical interface.

Using the terminal window, switch to the directory of your book or the location where you downloaded my files from GitHub.

cd /Users/username/smashing-css-books
Copy the code

Now, run Prince.

prince -s pdf-styles.css book.html builds/book.pdf
Copy the code

This will create a PDF file called book.pdf in the Builds folder. Now, if you make any changes to your CSS or HTML, you can run Prince to see the difference.

An HTML document

My entire “book” is compiled in a single HTML document. Compiling documents with Prince is possible, but I find it easier to work with just one large document. Before the chapter that starts with “H1”, I have a DIV that contains the cover image, and then the table of contents for the book.

Table of contents links to the ID of the H1 heading of each chapter.

<! DOCTYPEhtml>
<html dir="ltr" lang="en-US">
  <head>
  <meta charset="utf-8" />
  <title>Our Cats and All About Them</title>
  <meta name="author" content="Harrison Weir"/>
  <meta name="subject" content="Cats. Their Varieties, Habits and Management; and for show, the Standard of Excellence and Beauty"/>
  <meta name="keywords" content="cats,feline"/>
  <meta name="date" content="2014-12-05"/>
  </head>
  <body>
    <div class="frontcover">
    </div>
    <div class="contents">
      <h1>Extracts from Our Cats and All About Them by Harrison Weir</h1>

        <ul class="toc">
          <li><a href="#ch1">The First Cat Show</a></li>
          <li><a href="#ch2">Trained Cats</a></li>
          <li><a href="#ch3">General Management</a></li>
          <li><a href="#ch4">Superstition and Witchcraft</a></li>
        </ul>

    </div>

    <h1 id="ch1" class="chapter">The First Cat Show</h1>
      <p>...</p>

    <h1 id="ch2" class="chapter">Trained Cats</h1>
      <p>...</p>

    <h1 id="ch3" class="chapter">General Management</h1>
      <p>...</p>

    <h1 id="ch4" class="chapter">Superstition and Witchcraft</h1>
      <p>...</p>

  </body>
</html>
Copy the code

Then, CSS uses everything we’ve described so far. First, we need to set a size for the book using the @page rule. Then we use the :first pseudo-class selector to remove the margins on page 1, because this page will have the cover image.

@page {
  size: 5.5 in 8.5 in;  
  margin: 70pt 60pt 70pt;
}

@page:first {
  size: 5.5 in 8.5 in;  
  margin: 0;
}
Copy the code

Then we process the cover image to make sure it covers the entire page area.

div.frontcover { 
  page: cover; 
  content: url("images/cover.png");
  width: 100%;
  height: 100%; 
}
Copy the code

Next, we use :right and :left pseudo-class selectors to handle the details of the left and right pages.

The bottom left corner of the right page is the title of the book, the bottom right corner is the page number counter, and the top right corner is the chapter title. Section titles are further set using string-set in the stylesheet.

@page:right{ 
  @bottom-left {
    margin: 10pt 0 30pt 0;
    border-top:.25pt solid # 666;
    content: "Our Cats";
    font-size: 9pt;
    color: # 333;
  }

  @bottom-right { 
    margin: 10pt 0 30pt 0;
    border-top:.25pt solid # 666;
    content: counter(page);
    font-size: 9pt;
  }

  @top-right {
    content:  string(doctitle);
    margin: 30pt 0 10pt 0;
    font-size: 9pt;
    color: # 333; }}Copy the code

The left panel has the title at the bottom right and the page counter at the bottom left.

@page:left {
  @bottom-right {
    margin: 10pt 0 30pt 0;
    border-top:.25pt solid # 666;
    content: "Our Cats";
    font-size: 9pt;
    color: # 333;
  }

  @bottom-left { 
    margin: 10pt 0 30pt 0;
    border-top:.25pt solid # 666;
    content: counter(page);
    font-size: 9pt; }}Copy the code

For the first page that contains the cover image, we will make sure that no generated content appears and set it to Normal.

@page:first {
  @bottom-right {
    content: normal;
    margin: 0;
  }

  @bottom-left {
    content: normal;
    margin: 0; }}Copy the code

The next section of the stylesheet deals with counters. In addition to the preset page counters, we also defined counters for sections and numbers.

/* Reset chapter and figure counters on the body */
body {
  counter-reset: chapternum figurenum;
  font-family: "Trebuchet MS"."Lucida Grande"."Lucida Sans Unicode"."Lucida Sans", Tahoma, sans-serif;
  line-height: 1.5;
  font-size: 11pt;
}

/* Get the title of the current chapter, which will be the content of the h1.
Reset figure counter because figures start from 1 in each chapter. */
h1 {
  string-set: doctitle content(a);page-break-before: always;
  counter-reset: figurenum;
  counter-reset: footnote;
  line-height: 1.3;
}

/* Increment chapter counter */
h1.chapter:before {
  counter-increment: chapternum;
  content: counter(chapternum) ".";
}

/* Increment and display figure counter */
figcaption:before {
  counter-increment: figurenum;
  content: counter(chapternum) "-" counter(figurenum) ".";
}
Copy the code

Chapter numbers now precede titles. Numbers also display their numbering.

We create the footnote as explained earlier, superscripting the call to the footnote.

.fn {
  float: footnote;
}

.fn {
  counter-increment: footnote;
}

.fn::footnote-call {
  content: counter(footnote);
  font-size: 9pt;
  vertical-align: super;
  line-height: none;
}

.fn::footnote-marker {
  font-weight: bold;
}

@page {
  @footnote {
    border-top: 0.6 pt solid black;
    padding-top: 8pt; }}Copy the code

Then we add some rules to control the interruption of the page. You need to be quite careful not to be too strong on this. If your book has a lot of tables and numbers, adding a lot of specific rules here can result in a lot of long gaps in the book. Experiments and tests will show how much control you can have over sentence breaks. I’ve found the following rules to be a good starting point.

Keep in mind that this is a recommendation for user agents. In some cases, if the table does not fit on the page, it will be impossible to keep the table uncorrupted.

h1.h2.h3.h4.h5 {
  font-weight: bold;
  page-break-after: avoid;
  page-break-inside:avoid;
}

h1+p.h2+p.h3+p {
  page-break-before: avoid;
}

table.figure {
  page-break-inside: avoid;
}
Copy the code

Finally, we style the directory, where we use an interesting trick. In describing the cross-reference, I explained how we used target-counter to display the page number of the ID. That’s what we’re going to do for our catalog. The following rule places the page number after the link to each chapter in the table of contents.

ul.toc a::after {
  content: target-counter(attr(href), page);
}
Copy the code

In books, however, you usually use the lead dot to place all the page numbers in the right-hand margin. Surprisingly, CSS gives us a way to do this by adding leader() to the number in the generated content.

ul.toc a::after {
  content: leader('. ') target-counter(attr(href), page);
}
Copy the code

We now have a complete style sheet that we can use to make our book. I avoid spending a lot of time on typography here and concentrate on the nuts and bolts of creating a book. However, starting from this point, you can experiment and add your own style to create a unique book design.

Don’t limit yourself to books!

Keep in mind that these techniques aren’t just for books. You can use them to generate print and PDF versions of product catalogs directly from the HTML of websites you develop for clients. Or you can create flyers and brochures from web content.

If you want to use Prince to create PDF documents from websites, DocRaptor is a good choice. The service uses Prince through an API. You can send files and receive PDFS via the API — perfect for users to download content in PDF format at any time. Everything we’ve seen in this article can be done by integrating with DocRaptor’s API.

Even if you don’t have an immediate need to generate a PDF, this is one of the fascinating aspects of CSS — it’s a useful skill that you can hide away so you know what to do when a use case comes up.