DEV Community

Andreas
Andreas

Posted on • Originally published at Medium

PrintCSS: Page Selectors and Page Breaks

In this article, you will learn everything about page selectors and breaks. Both are very important when you plan to style a multi-page publication, like booklets.

You will learn how to start each chapter on a separate page and style the left and right pages differently.

Page Selectors and Breaks

Using the ‘@page’ rule, you can give a general style to all pages. But if you want to be more specific, page selectors like left, right, and first need to be used.

To see how these selectors work, let us start with a basic multi-page document. You can copy below HTML and CSS code into the printcss.live editor to follow this article.

HTML:

<div class="headerLeft">
  Page Selectors
</div>
<div class="headerRight">
  A sample document
</div>

<div class="footerLeft">
  <img src="[https://printcss.live/img/logo.png](https://printcss.live/img/logo.png)" />
</div>
<div class="footerRight">
  <a href="[info@azettl.net](mailto:info@azettl.net)">[info@azettl.net](mailto:info@azettl.net)</a><br />
  <a href="[https://printcss.live/](https://printcss.live/)">printcss.live</a>
</div>

<div class="toc">
  <h1>Table of contents</h1>
  <a href="#running">PrintCSS: Running Headers and Footers</a>
  <a href="#toc">PrintCSS: Table of Contents</a>
  <a href="#footnotes">PrintCSS: Footnotes</a>
</div>

<div class="content">
  <h1 id="running">PrintCSS: Running Headers and Footers</h1>
  <p>
    If you want to use HTML inside the page margin boxes, you will need to use running elements. These elements are normal HTML nodes with the CSS position property set to 'running(NAME)'.
  </p>
  <p>
    The name given to the running element is used within the page margin boxes to set their content to the running elements inner HTML.
  </p>
  <p>
    To do so, you need to set the specific page margin box's CSS content property to 'element(NAME)', where NAME is the given running element name.
  </p>
  <p>
    Elements with the position running do not appear in the document until you assign them to some CSS content property.
  </p>
  <p>
    Your running elements must come first in your HTML structure. For example, if you put the footer element before the closing body tag, the running footer will only appear on the last page.
  </p>

<h1 id="toc">PrintCSS: Table of Contents</h1>

<p>A very common use case for your PrintCSS document is creating a table of contents. But how would you know the page numbers of your chapters before you render the document? The content takes as many pages as it needs and if your content is dynamic it is impossible to say how many pages a chapter would result in.</p>

<p>Before we start with our table of contents we will need some content to create the table for. So let's take the result from my previous article PrintCSS: Running Headers and Footers and extend the content.</p>

  <h1 id="footnotes">PrintCSS: Footnotes</h1>

  <p>Footnotes play an important role when it comes to creating books or PDF documents in general. Unfortunately, not all PDF rendering tools are supporting the W3C draft yet. While the commercial tools all have a good integration of the draft, most open-source tools lack support for footnotes completely.</p>
  <p>Still, in this article, I will explain the W3C footnote draft to you, and we will see the rendering result with the different tools.</p>
</div>
Enter fullscreen mode Exit fullscreen mode

CSS:

@page  {
  size: A6;
  margin: 20mm;

@top-left{
    content: element(headerLeft);
    border-bottom:2px solid #434190;
  }

@top-center{
    border-bottom:2px solid #434190;
  }

@top-right{
    content: element(headerRight);
    border-bottom:2px solid #434190;
  }

@bottom-right {
    content: element(footerRight);
    border-top:2px solid #434190;
  }

@bottom-center{
    content: counter(page) ' / ' counter(pages);
    border-top:2px solid #434190;
    font-size:8pt;
  }

@bottom-left{
    content: element(footerLeft);
    border-top:2px solid #434190;
  }
}

.headerLeft{
  position: running(headerLeft);
  font-size:12pt;
}

.headerRight{
  position: running(headerRight);
  font-size:8pt;
  font-style: italic;
  text-align: right;
  color:#667eea;
}

.footerLeft{
  position: running(footerLeft);
}

.footerLeft img{
  width:20mm;
}

.footerRight{
  position: running(footerRight);
  text-align: right;
  font-size:8pt;
}

.toc{
  break-after:always;
  page-break-after:always;
}

.toc a{
  display:block;
}

.toc a::after { 
  content: leader(".") target-counter(attr(href), page); 
}
Enter fullscreen mode Exit fullscreen mode

Now let us add a cover page.

...

**<div class="cover">
  <h1>Cover Page</h1>
</div>**

<div class="toc">
...
Enter fullscreen mode Exit fullscreen mode

