Chapter 4 of the XSL-FO Tutorial
4. Blocks
4.1. Text Alignment, Line Height
Let's consider this piece:
<fo:block line-height="1.5" text-align="justify">
This is an example of double-justified text.
The space between lines is 1.5 of the nominal font height.
</fo:block>
The line-height property specifies the line height: it can be expressed as a length, as a numeric value, or as a percent. Numbers and percents are interpreted as multiples to the nominal font height.
Text-align property defines the alignment of the text within the block. XSL FO uses a specific coordinate system for referring to block edges: instead of ‘left’ and ‘right’, side alignment is expressed in terms of inline progression direction. For Western scripts, glyphs on the line are placed from left to right; therefore, left-aligned text will have text-align="start", and right-aligned text will have text-align="end". Two other values are "center" and "justify" (same as in CSS). You can also use other CSS values for this property — "left" is a synonym for start, and "right" is a synonym for end.
Let's look into a more complicated example:
<fo:block text-align="justify" text-indent="1in"
text-align-last="end" last-line-end-indent="1in">
This is an example of double-justified text with an indented first line.
The last line of the text is aligned to the right, and indented
by 1 inch from the right.
</fo:block>
This fragment should be formatted as follows:
-
text is double justified (
text-align); -
the first line is indented by 1 inch from the left (
text-indent); -
the last line is aligned to the right (
text-align-last); -
the last line is indented by 1 inch from the right (
last-line-end-indent).
By specifying a negative value for text-indent / last-line-end-indent, it is possible to create outdents. To make the text stay within the limits, two more properties are used that control indentation of the text as a whole:
<fo:block text-align="start" text-indent="-1in"
text-align-last="end" last-line-end-indent="-1in"
start-indent="1in" end-indent="1in">
This is an example of left-aligned text with an outdented first line.
The last line of the text is aligned to the right, and outdented
by 1 inch from the right.
</fo:block>
The names of properties start-indent and end-indent follow the same logic as the values for text-indent: start-indent controls white space added at the beginning of every line, and end-indent adds a margin at the end of every line.
To complete this chapter, let's introduce attributes to position blocks vertically with respect to each other: space-before and space-after. Their names also derive from the writing-mode approach: ‘before’ means “before the first line”, and ‘after’ implies “after the last line”.
Spaces are more complicated than indents: they aren't specified as a single value, but rather as a vector of several components — minimum, optimum, and maximum value for the space. Components can be assigned separately: an attribute name will consist of a property name followed by a component name, separated by a dot. You can also assign all numeric components the same value by using the attribute name without a component qualifier; this is what you normally do in most cases.
An important property of spaces is that they aren't additive: if there are several space specifiers between two blocks (e.g. space-after on a preceding block and space-before on a following block), a single space value is chosen so as to satisfy all applicable constraints. Apparently, spaces merge and don't sum up. (The real rules for space resolution are more complicate; please refer to the XSL FO specs).
The fragment below illustrates the use of spaces:
<fo:flow flow-name="xsl-region-body" font="14pt Times">
<fo:block font-size="24pt"
text-align="center"
space-before="30pt"
space-before.conditionality="retain"❶
space-after="12pt">The Jabberwocky</fo:block>
<fo:block font-style="italic"
text-align="end"
space-before="12pt"
space-after="9pt">Lewis Carroll</fo:block>
<fo:block start-indent="1.5in" space-after="9pt">
<fo:block>’❷Twas brillig, and the slithy toves</fo:block>
<fo:block>Did gyre and gimble in the wabe:</fo:block>
<fo:block>All mimsy were the borogoves,</fo:block>
<fo:block>And the mome raths outgrabe.</fo:block>
</fo:block>
<fo:block start-indent="1.5in" space-after="9pt">
<fo:block>“❸Beware the Jabberwock, my son!</fo:block>
<fo:block>The jaws that bite, the claws that catch!</fo:block>
<fo:block>Beware the Jubjub bird, and shun</fo:block>
<fo:block>The frumious Bandersnatch!”❹</fo:block>
</fo:block>
</fo:flow>
| ❶ | By default, space-before at the top of the page and space-after at the bottom of the page are suppressed. To force them, specify .conditionality="retain". |
| ❷ | ’ is a UCS code for right single quote. IREn addresses all characters by their Unicode values. |
| ❸ ❹ | “ and ” are UCS codes for left and right double quotes. |
4.2. Borders, Padding, and Background
Blocks may have borders from either side. Sides can be addressed either in an absolute orientation scheme (left, right, top, and bottom), or in a writing-mode relative scheme (resp. start, end, before, and after).
Every border has the following properties, that may get the following values in XSL FO:
-
colorone of 16 predefined HTML system colors, or an RGB value; -
stylesolid,dashed,dotted,double,inset,outset,groove,ridge, ornone; -
widththin,medium,thick, or an explicit width specification.
You can specify each property for each border separately by writing several attributes of the form border-{side}-{property}:
<fo:block border-top-color="black"
border-top-style="solid"
border-top-width="thick"
text-align="center">
Thick black border at the top
</fo:block>
You can also specify properties for all the four sides as a whole, using a shorthand notation border-{property}:
<fo:block border-color="gray"
border-style="groove"
border-width="medium"
text-align="center">
Medium gray groove around the whole block
</fo:block>
You can also group properties that refer to one side into a single shorthand attribute border-{side}. However, only absolutely oriented side names (top, bottom, left, and right) are permitted in this position. An example:
<fo:block text-align="center"
border-top="dashed 1pt #C00000"❶
border-bottom="1pt dashed #C00000">
1pt dashed red border at the top and bottom
</fo:block>
| ❶ | Elements inside the attribute can be specified in any order, separated by spaces. |
Finally, a single border attribute can accumulate properties that are ascribed to all the four sides:
<fo:block border="thin silver ridge"
text-align="center">
Thin silver ridge around the whole block
</fo:block>
When printed, a block may be split by a page break or a column break. What happens to the borders adjacent to the breakline? For some block types, you may want to box every part of the original block separately, i.e. draw a border line where the break occurs; this is the default behaviour in XSL FO. For some other blocks, you may prefer to “keep the box open” suppressing borders at column/page breaks. This behavior is controlled by a special component of the border's width — border-{side}-width.conditionality:
<fo:block border="thin blue groove"
border-before-width.conditionality="discard"
border-after-width.conditionality="discard">
If this block happens to be split by a page break,
no line will be drawn on either side of the break.
</fo:block>
Only writing-mode oriented sides (before, after, start, and end) are permitted in the conditional border expressions.
Once you have set a border around an object, you normally want to specify a padding between the text and the border. This is done by padding-{side} attributes:
<fo:block border="thin solid navy"
text-align="center"
padding-before="18pt"
padding-bottom="18pt">
<fo:block border="thin solid maroon">
The outer block has a 18 pt padding from top and bottom
</fo:block>
</fo:block>
There also exists a shorthand padding attribute:
<fo:block border="thin solid navy"
text-align="center"
padding="2cm">
<fo:block border="thin solid maroon">
The outer block has a 2 cm padding from all sides
</fo:block>
</fo:block>
You can also specify several numbers as a value for padding attributes:
-
if there are two values, the top and bottom paddings are set to the first value and the right and left paddings are set to the second;
-
if there are three values, the top is set to the first value, the left and right are set to the second, and the bottom one is set to the third;
-
if there are four values, they apply to the top, right, bottom, and left, respectively.
Example:
<fo:block border="thin solid navy"
text-align="center"
padding="1cm 3cm">
<fo:block border="thin solid maroon">
The outer block has 1 cm padding from top and bottom,
and 3 cm padding from right and left.
</fo:block>
</fo:block>
Like borders, padding may be conditional at page breaks: specifying padding-{side}.conditionality="discard" suppresses padding before or after a page break. Like for borders, only writing-mode oriented sides (before, after, start, and end) are permitted in this position.
To complete the picture, let's learn how to set backgrounds for blocks.
Blocks may have different backgrounds — colored or even decorated with a graphic. To specify a color for the background, use background-color property:
<fo:block color="yellow"
background-color="red"
padding="12pt"
text-align="center">
Yellow on red
</fo:block>
To add a background image to the block, you should
-
specify image source —
background-image; -
specify image position —
background-position; -
specify whether the image should be repeated along any of the axes —
background-repeat.
The background-image attribute specifies an URI of the bitmap image file. IREn handles HTTP, FTP, and file system resource locators in URIs. An unqualified URI is treated as a path to a file in the local file system; if the path is relative, it is calculated from the location of the source XSL FO document (rather than from the current directory where IREn is run). Note also the url('…') function-like wrapper around the file name: this is required by the XSL 1.0 Recommendation. (IREn recognizes unwrapped URLs, too).
Note: Under Win32, absolute pathnames may contain a colon after the disk letter. These colons confuse Java URI resolver: the disk letter is treated as protocol name. Use an unabridged file URI:
file:/C:/IREn/myimage.jpg
Example:
<fo:block border="0.5pt solid silver"
background-image="url('spots.jpg')"
padding="18pt"
text-align="center">
The whole background tiled with colored spots
</fo:block>
By default, an image specified in background-image tiles the whole block. To insert only a single instance, disable tiling by setting background-repeat="no-repeat":
<fo:block border="0.5pt solid silver"
background-image="url('spots.jpg')"
background-repeat="no-repeat"
background-position-horizontal="center"
background-position-vertical="center"
padding="18pt"
text-align="center">
A single image placed 18pt to the right
and 6pt below the upper left corner.
</fo:block>
The position of the image within the block is controlled by two properties, background-position-horizontal and background-position-vertical. The background-position shorthand property from CSS2 can also be used:
<fo:block border="0.5pt solid silver"
background-image="url('spots.jpg')"
background-repeat="repeat-y"
background-position="left center"
background-color="silver"
padding="18pt"
text-align="center">
A stripe made of coloured spots along the left edge of the block;
the rest of the block has a silver background.
</fo:block>
XSL Recommendation defines no method to scale the background image. To do it, you have to recur to RenderX add-ons; see description of rx:background-content-width, rx:background-content-height, and rx:background-scaling extension properties in the documentation for IREn 4.9.