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:
-
The page size is controlled by
page-heightandpage-widthproperties of the<fo:simple-page-master>. There also exists asizeshorthand property to set the page size. Worth noting are"portrait"and"landscape"values to set the default page size with different orientation. -
The size of region-body is determined by margins around it (calculated from page bounding rectangle).
-
All other regions stick to the correspondent edge on the page. Their width/height is given by the
extentproperty. 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 theextentof the correspondent side region. -
To control the allocation of page corners to either sidebars or headers/footers, a special
precedenceattribute 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 that sides of the region are referenced with respect to the original (not rotated) orientation! |