For this, we will already make use of the ‘break-after’ property. This way, we ensure that only our cover text is on the first page. For compatibility, we will also add the ‘page-break-after’ property.

.cover{
  break-after:always;
  page-break-after:always;
}
Enter fullscreen mode Exit fullscreen mode

The new cover page.The new cover page.

First Page

But still, the first page has the same header and footer as all other pages. Usually, you do not want the same or any header/footer on the first page. To remove this information, you can use the ‘:first’ pseudo-class. Within this selector, you can give the first page different content in the page margin boxes.

@page:first{
  @top-left{
    content:"";
    border-bottom:none;
  }

  @top-center{
    border-bottom:none;
  }

  @top-right{
    content:"";
    border-bottom:none;
  }

  @bottom-right {
    content:"";
    border-top:none;
  }

  @bottom-center{
    content:"";
    border-top:none;
  }

  @bottom-left{
    content:"";
    border-top:none;
  }
}
Enter fullscreen mode Exit fullscreen mode

First page with empty page margin boxes.First page with empty page margin boxes.

Looking at the above screenshot, you see the difference between the first and second page. You see that the third and fourth page still have the same header/footer in the below screenshot.

The third and fourth page.The third and fourth page.

Left and Right Pages

Another common use case is printing the page numbers on the outside bottom corner of your page. Or showing the chapter’s title only on the left page. So to differ between the pages you can use the ‘:left’ and ‘:right’ pseudo-classes.

Picture by Tamara Gak @tamara_photography, [https://unsplash.com/photos/IBXcdiq-o0A](https://unsplash.com/photos/IBXcdiq-o0A)Picture by Tamara Gak @tamara_photography, https://unsplash.com/photos/IBXcdiq-o0A

We need to define different content in the page margin boxes for the left and right pages to achieve this.

...
@page:left{
  @bottom-left {
    content:"I am a left page";
    border-top:2px solid #434190;
    font-size:8pt;
  }
}

@page:right{
  @bottom-right {
    content: "I am a right page";
    border-top:2px solid #434190;
    font-size:8pt;
  }
}
...
Enter fullscreen mode Exit fullscreen mode

You can see that we overwrite the bottom page margin boxes for the right and left pages in the CSS code above.

Left and right pagesLeft and right pages

Now let’s put the page numbers to the outside and hide the rest.

...
@page:left{
  @bottom-right {
    content:"";
    border-top:2px solid #434190;
  }

  @bottom-center{
    content:"";
    border-top:2px solid #434190;
  }

  @bottom-left{
    content: counter(page) ' / ' counter(pages);
    border-top:2px solid #434190;
    font-size:8pt;
  }
}

@page:right{
  @bottom-right {
    content: counter(page) ' / ' counter(pages);
    border-top:2px solid #434190;
    font-size:8pt;
  }

  @bottom-center{
    content:"";
    border-top:2px solid #434190;
  }

  @bottom-left{
    content:"";
    border-top:2px solid #434190;
  }
}
...
Enter fullscreen mode Exit fullscreen mode

Adjusted Page Numbers on Left and Right PagesAdjusted Page Numbers on Left and Right Pages

Blank Pages

Now what to do about empty pages? Most of the time, you do not want a page number or any header on pages without content. For this, there is a pseudo-class called ‘blank’.

Let us first prepare our document again, so we let each chapter start on a right page. With this, the left page might be empty in some cases, as the previous chapter’s content could end on a right page.

Look at the CSS below. Instead of passing an ‘always’ to the ‘break-before’, we pass a ‘right’. This way, the content of a chapter will always start on an right page.

.content h1{
  break-before:right;
  page-break-before:right;
}
Enter fullscreen mode Exit fullscreen mode

The screenshot below shows how the chapter’s content starts on the right page, and the left page is empty.

Left Page without ContentLeft Page without Content

Not empty, though, as we still have the header and footer. Now, let’s use the ‘blank’ pseudo-class and remove those.

@page:blank  {

  @top-left{
    content:"";
    border-bottom:none;
  }

  @top-center{
    content:"";
    border-bottom:none;
  }

  @top-right{
    content:"";
    border-bottom:none;
  }

  @bottom-right {
    content:"";
    border-top:none;
  }

  @bottom-center{
    content:"";
    border-top:none;
  }

  @bottom-left{
    content:"";
    border-top:none;
  }
}
Enter fullscreen mode Exit fullscreen mode

A empty left page.A empty left page.

All examples in this article were rendered with PDFreactor. You can try the other PDF rendering tools too. These samples will work with most of them!

Another topic which I will cover in a different article is ‘named pages’. So if you liked the content of this article, follow my blog for more!

Top comments (0)