Making books with HTML + CSS — a look at Vivliostyle (Part 1 – page layouts)

Before you read further, the following information has been gathered in the process of making experimental books with Vivliostyle. As the specs are a little old and pretty experimental, I can’t guarantee you would necessarily get the same results as I did. Also, if you have used the tool and have found any other ways to do what I did, please feel free to start a conversation about that. I’d be happy to share what is known and see how we can make it work better/further. Thanks for reading!

A history of css-regions

It was a dark and stormy night. A team of Adobe’s developers offered web designers the possibility of producing magazine-like layout by using different placeholders for a different kind of content, using elements they named CSS-Regions. To achieve this, they came up with the idea of flows which would describe how the content is truncated and where it should go. When designing a novel, for example, you need to create rules for the locations of page numbers, running headers and the text box for each page, and when using InDesign, the text flow from one page to another, or, more precisely, from one main text box to the next one. With CSS-regions, the ability to divide content into different boxes became a reality. In the International Digital Publishing Forum (aka IDPF) issued specifications for EPUB adaptive layout which “defines a model for template-based adaptive paginated layouts as an extension to CSS.” In other terms, it was an epub-in-browser rendering project, showing content as a real book, with defined locations for the elements of the page. Using page masters and partitions, the look and feel of the content started to feel more and more like a book, with pages, page numbers, running headers and so on. For a while, this method only worked in the applications that IDPF produced, and, therefore, was nothing more than an excellent example of how content could be rendered on screen.

Vivliowhat?

In September, Vivliostyle’s  beta was released. Working as a polyfill for IDPF’s adaptive layout, Vivliostyle’s environment gave web designers the opportunity to create books in a browser.

thoughts about open source
A book in the browser.

How does it work?

Vivliostyle is working closely with W3C on the paged media css specifications. Though those specifications were still in working draft, they added the possibility to describe content using the CSS from the adaptive layout specifications. For an example of what can be done in Vivliostyle, let’s look at the making of the Cabbage Tree Method book, which I  recently designed. Here’s how I made it. Everything is made with html and css.

What makes a book?

A book is an artifact in three dimensions: width, height and thickness. While width and height are chosen to efficiently display the content, the thickness is the result of those choices. The best book is the one that focuses on readability without losing its three-dimensional aspects: to have something that looks and feels like a book, you need a minimum of pages, therefore you need to have the right height/width/content ratio. To design a book, you need to be aware of its content. How much text? Are there any illustrations? Are there notes and/or quotes? What does it need to have to feel like a book? First, when designing a book, you need a format. We went with a dimensionally small-sized book, appropriate to the amount of content. To do so, in the css, just add this:

@page {  
  size: 125mm 210mm;  
}

The @page element lets you describe the size of your page. The Cabbage Tree Method book has a width of 125mm and a height of 210mm.

Page masters & flows

Vivliostyle works like InDesign. When you’re making a book with InDesign, you need to design the page masters that will be used for different pages of the book. For the Cabbage Tree Method book, we have four different page masters:

  • the title page:  presents the title of the book, its version, the author name (if there is any), and the logos of the publisher and sponsors (as needed);
  • the table of contents: that will identify the location of each different part of the book. It needs to show the page number on which each section starts;
  • the section title page for each part or section: which shows the name of the part;
  • the chapter content (content pages): which is how the content of each chapter appears.

For each of those masters, we created a flow element saying that if there is this kind of content, then the page master chosen must be this one. Let’s look at our first section in the html:

<section data-type="titlepage">  
  <h1 id="TheCabbageTreeMethod">The Cab­bage Tree Method</h1>  
  <div class="booktitle">The Cab­bage Tree Method</div>  
  <h3 class="titlepageSub">Open Source Collaborative Product Development</h3>
  <div class="logo">  
    <img src="images/logos.png">  
     <p>The version of this book is 0.1</p>  
  </div>  
</section>

This section has a data-type of titlepage. In the css, we pass the content of this section to the titlepage flow. To do so, we add those lines to our css:

