RenderX

Chapter 5 of the XSL-FO Tutorial

5. Page Layout

5.1. Page Sequence Masters

So far, I have used only single page masters in examples. In this section, more complex cases will be analyzed. To start, let's design a page sequence with two page masters: one for the first page, the other one for the rest of the document.

<?xml version="1.0" encoding="iso-8859-1"?>

<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <fo:layout-master-set>
    <fo:simple-page-master master-name="first-page">
      <fo:region-body margin="1in" border="thin silver ridge"❶
                                      padding="6pt"/>
    </fo:simple-page-master>
    <fo:simple-page-master master-name="all-pages">
      <fo:region-body margin="1in"/>
    </fo:simple-page-master>
    <fo:page-sequence-master master-name="my-sequence">❷
      <fo:single-page-master-reference master-reference="first-page"/>❸
      <fo:repeatable-page-master-reference master-reference="all-pages"/>❹
    </fo:page-sequence-master>
  </fo:layout-master-set>
  <fo:page-sequence master-reference="my-sequence"❺>
    <fo:flow flow-name="xsl-region-body" font="72pt Times">
       <fo:block space-before="2in" space-after="2in">❻
         First block
       </fo:block>
       <fo:block space-before="2in" space-after="2in">❼
         Second block
       </fo:block>
       <fo:block space-before="2in" space-after="2in">
         Third block
       </fo:block>
    </fo:flow>
  </fo:page-sequence>
</fo:root>

In XSL FO, you can specify borders, padding, and background on regions in exactly the same way as you do it on blocks. The first page in this example will have a border around it, while others will remain borderless.
The page sequence master defines the chain of page masters to use for a page sequence.
<fo:single-page-master-reference> inserts a single page master in the chain.
<fo:repeatable-page-master-reference> makes the specified page masters repeat up to the end of the chain.
Note that master-reference attribute of a <fo:page-sequence> can refer to either a <fo:page-sequence-master> or a <fo:simple-page-master>. In the latter, all pages generated by this <fo:page-sequence> will use the same page master.
Spaces are not inheritable: you cannot specify them on a surrounding block. There's no alternative to specifying them explicitly on every block involved.

You can also specify different page masters for odd and even pages, blank pages, first/last pages, etc. This is achieved by using a more complex sequence specifier — <fo:repeatable-page-master-alternatives>. It contains one or more <fo:conditional-page-master-reference> elements; each of these elements specifies a name of a page master and a set of conditions that should be satisfied for this page master to apply. When generating a page chain, the alternatives inside <fo:conditional-page-master-reference> are looked from left to right, and the first one for which all the conditions hold will be chosen.

In the example below, the first page will have a thin silver border around it, and all other pages will have a border along the inside edge of the body area (left for even pages, right for odd ones).

  <fo:layout-master-set>
    <fo:simple-page-master master-name="first-page">
      <fo:region-body margin="1in" border="thin solid silver"
                                   padding="6pt"/>
    </fo:simple-page-master>
    <fo:simple-page-master master-name="odd-page">
      <fo:region-body margin="1in" border-right="medium gray ridge"
                                   padding-right="6pt"/>
    </fo:simple-page-master>
    <fo:simple-page-master master-name="even-page">
      <fo:region-body margin="1in" border-left="medium gray ridge"
                                   padding-left="6pt"/>
    </fo:simple-page-master>
    <fo:page-sequence-master master-name="my-sequence">
      <fo:repeatable-page-master-alternatives>
        <fo:conditional-page-master-reference page-position="first"
                                              master-reference="first-page"/>
        <fo:conditional-page-master-reference odd-or-even="odd"
                                              master-reference="odd-page"/>
        <fo:conditional-page-master-reference odd-or-even="even"
                                              master-reference="even-page"/>
      </fo:repeatable-page-master-alternatives>
    </fo:page-sequence-master>
  </fo:layout-master-set>
  <fo:page-sequence master-reference="my-sequence">
    …
    …
    …

5.2. Areas, Flows, Static Contents

So far, I only placed the contents into the body region of the page master. There are other regions on the page, used to display static elements of page layout — headers, footers, and sidebars. Inside page master, there may be up to five region specifications:

  • <fo:region-body> the central part of the page; required

  • <fo:region-before> header region

  • <fo:region-after> footer region

  • <fo:region-start> left sidebar region

  • <fo:region-end> right sidebar region

The dimensions of the regions are calculated by the following algorithm:

  1. The page size is controlled by page-height and page-width properties of the <fo:simple-page-master>. There also exists a size shorthand property to set the page size. Worth noting are "portrait" and "landscape" values to set the default page size with different orientation.

  2. The size of region-body is determined by margins around it (calculated from page bounding rectangle).

  3. All other regions stick to the correspondent edge on the page. Their width/height is given by the extent property. Note that side regions does not influence the position of the region-body; so, the correspondent margin of the region-body must be wide enough for the side regions to fit — not less than the extent of the correspondent side region.

  4. To control the allocation of page corners to either sidebars or headers/footers, a special precedence attribute is used on side regions: if set to "true", its bearer captures the corner. In case of equal precedences, headers/footers win.

All regions may have borders, padding and background. However, the XSL 1.0 Recommendation is contradictory with respect to borders and padding on all region areas but <fo:region-body>: the respective properties are listed, but there is a notice in the text that requires borders and padding to be 0. IREn implements borders and padding on all regions, but you are warned.

Regions are named using a special region-name property. This property has a different default value for each of the regions:

  • "xsl-region-body" for <fo:region-body>,

  • "xsl-region-before" for <fo:region-before>,

  • "xsl-region-after" for <fo:region-after>,

  • "xsl-region-start" for <fo:region-start>,

  • "xsl-region-end" for <fo:region-end>.

To put contents into side regions, a special formatting object — <fo:static-content> — is placed inside <fo:page-sequence>. It is bound to a specific region by the flow-name property that should match the region-name of a region in a page-master. The contents of a <fo:static-content> is formatted in the respective region on every page produced by this page-master.

Let us now look at the examples. The simplest example just adds a header to “Hello, world!”:

  <fo:layout-master-set>
    <fo:simple-page-master master-name="my-page">
      <fo:region-body margin="1.5in 1in"❶/>
      <fo:region-before extent="1.5in"
                        padding="6pt 1in"
                        border-bottom="0.5pt silver solid"
                        display-align="after"❷/>
    </fo:simple-page-master>
  </fo:layout-master-set>
  <fo:page-sequence master-reference="my-page">
    <fo:static-content flow-name="xsl-region-before"❸
                       font="italic 10pt Times">
       <fo:block>"Hello, world!" Example</fo:block>
    </fo:static-content>
    <fo:flow flow-name="xsl-region-body">
       <fo:block>Hello, world!</fo:block>
    </fo:flow>
  </fo:page-sequence>

Margins can be set by multiple values inside the margin shorthand: assignment of values to sides is the same as for padding.
display-align specifies the alignment of the contents inside the area. It is a common technique to set it to "before" for headers.
The default name for the header region is used.

Another example uses sidebars. It draws a right sidebar on odd pages, and a left sidebar on even pages:

  <fo:layout-master-set>
    <fo:simple-page-master master-name="even-page">
      <fo:region-body margin="1in 1.5in"
                      column-count="2"❶ column-gap="0.5in"/>
      <fo:region-start extent="1.5in"
                       region-name="my-left-sidebar"
                       reference-orientation="90"❷
                       padding="6pt 1in"
                       border-right="0.5pt silver solid"❸
                       display-align="after"/>
    </fo:simple-page-master>
    <fo:simple-page-master master-name="odd-page">
      <fo:region-body margin="1in 1.5in"
                      column-count="3"❹ column-gap="0.5in"/>
      <fo:region-end   extent="1.5in"
                       region-name="my-right-sidebar"
                       reference-orientation="-90"
                       padding="6pt 1in"
                       border-left="0.5pt silver solid"
                       display-align="after"/>
    </fo:simple-page-master>
    <fo:page-sequence-master master-name="my-sequence">
      <fo:repeatable-page-master-alternatives>
        <fo:conditional-page-master-reference odd-or-even="odd"
                                            master-reference="odd-page"/>
        <fo:conditional-page-master-reference odd-or-even="even"
                                            master-reference="even-page"/>
      </fo:repeatable-page-master-alternatives>
    </fo:page-sequence-master>
  </fo:layout-master-set>
  <fo:page-sequence master-reference="my-sequence">
    <fo:static-content flow-name="my-left-sidebar"
                          font="italic 10pt Times">
       <fo:block text-align="end">
         Left sidebar on an even page
       </fo:block>
    </fo:static-content>
    <fo:static-content flow-name="my-right-sidebar"
                          font="italic 10pt Times">
       <fo:block text-align="start">
         Right sidebar on an odd page
       </fo:block>
    </fo:static-content>
    …
    …
    …

Body region may have multiple columns; other regions may not. The last attribute specifies the gap between columns.

Note: Number of columns may differ across pages within a single flow. In this example, all odd pages will have three columns while all even pages will have two.

reference-orientation attribute specifies rotation of coordinate axes for the region; its value is an angle of rotation counterclockwise (in degrees; must be multiple of 90; negative values rotate clockwise).

Note that sides of the region are referenced with respect to the original (not rotated) orientation!

Download the complete XSL-FO Tutorial as PDF