[data-type="titlepage"] {  
  -epubx-flow-into: titlepage;  
}
@-epubx-page-master titlepagepage {  
  @-epubx-partition body {  
    -epubx-flow-from: titlepage;  
    -epubx-required: true;  
  }
}

-epubx-flow-into is the attribute that seals the content to its page master. With those lines, we say that any content that has a data-type of titlepage will be sent into the body partition of the titlepage page master. -epubx-required: true; means that this pagemaster can be used only if there is a flow called titlepage. So, if there is, in the html, content that flows into the titlepage flow, then the page master used will be the titlepagepage one. Then, we need to provide a location and a width/height for this partition.

@-epubx-page-master titlepagepage {  
  @-epubx-partition body {  
    -epubx-flow-from: titlepage;  
    -epubx-required: true;  
    left: 10mm;  
    right: 10mm;  
    top: 32pt;  
    bottom: 12pc;  
  }
}

Using those lines, we draw a box that starts at 32pt from the start, 10mm from the left edge of the page and 10mm to the right edge of the page, and stops at 12pc from the bottom edge of the page. [add a picture with the location as example HERE] As you can see, we can use whatever unit we want as the browser is able to handle it. Here we have millimetres, points and picas. (I recommend that you only work with one kind of unit. The mention of multiple units is here to show that it’s possible to do so). We’ll need to do the same for all partitions of the page. This page master also has a logo partition, that describes the location of the logos on this page. Let’s add it to the css:

.logo {  
  -epubx-flow-into:  logo;  
}

Everything with a class logo will be sent to the logo flow.

  @-epubx-partition logos {  
    -epubx-flow-from: logo;  
    -epubx-required: true;  
    left: 10mm;  
    right: 10mm;  
    bottom: 4.3pc;  
  }

The logos partition will get content from the logo flow, and will put in in the logos box which starts at 4.3pc from the page bottom. You can also see how we add a blue background to the page by adding background: #435772; to the page master. Here is the complete css for the title page:

@-epubx-page-master titlepagepage {  
  @-epubx-partition body {  
    -epubx-flow-from: titlepage;  
    -epubx-required: true;  
    left: 10mm;  
    right: 10mm;  
    top: 32pt;  
    bottom: 12pc;  
  }
  @-epubx-partition logos {  
    -epubx-flow-from: logo;  
    -epubx-required: true;  
    left: 10mm;  
    right: 10mm;  
    bottom: 4.3pc;  
  }
  background: #435772  
}

With this html and css, we can see how the layout is made on the page. What you need to keep in mind is that simple rule: before choosing a pagemaster, Vivliostyle will look through your HTML content, and, depending on the -epubx-flow-into / -epubx-flow-from it will find, and will choose the page master that matches all the rules. If no rules can be fullfilled, Vivliostyle will hang because it won’t know what to do with your content, and you’ll need to close/reopen your browser.

This is what we’ll get on screen:

the cabbage tree method
This is what you can get with the HTML and CSS we just created.

Artifacts of the book

On a page of a book, there are those small indications that let you know what book you’re reading and which chapter/sections you’re in (often as running headers) and the location in of the book (often as page numbers). For quite some time now, those were almost impossible to get easily in the world of books-in-browsers. Book.js was used for cloning section and chapter headers and putting those in different locations, but you needed to change it by hand if the chapter title was too long. Page numbers had the same kind of issues, and the table of content needed some hard work to be sure it was correct. Vivliostyle has a nice way to handle those two issues. Let’s start with the easy one.

Folios (aka page numbers)

Since the css counter was made available, handling any numbering is way more time-consuming as it’s calculated in real time. For example, removing an item in a numbered list which has a counter won’t change the semantic numbering. Since paged-media CSS specifications, pages are numbered as they are generated. To add a page number to any page master, you only need to add the counter as content:

@-epubx-partition {  
  content: counter(page);  
  left: 10mm;  
  right: 10mm;  
  height: 13pt;  
  bottom: 16pt;  
  text-align: center;  
  font-family: "Cooper Hewitt";  
  font-size: 7pt;  
}

Adding this partition to any page masters will add the page number at 16pt from the bottom of the page, centred, using the Cooper Hewitt font family and with a size of 7pt.

Running headers

Running headers ask a little more work. First, in the html, they need to exist on their own. For example, we have an h2 named introduction that we want to see as our running header. We need to duplicate the content and give it a class to reuse it inside a specific flow.

<h2 id="introduction">Introduction</h2>  
<div class="dup">Introduction</div>

Even if the paged media specifications include it, we still depend on the adaptive layout specs. That’s why you need to create a specific flow for those. Let’s make one for the chapter title.

.dup {  
  -epubx-flow-into: header;  
  -epubx-flow-options: exclusive static last;  
}

-epubx-flow-into: header; means that we can use it as a flow on any page we want. But if you look at the code, we have another small line which will seriously help us for recursive information inside the book:

  -epubx-flow-options: exclusive static last;

-epubx-flow-options is a way to reuse content inside the book. As defined in the specs:

exclusive: When content is selected for a partition, elements marked as exclusive are considered first. Only one exclusive element is used for a single partition and one element is always consumed (and removed from the flow if it is not also marked as static).
static: When an element is consumed in a partition, it is removed from the flow, unless it is marked as static. Static elements are placed in the flow again when they are consumed.
last: When this option is applied to elements which are also marked exclusive, the last of them is flowed in the next available partition.

Those three options mean that: the header flow will be considered first, meaning that it will be sent to the flow first. Then, marked as static, it will be used until another element of the same flow is found in the html, and, marked as last, meaning that the only element used will be the last one (you won’t have all the previous running titles inside the flow). With this, we’ll have a flow containing the last of all running headers that we’ll be able to place on the page. Then we need to create the partition:

@-epubx-partition class(header) {  
  -epubx-flow-from: header;  
  left: 10mm;  
  right: 10mm  
  height: 13pt;  
  position: absolute;  
  top: 16pt;  
}

And then, there are running headers.

Symmetric layout

All this is perfect for the so called modern layout, as against a symmetrical one. But what if I want different right/left pages? What if I want to have the book title as a running header on the left page and chapter title on the right? Do not worry! That’s possible! Thanks to the -epubx-expr and -epubx-enabled: attributes. While -epubx-expr(); is like a grandfather of css calc() that allow you to make math expression as variable, -epubx-enabled is an attribute for partition that tell vivliostyle that the partition is enabled or not for a page master. The -epubx-expr works this way: -epubx-expr( expression ? if true do this : if false do that) For example: if we want only a page number on the right page, we can add: -epubx-enabled: -epubx-expr( page-number % 2==0 ? 1 : 0); to the pagenumber partition. Let’s translate it in a more readable way: The partition will appear on the page if the rest of the Euclidian division of the page number by two is equal to 0 —meaning it’s a left page—, otherwise, the partition won’t appear. Expressions can also be used with left and right attributes:

left: -epubx-expr( page-number % 2==1 ? 10mm: 20mm);  
right: -epubx-expr( page-number % 2==0 ? 10mm: 20mm);

If the page number is odd — meaning it’s a left page, left is 10mm, otherwise, left is 20mm; if the page number in even, right is 10mm, otherwise, right is 20mm;

A screenshot from vivliostyle showing the partitions of each page.

epubx-utilization

Last, but not least, Vivliostyle is looking quite ahead of the content to see what page master will be used and when. The result is that it can go wrong when the content for a section is too light. To avoid this kind of thing, the adaptive layout specs provide the -epubx-utilization attribute that lets you modify with a variable how far ahead it should look, specifically at the end of the chapters. While 1 is the default, using a smaller number lets you have a control over how it should work. Since it’s based on the content in the html, there is no perfect rule for this. For example, for the Cabbage Tree Method, all page master are using: -epubx-utilization: 0;. Next time, we’ll be exploring how to make cross-references inside the book, and even a table of contents!