Abstract

This specification presents new features to fully support the media type embossed, i.e. to print braille on paper. The specification is derived from CSS2 [CSS2] and CSS3.

Status of This Document

This document is merely a public working draft of a potential specification. It has no official standing of any kind and does not represent the support or consensus of any standards organisation.

Braille CSS was invented by the creators of DAISY Pipeline 2 as a means of configuring the braille production scripts, and as an interface between software components.

Although the media types braille (intended for braille tactile feedback devices) and embossed (intended for paged braille printers) exist, there is no support in CSS2 [CSS2] and CSS3 for actually laying out content for braille devices or braille paper. Because of its very restricted grid layout and its bulkiness, braille has rather specific requirements, and the styling possibilities are limited. Therefore it was decided to make a custom CSS specification that would support all the features specific to braille.

Braille CSS has become a pick-and-mix of existing CSS2 and CSS3 features and new ones. While virtually all of the core concepts of CSS remain intact, a great deal of existing features were either not incorporated, or were incorporated in a slimmed-down form. One reason is that a lot of features simply don't make sense in the context of braille. Also, for the sake of simplicity, the authors didn't bother to include features that are not supported by implementations. Still it was chosen not to write the specification from scratch but to explicitely reference existing specifications whenever possible and to explain the differences.

While the main purpose of this specification is a practical one, namely to support the use and development of the DAISY Pipeline 2 braille production scripts, we hope to evolve towards full compatilbity with CSS in the long run. In order achieve this, braille CSS will have to define how implementations should cope with all possible CSS rules and properties, given the limited rendering possilities in the context of braille. But in addition, CSS would also have to be extended to support features specific to braille.

If you would like to give feedback or contribute to this specification, please file issues at this project's home on GitHub.

Table of Contents

1. Introduction

This section is non-normative.

Braille is a tactile writing system used by the blind and visually impaired. Each braille character is formed within a rectangular box with fixed dimensions known as a braille cell. A character is made up of up to six raised dots arranged in a 3 x 2 configuration, which yields sixty-four possible combinations. In eight-dot braille, a full braille cell consists of eight (4 x 2) dots and there are 256 combinations. Unicode has reserved the U+2800..U+28FF range for the Braille Patterns block.

The process of transforming text to braille is called braille transcription. The rules that define the braille transcription in a certain language form the braille code of that language. There are hundreds of braille codes in use all over the world. Each language can have several codes, and each code can have several variants.

Braille can be read on paper or on a refreshable braille display connected to a computer. Most braille printers (also called embossers) and braille displays have a fixed-pitch character grid or matrix layout. If m represents the maximal number of lines a page can contain and n is the maximal number of cells in a line, then a cell can only appear in one of m x n possible positions.

Because braille cells take up a lot of space compared to printed words, paper braille books are considerably bulkier than regular books. Usually braille books are divided into several volumes in order to make them more handleable and suitable for distribution.

1.1 Terminology

Agents supporting braille CSS can be subdivided into two categories:

2. How to read this Specification

This specification follows the CSS property definition conventions from [CSS2]. In addition to the property-specific values listed in their definitions, all properties defined in this specification also accept the inherit and initial keywords as their values. For readability they have not been repeated explicitly.

Value types, properties, functions and at-rules not defined in this specification are defined in CSS Level 2 Revision 1 [CSS2] or in other CSS modules. External definitions will always be explicitely referenced from this specification. This specification will further expand, restrict or override definitions. In that case the differences will be explained in informative notes.

The examples included in this specification serve as illustrations as well as tests for two implementations of braille CSS that are being developed within the DAISY Pipeline 2 project. Test results of the Liblouis based renderer are marked with an “L”, those of the Dotify based renderer are marked with a “D”.

Examples are set off from the normative test with a yellow box, like this:

This is an example.

Notes are set off from the normative test with a green box, like this:

Note

This is an informative note.

2.1 Conformance

As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.

The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL in this specification are to be interpreted as described in [RFC2119].

3. Syntax

[CSS3SYN] describes the basic structure and syntax of CSS stylesheets. The syntax also applies to braille CSS.

Implementations of braille CSS may support vendor-specific properties and values. To avoid clashes with future CSS features, the [CSS2] specification reserves a prefixed syntax for proprietary extensions. Other implementations that not recognize such vendor-prefixed properties should ignore them.

For all known implementations with proprietary extensions, include references to relevant documentation. For example, the Dotify based implementation may support -obfl- prefixed properties. See braille-css#36.

4. Values and Units

[CSS3VAL] describes the common values and units that CSS properties accept and the syntax used for describing them in CSS property definitions. Some but not all of them apply to braille CSS. The following types are redefined or newly defined:

<length>
Lenghts are always expressed in multiples of braille cells (cell width for horizontal measurement and cell height for vertical measurement). No unit identifier is required. Some properties allow negative length values.
<braille-character>
A braille character is defined as a single Unicode character in the range U+2800..U+28FF.
<braille-string>
A braille string is defined as a sequence of braille characters, enclosed with double or single quotes.
Note

<length> redefines <length> [CSS3VAL], <braille-character> and <braille-string> are new.

5. Selectors

See braille-css#25.

6. Cascading and Inheritance

See braille-css#26.

7. Style Attributes

Some document formats, such as HTML, have a style attribute to permit the author to directly apply style information to specific elements. The style attribute's syntax and interpretation in defined in [CSSSTYLEATTR]:

inline-stylesheet
  : S* declaration? [ ';' S* declaration? ]*
  ;

Interpreters may optionally support an extension of this syntax:

inline-stylesheet
  : declaration-list [ S+ inline-ruleset ]*
  ;

declaration-list
  : S* declaration? [ ';' S* declaration? ]*
  ;

inline-ruleset
  : '&'? S* [ [ '>' | '+' | '~' ]? S* selector ]+ S* '{' declaration-list '}' S*
  ;

This syntax is inspired by Sass [SASS]. The inline rulesets apply to elements relative to the element to which the style attribute belongs. A ‘&’ (ampersand) indicates the position of the base element within the combined selector expression. Without a ‘&’, a space between the base element and the relative selector is assumed. If a ‘&’ is present and is no space of other combinator separates it from the relative selector, it means the relative selector is effectively “chained” onto the base element as if it where a single sequence of simple selectors.

8. Media Types

Specifying media-dependent style sheets is done using media types [CSS2]. For braille CSS, only one media type is relevant: a braille renderer shall only take into account style sheet rules for media type embossed (or all).

Note

A braille translator may also look at other media types (notably print) in order to find hints for the translation. A typical use case is text-level styling in print such as boldfacing or italicizing which is conveyed in braille using braille indicators.

Add examples of other media types. See braille-css#27.

Allow media braille in addition to embossed in order to differentiate between properties that only make sense for braille on paper, and properties that make sense on refreshable braille displays too (examples would be white-space, hyphens, hyphen-character, text-transform, etc.). See braille-css#1.

9. Box Model

See braille-css#29.

The CSS Box model [CSS3BOX] describes how each element and each string of text is laid out by transforming the document tree into a tree of rectangular boxes, each consisting of a content area and optional surrounding padding, border and margin areas. Braille CSS has a slightly simplified model.

Each element in the document tree generates zero or more boxes. Some other boxes are not the direct result of an element, such as for instance line boxes, page boxes, and anonymous boxes. The parent box of another box is called the containing box or container. In general, generated boxes of an element act as containing boxes of descendant elements.

Elements that are broken across lines or pages result in box fragments. The generic term for containers like line and page boxes is fragmentainers. How content breaks across fragmentainers is described in the section Box Model for Breaking [CSS3BREAK].

The position and size of an element's box(es) are often calculated with respect to the edges of a certain rectangle, called the containing block. The containing block in which the root element lives is called the initial containing block which coincidences with the page area box. Note that the initial containing block depends on the context. Different pages have different initial containing blocks. For other elements, the containing block is formed by the content edge of the nearest block-level ancestor box.

Note

These simplified definitions are equivalent to the original definitions of containing block and initial containing block [CSS3BOX] [CSS3POS], considering that braille CSS does not support continuous media or anything other than static positioning.

There are page boxes, block-level boxes, line boxes and inline-level boxes. A block-level box is like a paragraph, a line box like a line of text, and inline-level boxes like words inside a line. Page boxes are described in the section Paged Media. Boxes are laid out according to the normal flow positioning scheme, which consists of block formatting of block-level boxes and inline formatting of inline-level boxes.

Note

As opposed to [CSS2] where boxes can be floated or positioned absolutely as well, braille CSS only supports the normal flow positioning scheme. Another difference is that normal flow in braille CSS doesn't include relative positioning.

9.1 Block-level Formatting

Elements with a value of block or list-item for the display property are called block-level elements. Block-level elements generate block-level boxes, which are boxes that participate in a block formatting context. In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. The vertical distance between two sibling boxes is determined by the margin properties. Vertical margins between adjacent block-level boxes collapse.

In general, each box's left and right outer edges touch the left and right edges of the containing block. The following constraint must hold:

margin-left + border-left-width + padding-left + width + padding-right + border-right-width + margin-right = width of containing block

In the equation above, border-left-width is equal to 1 if the value of border-left is not none, or 0 otherwise. Similarly, border-right-width is equal to 1 if the value of border-right is not none, or 0 otherwise.

However, if an element is positioned, the box's edges don't need to touch the edges of the containing block. In this case the equation becomes:

left offset + margin-left + border-left-width + padding-left + width + padding-right + border-right-width + margin-right + right offset = width of initial containing block

Here, left offset is equal to the value of left if it is not auto, or otherwise the distance from the left edge of the containing block to the left edge of the initial containing block. Likewise, right offset is equal to the value of right if it is not auto, or otherwise the distance from the right edge of the containing block to the right edge of the initial containing block.

If a box has only inline-level children, the height is the number of line boxes. An empty box has height ‘0’. If the box has block-level children, the height is the distance between the top border-edge of the topmost block-level child box that doesn't have margins collapsed through it and the bottom border-edge of the bottommost block-level child box that doesn't have margins collapsed through it. However, if the element has a nonzero top padding and/or top border, then the content starts at the top margin edge of the topmost child. Similarly, if the element has a nonzero bottom padding and/or bottom border, then the content ends at the bottom margin edge of the bottommost child.

Note

Block formatting in braille CSS is considerably simplified with respect to [CSS2] and [CSS3BOX]. Since there is no floating, no absolute positioning and no display: inline-block, each page has only a single block formatting context. Furthermore, the text orientation is always left-to-right and top-to-bottom (it is as if the direction and writing-mode properties would have their values set to ltr and horizontal-tb). Finally, because there can be no replaced elements and there are no width, height, min-width, min-height, max-width and max-height’ properties (it is as if their values would be set to auto, auto, 0, 0, none and none), calculating widths, heights and margins becomes rather trivial.

9.2 Inline-level Formatting

Elements with a value of inline for the display property are called inline-level elements. Inline-level elements generate inline-level boxes, which are boxes that participate in an inline-level formatting context. In an inline-level formatting context, boxes are laid out horizontally, one after the other, beginning at the top of a containing block. The rectangular area that contains the boxes that form a line is called a line box. Line boxes are created as needed to hold inline-level content. Line boxes are never empty and do never hold collapsible white space only.

The height of a line box is determined by the line-height property, which has an initial value of 1. The width of a line box is determined by the containing block. The left edge of a line box touches the left edge of its containing block and the right edge touches the right edge of its containing block.

When the total width of the inline-level boxes on a line is less than the width of the line box containing them, their horizontal distribution within the line box is determined by the text-align property. When an inline box exceeds the width of a line box, it is split into several boxes and these boxes are distributed across several line boxes.

Note

Inline formatting in braille CSS is simplified with respect to [CSS2] and [CSS3TEXT]. The height of a line box is always equal to 1, and there is no inline-level alignment.

9.3 Anonymous Boxes

Anonymous boxes are created when the box model requires a child box with a certain value for display, but the child actually has a different value.

The properties of anonymous boxes are inherited from the enclosing non-anonymous box. Non-inherited properties have their initial value.

9.4 Collapsing Margins

The adjoining margins of two or more boxes (which might or might not be siblings) may combine to form a single margin. Margins that combine this way are said to “collapse”. Margins are adjoining if there are no line boxes, padding or border areas to separate them. Adjoining vertical margins collapse, horizontal margins don't. A collapsed margin is considered adjoining to another margin if any of its component margins is adjoining to that margin (collapsing is “transitive”). When two or more margins collapse, the the width of the resulting margin is the maximum of the collapsing margins' widths.

Note

This simplified definition is equivalent to the original definition of collapsing margins [CSS2] [CSS3BOX], considering that in braille CSS each page has only a single block formatting context, that the height of block-level boxes are auto-computed, that boxes can have no negative top or bottom margins, that the margin properties do not apply on inline-level boxes and that there is no floating, no clearance, no overflow, no absolute positioning, no vertical boxes and no display: inline-block.

In the Liblouis implementation, paddings currently collapse. See pipeline-mod-braille#12. Also, the behavior of margins in liblouis at the top of pages is not according to CSS.

In the Dotify implementation, margins currently don't collapse. See obfl#27 and obfl#29.

9.5 The display property

Name: display
Value: block | inline | list-item | none
Initial: inline
Applies to: all elements and pseudo-elements
Inherited: no
Media: embossed
Computed value: the specified value

This property determines the type of box(es) that are generated for an element. The values are as follows:

inline
This value causes an element to generate an inline box.
block
This value causes an element to generate a block box.
list-item
This value causes an element to generate a principal block box and a marker box.
none
This value causes an element to generate no boxes (i.e., the element has no effect on layout). Descendant elements do not generate any boxes either; this behavior cannot be overridden by setting the display property on the descendants.

9.6 Box Offsets: the left and right properties

An element is said to be positioned if its left or right properties have a value other than auto.

Name: left, right
Value: <length> | auto
Initial: auto
Applies to: block | list-item
Inherited: no
Media: embossed
Computed value:

The left and right properties... Values have the following meanings:

auto
...
<length>
... specifies how far a box's left or right margin edge is offset to the edge of the page area
Note

Note that these properties have a different meaning than the left and right properties defined in [CSS2] and [CSS3POS].

9.7 Margins: the margin-top, margin-right, margin-bottom, margin-left, and margin properties

Name: margin-top, margin-right, margin-bottom, margin-left
Value: <length>
Initial: 0
Applies to: block | list-item | @page
Inherited: no
Media: embossed
Computed value: see text

For block and list-item elements, the margin properties set the thickness of the margin area. The value may be a negative length for margin-left and margin-right.

In a page context, margin-top and margin-bottom set the height of the top and bottom page-margin areas. The value must be a non-negative <length>.

Note

These properties have a number differences with the original margin properties defined in [CSS3BOX]:

  • Margins can only be expressed in terms of cells and lines. Other units or percentages are not allowed.
  • margin-top and margin-bottom may not be negative.
  • The properties don't apply on inline-level boxes.
<body>
  <p> ⠤⠤⠤ </p>
</body>
@page { size: 10 3; }

p {
  display: block;
  margin-left: 1; }
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="3" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠀⠤⠤⠤</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠀⠤⠤⠤⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

The value of margin-left may be negative:

@page { size: 10 3; }

body {
  display: block;
  margin-left: 3; }

p {
  display: block;
  margin-left: -1; }
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="3" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠀⠀⠤⠤⠤</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠀⠀⠤⠤⠤⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
Name: margin
Value: [ <length> | auto ]{1,4}
Initial: (see individual properties)
Applies to: block | list-item
Inherited: no
Media: embossed
Computed value: (see individual properties)

margin is a shorthand for the other four properties. If margin has four values, they set top, right, bottom and left in that order. If left is omitted, it is the same as right. If bottom is omitted, it is the same as top. If right is omitted it is the same as top.

@page { size: 10 3; }

p {
  display: block;
  margin: 1; }
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="3" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row/>
          <row>⠀⠤⠤⠤</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠤⠤⠤⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

9.8 Padding: the padding-top, padding-right, padding-bottom, padding-left, and padding properties

Name: padding-top, padding-right, padding-bottom, padding-left
Value: <length>
Initial: 0
Applies to: block | list-item
Inherited: no
Media: embossed
Computed value: the specified value

Padding properties set the thickness of the padding area. The value may not be negative.

Note

These properties have a number differences with the original padding properties defined in [CSS3BOX]:

  • Paddings can only be expressed in terms of cells and lines. Other units or percentages are not allowed.
  • The properties don't apply on inline-level boxes.
Name: padding
Value: <length>{1,4}
Initial: (see individual properties)
Applies to: block | list-item
Inherited: no
Media: embossed
Computed value: (see individual properties)

padding is a shorthand for the other four properties. If padding has four values, they set top, right, bottom and left in that order. If left is omitted, it is the same as right. If bottom is omitted, it is the same as top. If right is omitted it is the same as top.

9.9 Borders: the border-top, border-right, border-bottom, border-left, and border properties

Name: border-top, border-right, border-bottom, border-left
Value: <braille-character> | none
Initial: none
Applies to: block | list-item
Inherited: no
Media: embossed
Computed value: the specified value

These properties set the style of the top, right, bottom, and left border of a box. Values have the following meanings:

<braille-character>
A border is constructed by repeating the specified braille character along the side of the box. The border width is ‘1’.
none
No border is constructed (and the width is therefore ‘0’).
Name: border
Value: [ <braille-character> | none ]{1,4}
Initial: (see individual properties)
Applies to: block | list-item
Inherited: no
Media: embossed
Computed value: (see individual properties)

border is a shorthand for the other four. Its four values set the top, right, bottom and left border respectively. A missing left is the same as right, a missing bottom is the same as top, and a missing right is also the same as top.

<body>
  <h> ⠿⠿⠿ </h>
</body>
@page { size: 10 3; }

h {
  display: block;
  padding: 0 1;
  border:    ⠇; }
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="3" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠖⠒⠒⠒⠒⠒⠒⠒⠒⠲</row>
          <row>⠇⠀⠿⠿⠿⠀⠀⠀⠀⠸</row>
          <row>⠓⠒⠒⠒⠒⠒⠒⠒⠒⠚</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠖⠒⠒⠒⠒⠒⠒⠒⠒⠲ ⠇⠀⠿⠿⠿⠀⠀⠀⠀⠸ ⠓⠒⠒⠒⠒⠒⠒⠒⠒⠚

10. Text

User agents in the ‘braille renderer’ category require that the document text (as well as text in content properties) consists of only white space characters and Unicode braille. Braille translators don't have this restriction, they can transform text to braille when necessary. The transformation from text to braille can be controlled on element level with the text-transform property.

The specification doesn't impose a specific ordering between text transformation, white space processing and line breaking, as long as in the end the white space processing, line breaking and braille translation rules are satisfied, and all text can be rendered in braille cells.

10.1 Transforming Text: the text-transform property

When document text does not consist solely of Unicode braille and white space, the braille translator transforms it to braille somehow. How text is supposed to be transformed depends on the braille code but also on the context. The text-transform property can be used for providing the translator with all the necessary context information to do its job correctly.

Name: text-transform
Value: auto | <custom-ident> +
Initial: auto
Applies to: all elements and pseudo-elements and margin contexts, and @counter-style rules
Inherited: yes
Media: embossed
Computed value: Values are inherited in a special way (see below).

Because braille transcription is a complex process influenced by braille codes and other factors, the possible values for text-transform and their exact meanings are UA-dependent.

auto
Text is transformed to braille the “default” way.
none
Text must not be transformed. This implies that the text already consists of Unicode braille and white space only.
<custom-ident> +
A space separated list of arbitrary but distinct values not equal to auto or none. Values are assumed to be “applied” by the braille translator from left to right.

In order to get some indication of what kind of values could be supported and to create uniformity across braille codes, a grammar could be made with a list of possible values and approximate meanings.

Values are inherited in a cumulative way:

Note

There is a fundamental difference between this property and the original text-transform property as defined in [CSS3TEXT]. While the original property is about describing basic character transforms (e.g. case transforms) for styling purposes, the Braille CSS property is about influencing the braille transcription. It is obvious that a transformation to another writing system is much more complex than simple case transforms, and this explains why the Braille CSS property can have arbitrary values whereas the original property has well-defined values (except for the capitalize value which depends on how word boundaries are determined).

Note that for certain text-transform values such as e.g. uppercase one could consider the transformation to braille as a two-step process consisting of a text-to-text step and a text-to-braille step. However there is no reason to make that distinction explicit as it would only be limiting.

10.2 The white-space property

The source text of a document often contains formatting that is not relevant to the final rendering: for example, breaking the source into segments (lines) for ease of editing, or adding white space characters such as tabs and spaces to indent the source code. The interpretation of such formatting can be controlled with the white-space property. The property specifies whether and how white space is collapsed and whether lines may wrap at unforced soft wrap opportunities.

Name: white-space
Value: normal | pre-wrap | pre-line
Initial: normal
Applies to: all elements and pseudo-elements and margin contexts
Inherited: yes
Media: embossed
Computed value: the specified value

Values have the following meanings, which must be interpreted according to the white space processing and line breaking rules:

normal
Sequences of white space are collapsed into a single character, or in some cases, no character. Lines may wrap at allowed soft wrap opportunities.
pre-wrap
Like normal, this value allows soft wrapping, but sequences of white space are not collapsed. Segment breaks are preserved as forced line breaks.
pre-line
Like normal, this value collapses consecutive spaces and allows soft wrapping, but segment breaks are preserved as forced line breaks.

10.3 White Space Processing Rules

White space processing affects only the white space characters: spaces (U+0020 space), braille spaces (U+2800 braille pattern blank), tabs (U+0009 character tabulation), and segment breaks (U+000D carriage return, U+000A line feed and U+000D U+000A).

Within an inline formatting context, white space characters are processed as follows:

  1. Every braille space and every tab is converted to a normal space (U+0020 space).

  2. If white-space is normal or pre-line, all spaces and tabs immediately preceding or following a segment break are removed.

  3. Segment breaks are transformed for rendering according to the segment break transformation rules:

    • If white-space is pre-wrap or pre-line, segment breaks are transformed into a preserved line feed (U+000A line feed).

    • If white-space is normal, segment breaks are converted to a collapsible space (U+0020 space), unless the character immediately before or immediately after the segment break is the zero-width space character (U+200B zero width space (zwsp)), then the segment break is removed.

  4. If white-space is normal or pre-line, spaces are considered collapsible. Any space immediately following another collapsible space is collapsed to have zero advance width. It is invisible, but retains its soft wrap opportunity, if any. A translator may in some cases completely remove collapsible spaces.

    Note

    As an example of space that is dropped between words, in EBAE English braille, “to have” is translated to “⠖⠓”.

    If white-space is pre-wrap, any sequence of spaces is treated as a sequence of non-breaking spaces (U+00A0 no-break space (nbsp)). However, a soft wrap opportunity exists at the end of the sequence.

Note

Two characters in the same inline formatting context can follow each other regardless of whether they are within the boundaries of the same inline box.

Then, as inline boxes are laid out:

  1. Sequences of collapsible spaces at the beginning of line boxes are removed.

  2. Each non-collapsed space (U+0020 space) is rendered as a number of empty braille cells specified by the word-spacing property (by default 1). Non-breaking spaces (U+00A0 no-break space (nbsp)) are not considered word-separator characters and are treated as any other character. Zero-width space characters (U+200B zero width space (zwsp)) have a zero advance width.

  3. Sequences of collapsible spaces at the end of line boxes are removed. If spaces at the end of a line are non-collapsible but have white-space set to pre-wrap the UA may visually collapse their character advance widths.

White space that was not removed or collapsed during the white space processing steps is called preserved white space.

10.4 Line Breaking

When inline-level content is laid out into lines, it is broken across line boxes. Line breaking is based on [CSS3TEXT]:

10.5 Breaking within Words

Hyphenation allows the controlled splitting of words to improve the layout of paragraphs, typically splitting words at syllabic or morphemic boundaries and visually indicating the split. Especially for braille, where space is very limited, hyphenation can have a significant impact on the layout. Braille CSS does not define the rules for hyphenation, but provides ways to control whether hyphenation is allowed and how hyphenation opportunities are determined.

10.5.1 The hyphens property

Name: hyphens
Value: none | manual | auto
Initial: manual
Applies to: all elements and pseudo-elements
Inherited: yes
Media: embossed
Computed value: the specified value

Hyphenation is controlled with the hyphens property. Values have the following meanings:

none
Words are not hyphenated, even if characters inside the word explicitly define hyphenation opportunities.
manual
Words are only hyphenated where there are soft hyphens (U+00AD soft hyphen (shy)) inside the word. Soft hyphens are invisible format characters that explicitly suggest hyphenation opportunities, and that produce a hyphenation character only when a line is broken at that point. A translator may drop soft hyphens, e.g. when they appears inside a contraction.
Note

[UAX14] describes the role of soft hyphens in Unicode line breaking.

auto
Words may be broken at appropriate hyphenation points either as determined by soft hyphens inside the word or as determined automatically by the user agent (i.e. braille translator), based on document language and braille code. Hyphenation characters inside a word, if present, take priority over automatic hyphenation.

10.5.2 The hyphenate-character property

The hyphenate-character property specifies the character that is rendered at the end of the line before a hyphenation break.

Name: hyphenate-character
Value: auto | <braille-character>
Initial: auto
Applies to: all elements and pseudo-elements
Inherited: yes
Media: embossed
Computed value: the specified value

The auto value means that it is up to the user agent to find an appropriate value.

10.6 Line spacing: the line-height property

The height of a line box is determined by the line-height property of its block container. Values must be strictly positive <length>s. By default the line height is equal to the text height which is always 1. When line-height is set to a higher value, text inside the line box touches the top edge of the box, and space is added at the bottom. All line boxes in a block have the same height, including the last one. In other words, the content area of a block box changes proportionately with the value of line-height. Top and bottom padding and margins however are not affected by line-height.

Allow values between 1 and 2.

Name: line-height
Value: <length>
Initial: 1
Applies to: block | list-item
Inherited: yes
Media: embossed
Computed value: the specified value
Note

[CSS3LINE] describes how the vertical positioning of text inside a line box is affected by the vertical-align property. There is no such property in braille CSS. Text is always aligned vertically as if vertical-align were top.

<body>
  <p> ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ </p>
</body>
@page { size: 10 6; }

body {
  display: block;
  line-height: 2; }
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="6" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row rowgap="4">⠤⠤⠤⠀⠤⠤⠤</row>
          <row rowgap="4">⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

Margins are not affected by line-height:

<body>
  <p> ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ </p>
</body>
@page { size: 10 6; }

body {
  display: block;
  line-height: 2; }

p {
  display: block;
  margin-top: 3; }
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="6" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row/>
          <row/>
          <row/>
          <row rowgap="4">⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀

Alternating lines on facing pages can be accomplished with a combination of line-height, @page:right, @page:left and margin-top:

<body>
  <p> ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ </p>
  <p> ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ </p>
  <p> ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ </p>
</body>
@page { size: 10 6; }

@page:left { margin-top: 1; }

body {
  display: block;
  line-height: 2; }

p {
  display: block; }
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="6" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row rowgap="4">⠤⠤⠤⠀⠤⠤⠤</row>
          <row rowgap="4">⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤</row>
        </page>
        <page>
          <row/>
          <row rowgap="4">⠤⠤⠤⠀⠤⠤⠤</row>
          <row rowgap="4">⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤</row>
        </page>
        <page>
          <row rowgap="4">⠤⠤⠤⠀⠤⠤⠤</row>
          <row rowgap="4">⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠀⠀⠀⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

10.7 Text Alignment: the text-align property

Name: text-align
Value: left | center | right
Initial: left
Applies to: block | list-item
Inherited: yes
Media: embossed
Computed value: the specified value

10.8 First Line Indentation: the text-indent property

Name: text-indent
Value: <length>
Initial: 0
Applies to: block | list-item
Inherited: yes
Media: embossed
Computed value: the specified value
<body>
  <p> ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ </p>
</body>
@page { size: 10 3; }

p {
  display: block;
  text-indent: 1; }
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="3" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠀⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠀⠤⠤⠤⠀⠤⠤⠤⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠀⠀⠀⠀⠀⠀

The value of text-indent may be negative:

@page { size: 10 3; }

body {
  display: block;
  margin-left: 3; }

p {
  display: block;
  text-indent: -1; }
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="3" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠀⠀⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠀⠀⠀⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠀⠀⠀⠤⠤⠤</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠀⠀⠤⠤⠤⠀⠤⠤⠤⠀ ⠀⠀⠀⠤⠤⠤⠀⠤⠤⠤ ⠀⠀⠀⠤⠤⠤⠀⠀⠀⠀

10.9 Word Spacing: the word-spacing property

The word-spacing property specifies spacing between “words”, expressed in multiples of an empty cell. Values must be non-negative lengths. Word boundaries are determined and word spacing applied as part of the white space processing. By default word-spacing is 1. A zero value results in all inter-word spacing being eliminated.

Name: word-spacing
Value: <length>
Initial: 1
Applies to: all elements and pseudo-elements and margin contexts
Inherited: yes
Media: embossed
Computed value: the specified value
Note

This property differs from the original word-spacing property [CSS3TEXT] in that it specifies the absolute inter-word spacing and not the (absolute or relative) additional inter-word spacing. Also, in braille CSS non-breaking spaces are not considered word-separator characters.

10.10 Letter Spacing: the letter-spacing property

The letter-spacing property specifies the spacing, expressed in multiples of an empty cell, between adjacent “base units” of the language, script or text. What these base units are is determined by the braille code. The exact result of applying letter-spacing is therefore UA-dependent.

Note

The base unit could for example be defined as the smallest unit of the script (called a grapheme) which in the case of braille is any (non-blank) braille character (Unicode character in the range U+2801..U+28FF).

Another definition of the base unit could be any group of braille characters that corresponds with a single grapheme when written in a certain other writing system (such as Latin). In the case of contracted braille, this definition could be extended to any group of braille characters that corresponds with a group of graphemes in the other writing system and can not be further divided in smaller such groups.

A last example of a definition is any group of braille characters that corresponds with a single letter in another writing system. This would mean among other things that capital and number signs are attached to the next character, and that punctuation marks are attached to the previous character.

Name: letter-spacing
Value: <length>
Initial: 0
Applies to: all elements and pseudo-elements and margin contexts
Inherited: yes
Media: embossed
Computed value: the specified value

The values of letter-spacing must be non-negative <length>s. The default is 0. Letter spacing is not applied at the beginning or at the end of a line. Letter spacing between two characters effectively “belongs” to the innermost element that contains the two characters: the total letter spacing between two adjacent characters is specified by and rendered within the innermost element that contains the boundary between the two characters. Letter spacing ignores zero-width spaces (U+200B zero width space (zwsp)). Non-breaking spaces (U+00A0 no-break space (nbsp)) are treated like any other character.

11. Generated Content, Automatic Numbering, and Lists

11.1 Pseudo-elements

Pseudo-elements provide a way to insert and style content that does not exist in the source document. Pseudo-elements generate boxes just like normal elements do. For pseudo-elements to be generated, they must not have their content property set to none. In the general case, pseudo-elements inherit any inheritable properties from the element in the document tree to which they are associated (their superior parent), and their boxes are positioned with respect to the superior parent's box. The syntax for selecting pseudo-elements is defined in [CSS3GENCON].

11.1.1 The ::before and ::after pseudo-elements

The ::before and ::after pseudo-elements are used to insert content immediately before and immediately after the content of an element (or other pseudo-element). The generated boxes are contained within the superior parent's box. The content property is used to specify the content to insert.

11.1.2 Markers: the ::marker pseudo-element

The ::marker pseudo-element is used to represent a list item's marker (the bullet or number identifying the item). For a ::marker pseudo-element to be generated, its superior parent must have a computed display value of list-item. The default value of the pseudo-element's content property is determined by the list-style-type property of its superior parent.

11.2 Automatic Numbering with Counters

A counter is a special concept used to automatically number list items, pages, etc. [CSS3LIST] describes how counters are created and manipulated with the counter-increment, counter-set and counter-reset properties, and used with the counter() function.

11.2.1 Manipulating Counters: the counter-increment, counter-set and counter-reset properties

Name: counter-reset
Value: [ <custom-ident> <integer>? ]+ | none
Initial: none
Applies to: all elements and pseudo-elements
Inherited: no
Media: embossed
Computed value: the specified value

The counter-reset property creates new counters on an element. Its values are defined as follows:

none
The element does not create any new counters.
[ <custom-ident> <integer>? ]+
The element creates one or more new counters. If an <integer> is provided after a <custom-ident>, it is the starting value of the counter. Otherwise, the starting value of the new counter is 0.
Name: counter-set
Value: [ <custom-ident> <integer>? ]+ | none
Initial: none
Applies to: all elements and pseudo-elements
Inherited: no
Media: embossed
Computed value: the specified value
Name: counter-increment
Value: [ <custom-ident> <integer>? ]+ | none
Initial: none
Applies to: all elements and pseudo-elements
Inherited: no
Media: embossed
Computed value: the specified value

The counter-set and counter-increment properties manipulate the value of existing counters. They only create new counters if there is no counter of the given name on the element yet. Their values are defined as follows:

none
The element does not alter the value of any counters.
[ <custom-ident> <integer>? ]+
The element alters the value of one or more counters on it. If there is not currently a counter of the given name on the element, the element creates a new counter of the given name. If an <integer> is provided after a <custom-ident>, the value of the innermost counter of the given name is set to that integer (for counter-set) or incremented by that integer (for counter-increment). Otherwise, the value of the innermost counter of the given name is set to 0 (for counter-set) or incremented by 1 (for counter-increment).

Inheriting counters must be done before resetting counters, which must be done before setting counters, which must be done before incrementing counters, which must be done before using counters.

A counter in an element that does not generate a box cannot be set, reset, or incremented.

11.2.2 Creating and Inheriting Counters

Every element has a collection of zero or more counters, which are inherited through the document tree in a special way. A counter and its value are inherited separately, possibly from different elements.

If an element has preceding siblings, it inherits all of the immediately preceding sibling's counters. Otherwise, if the element has a parent, it inherits all of the parent's counters.

The element then inherits counter values from the immediately preceding element in document order. This is done by examining the set of counters that the immediately preceding element has, and, for every counter that exists in both the element's set and the preceding element's set, giving the element's counter the same value.

Additional counters can be created on elements with the counter-reset property. The effect depends on what other counters of that name exist on the element:

  • If no counters of that name exist on the element, create a new counter with that name.
  • Otherwise, if a counter of that name exists on the element, and it was created by a preceding sibling, replace the innermost counter of that name on the element with a newly-created counter with that name.
  • Otherwise, create a new counter with that name and nest it inside of the innermost counter with that name.

The value of the new counter is set to the provided starting value.

A page counter is created automatically on the root element. Its purpose is for numbering braille pages. The counter is implicitely incremented on each page. Depending on the implementation, explicitely setting or incrementing this counter may or may not have an effect. No new counters can be created with the name page.

Implementations may define additional automatic counters.

11.2.3 Printing Counters: the counter() function

Counters can be used with the counter() function. This happens automatically in the default contents of ::marker pseudo-elements, but the function can be used anywhere a string value is allowed. The function takes the name of a counter and an optional <counter-style> name (which defaults to decimal) and returns a <string> value:

counter() = counter( <custom-ident> [, [ <counter-style> | none ] ]? )

The <string> value returned by the function is obtained as follows:

  • If the second argument to the function is none, the function returns the empty string.
  • Otherwise, the function generates a counter representation for the value of the innermost counter of that name on the element (or 0 if the element has no counter of that name), using the <counter-style> specified by the second argument.
Braille pages can be numbered by printing the page counter in the page margin. (See also the section Page-Margin Boxes below.)
<body>
  ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿
  ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿
  ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿
</body>
@page {
  size: 10 5;
  margin-top: 1;
  @top-right {
    content: counter(page);
  }
}
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="5" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠀⠀⠀⠀⠀⠀⠀⠀⠼⠁</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
        </page>
        <page>
          <row>⠀⠀⠀⠀⠀⠀⠀⠀⠼⠃</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠀⠀⠀⠀⠀⠀⠀⠀⠼⠁ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠼⠃ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠀⠀⠀⠀⠀⠀

11.2.4 Defining Counter Styles: the @counter-style rule

The @counter-style rule allows the definition of custom counter styles. A @counter-style rule consists of the keyword @counter-style, a name, and a block of declaractions (called desciptors) which define how a counter value is converted into a string. A counter styles's name must be a <custom-ident> not equal to none or decimal. The various descriptors that make up a counter style are described in [CSS3COUNTERSTYLES]. In addition, a counter style in Braille CSS can also have a text-transform descriptor.

User agents must define the decimal counter style as an ultimate fallback style. Agents may include additional predefined styles in their UA stylesheet. All counter styles, predefined or not, except for decimal, can be overridden.

Note

The decimal counter style may be defined as follows:

@counter-style decimal {
  system: numeric;
  symbols: '' '' '' '' '' '' '' '' '' ''
}

In addition to the steps listed in [CSS3COUNTERSTYLES] for generating a counter representation, user agents in the ‘translator’ category must perform the necessary steps to ensure that the resulting representation is a braille string. The transformation to braille is influenced by the text-transform descriptor.

11.2.5 Default Marker Contents: the list-style-type property

Name: list-style-type
Value: <braille-string> | <counter-style> | none
Initial: none
Applies to: list-item
Inherited: yes
Media: embossed
Computed value: specified value

The list-style-type property is used to construct the default contents of a list item's marker; otherwise, list-style-type is ignored. The values are defined as follows:

none
The marker's default contents are none.
<braille-string>
The <braille-string> is used as the marker's default contents.
<counter-style>
The marker's default content are <counter-prefix> counter( list-item, <counter-style> ) <counter-suffix> where <counter-prefix> and <counter-suffix> are the values of the prefix and suffix descriptors for the specified counter style.

11.3 Named Strings

The string-set property sets the value of a named string, which functions as a variable. The value can be retrieved using the string() function. Since these variables may change on a given page, an optional second value for the string() function allows authors to choose which value on a page is used.

11.3.1 The string-set property

Name: string-set
Value: [ <custom-ident> <content-list> ] [, <custom-ident> <content-list> ]* | none
Initial: none
Applies to: all elements
Inherited: no
Media: embossed
Computed value: specified value

The string-set property contains one or more pairs, each consisting of a custom identifier followed by a content-list describing how to construct the value of the named string.

<content-list> expands to one or more of the following values, in any order. The generated content is the concatenation of all values in the list.

content-list = [ <string> | <attr(<identifier>)> | <content()> ]+

<string>
A string.
<attr(<identifier>)>
An attr() function, as defined in [CSS3VAL].
<content()>
A content() function, which returns the string value of the element. Any text that is generated inside ::before or ::after pseudo-elements are not part of this. Elements that do not generate boxes can also have a non-empty string value.

Named strings contain unformatted text. XML structure and CSS styling are not preserved. Text transformation and white space processing of strings happens after evaluation of the variable (with the string() function) and not before assignment (with the string-set property). This means that text-transform and white-space properties can have an effect at the place of insertion, but not at the original position in the DOM.

The content values of named strings are assigned at the point when the content box (or first content box fragment) of the element is created, or if the element does not generate any boxes, would have been created if it was a non-empty inline element.

11.3.2 The string() function

The string() function is used to insert the value of a named string into the document via the content property. This function requires one argument, the name of the named string. Since the value of a named string may change several times on a page an optional second argument indicates which value of the named string should be used.

string() = string( <custom-ident> [ , [ first | start | last | start-except-last | last-except-start | page-first | page-start | page-last | page-start-except-last | page-last-except-start | spread-first | spread-start | spread-last | spread-start-except-last | spread-last-except-start | ] ]? )

The second argument of the string() function is one of the following keywords:

first
page-first
The value of the first assignment on the page is used. If there is no assignment on the page, the assignment in effect at the end of the previous page (entry value) is used. first is the default value.
start
page-start
The value of the first assignment on the page is used if the content box (fragment) of that element does not follow any other content boxes on the page. Otherwise the assignment in effect at the end of the previous page (entry value) is used.
last
page-last
The assignment in effect at the end of the current page (exit value) is used.
start-except-last
page-start-except-last
The assignment that would be used by start is used if it precedes another assignment on the current page. Otherwise the empty string is used.
last-except-start
page-last-except-start
The last assignment following a content box on the current page is used, or the empty string if there is no such assignment. Effectively this is the same as last but excluding the assignment that would be used by start (and all assignments that precede it).
spread-first
Analogous to first with ‘page’ replaced by ‘page spread’.
spread-start
Analogous to start with ‘page’ replaced by ‘page spread’.
spread-last
Analogous to last with ‘page’ replaced by ‘page spread’.
spread-start-except-last
Analogous to start-except-last with ‘page’ replaced by ‘page spread’.
spread-last-except-start
Analogous to last-except-start with ‘page’ replaced by ‘page spread’.
Braille pages can be numbered by printing the page counter in the page margin. (See also the section Page-Margin Boxes below.)
<body>
  <p foo="⠁">
    ⠁⠁⠁ ⠁⠁⠁ ⠁⠁⠁ ⠁⠁⠁ ⠁⠁⠁
  </p>
  <p foo="⠿">
    ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿
  </p>
  <p foo="⠤">
    ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤
  </p>
  <p foo="⠸">
    ⠸⠸⠸ ⠸⠸⠸ ⠸⠸⠸ ⠸⠸⠸ ⠸⠸⠸
  </p>
  <p foo="⠛">
    ⠛⠛⠛ ⠛⠛⠛ ⠛⠛⠛ ⠛⠛⠛ ⠛⠛⠛ ⠛⠛⠛ ⠛⠛⠛
  </p>
  <p foo="⠌">
    ⠌⠌⠌ ⠌⠌⠌ ⠌⠌⠌ ⠌⠌⠌ ⠌⠌⠌
  </p>
</body>
@page {
  size: 10 6;
  @top-left {
    content: string(foo, first); }
  @top-right {
    content: string(foo, start); }
  @bottom-left {
    content: string(foo, last); }
  @bottom-right {
    content: string(foo, last-except-start); }
}
p {
  display: block;
  string-set: foo attr(foo);
}
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="6" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠁⠀⠀⠀⠀⠀⠀⠀⠀⠁</row>
          <row>⠁⠁⠁⠀⠁⠁⠁</row>
          <row>⠁⠁⠁⠀⠁⠁⠁</row>
          <row>⠁⠁⠁</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠀⠀⠀⠀⠀⠀⠀⠀⠿</row>
        </page>
        <page>
          <row>⠤⠀⠀⠀⠀⠀⠀⠀⠀⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠀⠀⠀⠀⠀⠀⠀⠀⠤</row>
        </page>
        <page>
          <row>⠸⠀⠀⠀⠀⠀⠀⠀⠀⠤</row>
          <row>⠤⠤⠤</row>
          <row>⠸⠸⠸⠀⠸⠸⠸</row>
          <row>⠸⠸⠸⠀⠸⠸⠸</row>
          <row>⠸⠸⠸</row>
          <row>⠸⠀⠀⠀⠀⠀⠀⠀⠀⠸</row>
        </page>
        <page>
          <row>⠛⠀⠀⠀⠀⠀⠀⠀⠀⠛</row>
          <row>⠛⠛⠛⠀⠛⠛⠛</row>
          <row>⠛⠛⠛⠀⠛⠛⠛</row>
          <row>⠛⠛⠛⠀⠛⠛⠛</row>
          <row>⠛⠛⠛</row>
          <row>⠛⠀⠀⠀⠀⠀⠀⠀⠀⠀</row>
        </page>
        <page>
          <row>⠌⠀⠀⠀⠀⠀⠀⠀⠀⠌</row>
          <row>⠌⠌⠌⠀⠌⠌⠌</row>
          <row>⠌⠌⠌⠀⠌⠌⠌</row>
          <row>⠌⠌⠌</row>
          <row/>
          <row>⠌⠀⠀⠀⠀⠀⠀⠀⠀⠀</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠁⠀⠀⠀⠀⠀⠀⠀⠀⠁ ⠁⠁⠁⠀⠁⠁⠁⠀⠀⠀ ⠁⠁⠁⠀⠁⠁⠁⠀⠀⠀ ⠁⠁⠁⠀⠀⠀⠀⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠀⠀⠀⠀⠀⠀⠀⠀⠿ ⠤⠀⠀⠀⠀⠀⠀⠀⠀⠿ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠀⠀⠀⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠀⠀⠀⠀⠀⠀⠀⠀⠤ ⠸⠀⠀⠀⠀⠀⠀⠀⠀⠤ ⠤⠤⠤⠀⠀⠀⠀⠀⠀⠀ ⠸⠸⠸⠀⠸⠸⠸⠀⠀⠀ ⠸⠸⠸⠀⠸⠸⠸⠀⠀⠀ ⠸⠸⠸⠀⠀⠀⠀⠀⠀⠀ ⠸⠀⠀⠀⠀⠀⠀⠀⠀⠸ ⠛⠀⠀⠀⠀⠀⠀⠀⠀⠛ ⠛⠛⠛⠀⠛⠛⠛⠀⠀⠀ ⠛⠛⠛⠀⠛⠛⠛⠀⠀⠀ ⠛⠛⠛⠀⠛⠛⠛⠀⠀⠀ ⠛⠛⠛⠀⠀⠀⠀⠀⠀⠀ ⠛⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠌⠀⠀⠀⠀⠀⠀⠀⠀⠌ ⠌⠌⠌⠀⠌⠌⠌⠀⠀⠀ ⠌⠌⠌⠀⠌⠌⠌⠀⠀⠀ ⠌⠌⠌⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠌⠀⠀⠀⠀⠀⠀⠀⠀⠀

11.4 Leaders: the leader() function

A leader is a repeating pattern used to visually connect content across horizontal spaces. They are most commonly used in tables of contents, between titles and page numbers. The leader() function, as a value for the content property, is used to create leaders. A <braille-string> describes the repeating pattern for the leader.

leader() = leader( <braille-string> )

Note

This function differs from the original leader() function [CSS3GCPM] in that it only takes a <braille-string> as an argument. dotted, solid, space or <string> are not allowed.

11.5 Cross-references

11.5.1 The target-counter() function

The target-counter() function retrieves the value of the named counter at the element referred to by the <url>. The second argument is the name of the counter.

target-counter() = target-counter( <url>, <custom-ident> )

Note

This function differs from the original target-counter() function [CSS3GCPM] in that it doesn't take an optional <counter-style> argument.

Note

The target-counter(), target-string() and target-text() functions only take a fragment URL which points to a location in the current document. The URL may also be provided indirectly using the attr() function [CSS3VAL], in which case ‘url’ will be implied as the type argument if omitted.

Add a target-content() function. See braille-css#6.

11.5.2 The target-string() function

The target-string() function retrieves the value of the named string at the element referred to by the <url>. The second argument is the name of the counter.

target-string() = target-string( <url>, <custom-ident> )

11.5.3 The target-text() function

The target-text() function retrieves the text value of the element referred to by the <url>.

target-text() = target-text( <url> )

Note

This function differs from the original target-text() function [CSS3GCPM] in that it doesn't take an optional second argument.

11.6 Inserting Content: the content property

Name: content
Value: none | <content-list>
Initial: none
Applies to: ::before, ::after, ::marker and ::alternate pseudo-elements, margin contexts and @begin and @end rules.
Inherited: no
Media: embossed
Computed value: the specified value

The content property dictates what is rendered inside the pseudo-element or margin area.

none
Causes the pseudo-element or margin area to have no content.
<content-list>
<content-list> expands to one or more of the following values, in any order. The generated content is the concatenation of all values in the list.

<content-list> = [ <string> | <attr()> | <string()> | <counter()> | <target-text()> | <target-string()> | <target-counter()> | <leader()> | <flow()> ]+

<string>
A string.
<attr()>
An attr() function, as defined in [CSS3VAL].
<string()>
A string() function.
<counter()>
A counter() function.
<target-text()>
A target-text() function.
<target-string()>
A target-string() function.
<target-counter()>
A target-counter() function.
<leader()>
A leader() function.
<flow()>
A flow() function. See the chapter about Named Flows.

12. Paged Media

See braille-css#28.

For producing braille on paper, the content of the document must be split into discrete pages. This process is called pagination. This specification defines properties for controlling the page dimensions, where pages may or must be broken, and for inserting content in page headers and footers.

12.1 Page Boxes

The page model [CSS3PAGE] specifies how a document is formatted within rectangular areas with a finite width and height, called page boxes, each consisting of a page area and up to 16 page-margin boxes. Braille CSS has a slightly simplified model.

In braille CSS, page boxes consist only of content and margin areas, no borders or padding. Moreover, the top and bottom page margins can only contain up to three page-margin boxes each.

CSS distinguishes between left pages and right pages on all documents, regardless of whether or not they are printed duplex or not. Each left page is followed by a right page and vice versa. Left and right pages can be styled differently with the :left and :right pseudo-classes.

12.1.1 The @page rule

The properties of a page box, such as its dimensions, are determined by properties declared within the page context, using @page rules.

A @page rule consists of the keyword @page, an optional page type selector, an optional page pseudo-class, and a block of declarations and margin at-rules (said to be in the page context). The page type selector matches pages of the named page type generated by the page property. Valid page pseudo-classes are :left, :right, :first and :blank. The :left and :right classes only match left or right pages, respectively. :first matches the first printed page of a volume. :blank matches content-empty pages that appear as the result of forced page breaks.

Declarations in page and margin contexts cascade as explained in the section Cascading in the page context [CSS3PAGE].

Note

This rule differs from the original @page rule [CSS3PAGE] in that only the size property is allowed in declarations.

12.1.2 Page Size: the size property

Name: size
Value: <length>{2} | auto
Initial: auto
Applies to: page context
Inherited: N/A
Media: embossed
Computed value: the specified value

The size property specifies the size of the page box's containing block. Values have the following meanings:

auto
The page box will be set to a size by the user agent. In the usual case, the size is chosen to match the printable area of the target page sheet.
<length>{2}
The page box will be set to the given dimensions. The first value establishes the page box width, and the second the page box height. Negative lengths are illegal.

The size property is not allowed within @page rules with a :left or :right pseudo-class.

Note

This property differs from the original size property [CSS3PAGE] in that it doesn't specify the orientation of the page box, and that no other values than auto and lengths are allowed.

Note

Note that while in the original specification the size property is meant to match the size of the page sheet, in braille CSS it is meant to match the printable area.

12.1.3 Page-Margin Boxes

Page-margin boxes are boxes within the page margin that can contain generated content. Page margins can be used to create page headers and footers, which are portions of the page set aside for supplementary information such as the page number or document title. The 16 page-margin boxes are defined and illustrated in [CSS3PAGE].

Only 6 of the 16 page-margin boxes are relevant in braille CSS, namely top-left, top-center, top-right, bottom-left, bottom-center and bottom-right.

Page-margin boxes are created by margin at-rules inside the page context. A margin at-rule consists of an ATKEYWORD that identifies the page-margin box (e.g. @top-left) and a block of declaractions (said to be in the margin context).

Note

This rules differs from the original margin at-rule [CSS3PAGE] in that only the content and white-space properties are allowed in declarations.

A page-margin box is generated if and only if the computed value of its content property is not none and does not consist of collapsible white space only. The height of a page-margin box is determined by the number of line boxes it contains. Soft wrapping is not allowed in page-margin boxes, but forced line breaks are. This means that if white-space is normal, the height is 1, and if white-space is pre-wrap or pre-line, the height is equal to the number of segment breaks plus 1. Text that falls outside of the page-margin box edges (horizontally) is clipped.

The top-left, top-center and top-right boxes, if they are generated, touch the page box's top edge. The offset between the page box's top edge and the page area is determined by the margin-top property, which defaults to 0. Page-margin boxes with a height less than this offset have empty space between them and the page area. Page-margin boxes with a height greater than margin-top extend into the page area, with the text in the page area wrapping around the page-margin boxes.

Analogous rules govern the properties of the bottom page-margin area (with ‘top’ replaced by ‘bottom’ everywhere).

Need to define how text in the page area should wrap around page-margin boxes.

Text in top-left and bottom-left boxes is left-aligned (as if text-align was set to left), text in top-center and bottom-center boxes is centered (as if text-align was set to center) and text in top-right and bottom-right boxes is right-aligned (as if text-align was set to right). Further alignment can be achieved by padding text with preserved spaces.

12.1.4 Using Named Pages: the page property

Name: page
Value: auto | <custom-ident>
Initial: auto
Applies to: block | list-item
Inherited: no (see text)
Media: embossed
Computed value: the specified value

The page property is used to specify a particular type of page (called a named page) on which an element must be displayed. If necessary, a forced page break is introduced and a new page generated of the specified type. The page can be styled by using the same type name in a page selector.

The page property does not inherit. However, if the page value on an element is auto, then its used value is the value specified on its nearest ancestor with a non-auto value. When specified on the root element, the used value for auto is the empty string.

<body>
  <div id="a">
    <p>
      ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤
      ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤
    </p>
  </div>
  <div id="b">
    <p>
      ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿
      ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿
    </p>
  </div>
</body>

Setting the size of the page and page margins:

@page {
  size: 10 7;
  margin-top: 1;
  margin-bottom: 2;
}
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="7" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row/>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
        </page>
        <page>
          <row/>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
        </page>
        <page>
          <row/>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

Setting different page sizes for different sections:

@page a { size: 8 4; }
@page b { size: 4 8; }
#a { page: a; }
#b { page: b; }
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="4" cols="8" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
        </page>
        <page>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
        </page>
      </section>
      <section rows="8" cols="4">
        <page>
          <row>⠿⠿⠿</row>
          <row>⠿⠿⠿</row>
          <row>⠿⠿⠿</row>
          <row>⠿⠿⠿</row>
          <row>⠿⠿⠿</row>
          <row>⠿⠿⠿</row>
          <row>⠿⠿⠿</row>
          <row>⠿⠿⠿</row>
        </page>
        <page>
          <row>⠿⠿⠿</row>
          <row>⠿⠿⠿</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠤⠤⠤⠀⠤⠤⠤⠀ ⠤⠤⠤⠀⠤⠤⠤⠀ ⠤⠤⠤⠀⠤⠤⠤⠀ ⠤⠤⠤⠀⠤⠤⠤⠀ ⠤⠤⠤⠀⠤⠤⠤⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠿⠿⠿⠀ ⠿⠿⠿⠀ ⠿⠿⠿⠀ ⠿⠿⠿⠀ ⠿⠿⠿⠀ ⠿⠿⠿⠀ ⠿⠿⠿⠀ ⠿⠿⠿⠀ ⠿⠿⠿⠀ ⠿⠿⠿⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

Generating content in the page margin:

@page {
  size: 10 6;
  margin-top: 1;
  @top-right {
    content: '⠒⠒⠒⠒';
  }
}
@page b { margin-top: 2; }
#b { page: b; }
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="6" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠀⠀⠀⠀⠀⠀⠒⠒⠒⠒</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
        </page>
      </section>
      <section>
        <page>
          <row>⠀⠀⠀⠀⠀⠀⠒⠒⠒⠒</row>
          <row/>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
        </page>
        <page>
          <row>⠀⠀⠀⠀⠀⠀⠒⠒⠒⠒</row>
          <row/>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠀⠀⠀⠀⠀⠀⠒⠒⠒⠒ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠒⠒⠒⠒ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠒⠒⠒⠒ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

Multiline content in the page margin:

@page {
  size: 10 6;
  margin-top: 2;
  @top-right {
    content: '⠒⠒⠒\A⠸⠸';
    white-space: pre-line;
  }
}
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="6" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠀⠀⠀⠀⠀⠀⠀⠒⠒⠒</row>
          <row>⠀⠀⠀⠀⠀⠀⠀⠀⠸⠸</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
        </page>
        <page>
          <row>⠀⠀⠀⠀⠀⠀⠀⠒⠒⠒</row>
          <row>⠀⠀⠀⠀⠀⠀⠀⠀⠸⠸</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
        </page>
        <page>
          <row>⠀⠀⠀⠀⠀⠀⠀⠒⠒⠒</row>
          <row>⠀⠀⠀⠀⠀⠀⠀⠀⠸⠸</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠀⠀⠀⠀⠀⠀⠀⠒⠒⠒ ⠀⠀⠀⠀⠀⠀⠀⠀⠸⠸ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠒⠒⠒ ⠀⠀⠀⠀⠀⠀⠀⠀⠸⠸ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠒⠒⠒ ⠀⠀⠀⠀⠀⠀⠀⠀⠸⠸ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

Making text in the page area wrap around page margin boxes:

@page {
  size: 10 6;
  @top-right {
    content: '⠒⠒⠒⠒';
  }
}
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="6" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠤⠤⠤⠀⠀⠀⠒⠒⠒⠒</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠿⠿⠿</row>
        </page>
        <page>
          <row>⠿⠿⠿⠀⠀⠀⠒⠒⠒⠒</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠤⠤⠤⠀⠀⠀⠒⠒⠒⠒ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠀⠀⠒⠒⠒⠒ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

Setting a different page layout for left- and right-hand pages:

@page { size: 10 6; }
@page:left {
  @bottom-center {
    content: '⠂⠂⠂⠂⠂⠂'
  }
}
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="6" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
        </page>
        <page>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row/>
          <row>⠀⠀⠂⠂⠂⠂⠂⠂⠀⠀</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠂⠂⠂⠂⠂⠂⠀⠀

12.2 Page Breaking

In order to avoid awkward breaks, the layout engine must be able to shift around content that would otherwise fall across the page break. The generic term for breaking content across containers such as page boxes is fragmentation, and the containers are called fragmentainers. [CSS3BREAK] defines how and where a sequence of boxes can be fragmented, including across page breaks. It defines properties for indicating where pages may or must be broken, and on what page (left or right) the subsequent content resumes.

Note

Lines and volumes are other examples of fragmentainers.

12.2.1 Controlling Page Breaks: the page-break-before, page-break-after, page-break-inside, orphans and widows properties

A page break opportunity between two boxes is under the influence of the containing block's page-break-inside property, the page-break-after property of the preceding element, and the page-break-before property of the following element. A page break opportunity between line boxes is under the influence of the containing block's widows and orphans properties. A break can be allowed, forced, or discouraged depending on the values of these properties. See the section Rules for Page Breaking below for the exact rules on how these properties affect page breaking.

Name: page-break-before
Value: auto | always | avoid | left | right
Initial: auto
Applies to: block | list-item
Inherited: no
Media: embossed
Computed value: specified value

avoid | left is currently not supported in the Liblouis based implementation.

Name: page-break-after
Value: auto | always | avoid | left | right
Initial: auto
Applies to: block | list-item
Inherited: no
Media: embossed
Computed value: specified value

left | right is currently not supported in the Liblouis based implementation.

Name: page-break-inside
Value: auto | avoid
Initial: auto
Applies to: block | list-item
Inherited: no
Media: embossed
Computed value: specified value

These properties control page break behaviour before, after and within the element's principle box. Values have the following meanings:

auto
Neither force nor forbid a page break before/after/inside the principle box.
always
Always force a page break before/after the principle box.
avoid
Avoid a page break before/after/inside the principle box.
left
Force one or two page breaks before/after the principle box so that the next page is formatted as a left page.
right
Force one or two page breaks before/after the principle box so that the next page is formatted as a right page.

Since breaks are allowed between siblings, but not between a box and its container (see Rules for Page Breaking), a page-break-before value on a first-child box is propagated to its container. Likewise a page-break-after value on a last-child box is propagated to its container.

Name: orphans
Value: <integer>
Initial: 0
Applies to: block | list-item
Inherited: no
Media: embossed
Computed value: specified value
Name: widows
Value: <integer>
Initial: 0
Applies to: block | list-item
Inherited: no
Media: embossed
Computed value: specified value

The orphans property specifies the minimum number of line boxes in a block container that must be left in a fragment before a page break. The widows property specifies the minimum number of line boxes of a block container that must be left in a fragment after a page break. Only positive integers are allowed. If a block contains fewer lines than the value of widows or orphans, the rule simply becomes that all lines in the block must be kept together.

widows is currently not supported in the Liblouis based implementation. See pipeline-mod-braille#13.

<body>
  <p id="1"> ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ ⠤⠤⠤ </p>
  <p id="2"> ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ </p>
  <p id="3"> ⠛⠛⠛ </p>
  <p id="4"> ⠸⠸⠸ ⠸⠸⠸ ⠸⠸⠸ ⠸⠸⠸ ⠸⠸⠸ </p>
</body>

Forcing page breaks:

@page { size: 10 5; }
p { display: block; }
p#1 { page-break-before: always; }
p#2 { page-break-after: always; }
p#3 { page-break-after: right; }
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="5" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
        </page>
        <page>
          <row>⠿⠿⠿</row>
        </page>
        <page>
          <row>⠛⠛⠛</row>
        </page>
      </section>
      <section>
        <page>
          <row>⠸⠸⠸⠀⠸⠸⠸</row>
          <row>⠸⠸⠸⠀⠸⠸⠸</row>
          <row>⠸⠸⠸</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠀⠀⠀⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠛⠛⠛⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠸⠸⠸⠀⠸⠸⠸⠀⠀⠀ ⠸⠸⠸⠀⠸⠸⠸⠀⠀⠀ ⠸⠸⠸⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

Forbidding page breaks:

@page { size: 10 5; }
p { display: block; }
p#2 { page-break-inside: avoid;}
p#3 { margin-top: 1; }
p#4 { page-break-before: avoid; }
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="5" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤</row>
        </page>
        <page>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿</row>
        </page>
        <page>
          <row/>
          <row>⠛⠛⠛</row>
          <row>⠸⠸⠸⠀⠸⠸⠸</row>
          <row>⠸⠸⠸⠀⠸⠸⠸</row>
          <row>⠸⠸⠸</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠛⠛⠛⠀⠀⠀⠀⠀⠀⠀ ⠸⠸⠸⠀⠸⠸⠸⠀⠀⠀ ⠸⠸⠸⠀⠸⠸⠸⠀⠀⠀ ⠸⠸⠸⠀⠀⠀⠀⠀⠀⠀
@page { size: 10 5; }
p { display: block; }
p#2 { widows: 2; }
p#3 { margin-top: 1; }
p#4 { orphans: 2; }
         
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="5" cols="10" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤⠀⠤⠤⠤</row>
          <row>⠤⠤⠤</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
        </page>
        <page>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿</row>
          <row/>
          <row>⠛⠛⠛</row>
        </page>
        <page>
          <row>⠸⠸⠸⠀⠸⠸⠸</row>
          <row>⠸⠸⠸⠀⠸⠸⠸</row>
          <row>⠸⠸⠸</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠤⠤⠤⠀⠀⠀ ⠤⠤⠤⠀⠀⠀⠀⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠛⠛⠛⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠸⠸⠸⠀⠸⠸⠸⠀⠀⠀ ⠸⠸⠸⠀⠸⠸⠸⠀⠀⠀ ⠸⠸⠸⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

12.2.2 Rules for Page Breaking

A flow may be broken across pages at a number of possible break points. In the case of forced breaks, the UA is required to break the flow at that point. In the case of unforced breaks the UA has to choose among the possible breaks that are allowed. Page breaks can occur between sibling block-level boxes (class A break point), or between line boxes inside a block container box (class B break point).

A forced page break occurs at a class A break point if, among the page-break-after and page-break-before properties of all the elements generating boxes that meet at this margin, there is at least one with a forced break value (always, left, or right).

A forced break takes precedence over any break restrictions acting at that point. When multiple forced break values apply to a single break point, they combine such that all types of break are honored. When left, and right are combined, the value specified on the latest element in the flow wins.

A forced page break (type right) also occurs at a class A break point if the last line box above this margin and the first one below it do not have the same value for page.

Unforced page breaks are inserted automatically in order to prevent content from overflowing the page. The following rules control whether unforced breaking at a break point opportunity is allowed:

  1. A page may be broken at a class A break point only if the page-break-after and page-break-before values applicable to this break point allow it, which is when at least one of them forces a break or when all of them are auto.
  2. However, if all of them are auto and a common ancestor of all the elements has a page-break-inside value of avoid, then breaking here is not allowed.
  3. Breaking at a class B break point is allowed only if the number of line boxes between the break and the start of the enclosing block box is the value of orphans or more, and the number of line boxes between the break and the end of the box is the value of widows or more.
  4. Additionally, breaking at a class B break point is allowed only if the page-break-inside property of all ancestors is auto.

If the above doesn't provide enough break points to keep content from overflowing the page, then rules 1, 2 and 4 are dropped in order to find additional break points. If that still does not lead to sufficient break points, rule 3 is dropped as well.

Note

Note that these rules only define where breaking is allowed, and while this specification requires that content does not overflow the page, it does not impose any particular algorithm for determining the exact break points.

12.2.3 Box Model for Page Breaking

Exactly how content breaks across pages is described in the section Box Model for Breaking [CSS3BREAK]. In short:

  • When a page break splits a block-level box, the box's margins, borders, and padding have no visual effect where the split occurs.
  • When a page break splits a block-level box, the box fragments may have different widths if the according page boxes have different widths.

13. Volumes

When producing braille on paper, a document may need to be split into several so called volumes due to size limits on paper books. Volumes are the physical units (books) that make up the complete work. This specification defines properties for controlling the size of volumes, where volumes may or must be broken, and for inserting content at the beginning or end of specific volumes.

13.1 The @volume rule

The properties of a volume, such as its dimensions, are determined by CSS properties declared within the volume context, using @volume rules.

A @volume rule consists of the keyword @volume, an optional volume selector, and a block of declarations and at-rules (said to be in the volume context). A volume selector is made of either a volume type selector, a volume pseudo-class, or a type selector followed by a pseudo-class. A volume selector matches a given volume if and only if all of its components match the volume. A volume type selector is a CSS identifier and matches volumes of the named volume type generated by the volume property. The volume pseudo-classes :first, :last and :nth(<n>) match the first, last and nth volume. If the pseudo-class follows a volume type selector, it matches the first, last or nth volume in a sequence of volumes of the specified type.

13.2 Volume Size: the min-length and max-length properties

Name: min-length
Value: <integer> | auto
Initial: auto
Applies to: volume context
Inherited: N/A
Media: embossed
Computed value: the specified value
Name: max-length
Value: <integer> | auto
Initial: auto
Applies to: volume context
Inherited: N/A
Media: embossed
Computed value: the specified value

The min-length and max-length properties specify the minimum and maximum allowed lengths of a volume in terms of pages. Negative lengths are illegal. The value auto means that no lower/upper constraint is set on the volume size. When max-length is auto and there are no forced volume breaks, the document must consist of a single volume.

13.3 Volume Areas: the @begin and @end rules

Volume areas are boxes at the beginning and end of volumes that can contain generated content. They are created by @begin and @end rules inside the volume context.

A @begin rule consists of the keyword @begin followed by a block of declarations. An @end rule consists of the keyword @end and a block of declarations.

A volume area box is generated if and only if the computed value of its content property is not none.

13.4 Using Named Volumes : the volume property

Name: volume
Value: auto | <custom-ident>
Initial: auto
Applies to: block | list-item
Inherited: no (see text)
Media: embossed
Computed value: the specified value

The volume property is used to specify a particular type of volume (called a named volume) on which an element must be displayed. If necessary, a forced volume break is introduced.

The volume property does not inherit. However, if the volume value on an element is auto, then its used value is the value specified on its nearest ancestor with a non-auto value. When specified on the root element, the used value for auto is the empty string.

13.5 Volume Breaking

In order to avoid awkward volume breaks (for instance, in the middle of a sentence, or after the first paragraph of a chapter), volumes sometimes need to be broken before the upper page bound has been reached. This specification defines properties for indicating where volumes may or must be broken. Breaks at certain places may be forced, encouraged or discouraged.

13.5.1 Controlling Volume Breaks: the volume-break-before, volume-break-after and volume-break-inside properties

A volume break opportunity between two boxes is under the influence of the containing block's volume-break-inside property, the volume-break-after property of the preceding element, and the volume-break-before property of the following element. See the section Rules for Volume Breaking below for the exact rules on how these properties affect volume breaking.

Name: volume-break-before
Value: auto | always | avoid | prefer
Initial: auto
Applies to: block | list-item
Inherited: no
Media: embossed
Computed value: specified value
Name: volume-break-after
Value: auto | always | avoid | prefer
Initial: auto
Applies to: block | list-item
Inherited: no
Media: embossed
Computed value: specified value
Name: volume-break-inside
Value: auto | avoid
Initial: auto
Applies to: block | list-item
Inherited: no
Media: embossed
Computed value: specified value

These properties control volume break behaviour before, after and within the element's principle box. Values have the following meanings:

auto
Neither force nor forbid nor encourage a volume break before/after/inside the principle box.
always
Always force a volume break before/after the principle box.
prefer
Encourage a volume break before/after the principle box
avoid
Avoid a volume break before/after/inside the principle box.

Since breaks are allowed between siblings, but not between a box and its container (see Rules for Volume Breaking), a volume-break-before value on a first-child box is propagated to its container. Likewise a volume-break-after value on a last-child box is propagated to its container.

13.5.2 Rules for Volume Breaking

A flow may be broken across volumes at a number of possible break points. In the case of forced breaks, the UA is required to break the flow at that point. In the case of unforced breaks the UA has to choose among the possible breaks that are allowed. Volume breaks can occur between sibling block-level boxes (class A break point), or between line boxes inside a block container box (class B break point).

A forced volume break occurs at a class A break point if, among the volume-break-after and volume-break-before properties of all the elements generating boxes that meet at this margin, there is at least one with a forced break value (always). A forced break takes precedence over any break restrictions acting at that point.

A forced volume break also occurs at a class A break point if the last line box above this margin and the first one below it do not have the same value for volume.

Unforced volume breaks are inserted automatically in order to meet the max-length constraints. The following rules control whether unforced breaking at a break point opportunity is allowed:

  1. A volume may be broken at a class A break point only if the volume-break-after and volume-break-before values applicable to this break point allow it, which is when at least one of them forces a break or when none of them are avoid.
  2. However, if none of them force a break and a common ancestor of all the elements has a volume-break-inside value of avoid, then breaking here is not allowed.
  3. Breaking at a class B break point is allowed only if the volume-break-inside property of all ancestors is auto.

If the above doesn't provide enough break points, the UA may break anywhere in order to avoid violating the max-length constraints.

In the end, all min-length constraints must be met as well, unless a volume being to short is the result of forced volume breaks.

Note

Note that these rules only define where breaking is allowed. The specification does not impose any particular algorithm for determining the exact break points.

14. Out-of-Flow Positioning

It is sometimes useful to take elements out of their normal flow and move or copy them into other containers. Examples include footnotes, volume endnotes, and repeated content at the beginning of volumes. This section describes a generic mechanism for moving content, called “named flows”. CSS is not a transformation language; the motivation for supporting named flows is presentational rather than structural.

Note

The approach taken in braille CSS is inspired by a number of CSS concepts and features described elsewhere:

14.1 Named Flows

A named flow is the ordered sequence of content associated with a flow with a given identifier. Content is placed into a named flow with the flow property, and taken out using the flow() value of the content property. The same element can participate in more than one flow (including the normal flow), and a named flow can have multiple sources and multiple destinations. This makes it possible to not only move but also copy and repeat content.

14.1.1 The flow property

Name: flow
Value: normal | <custom-ident>
Initial: normal
Applies to: all elements and ::alternate and ::duplicate pseudo-elements
Inherited: no
Media: embossed
Computed value: the specified value

The flow property causes an element to participate in the specified flow. The value must be one of the following:

normal
This value causes an element or pseudo-element to participate in the normal flow.
<custom-ident>
This value causes an element or pseudo-element to participate in the named flow with the specified name. The element or pseudo-element will not generate a box at the original position in the DOM.

The flow property does not affect the DOM position of an element or its contents, and it does not affect the CSS cascade and inheritance.

The visual formatting model however uses the relationships between content in the named flow as input, rather than the contents' original position in the DOM. Elements channelled into a named flow become siblings. A box establishes a containing block for the content it consumes using the flow() function. Elements in a named flow are ordered according to their document order.

14.1.2 The ::alternate and ::duplicate pseudo-elements

Content can be generated or duplicated using the ::alternate and ::duplicate pseudo-elements. The content of an ::alternate pseudo-element is determined by its content property. The content of a ::duplicate pseudo-element is copied from the element in the document tree to which it is associated. The ::alternate(<n>) and ::duplicate(<n>) notations can be used to create several ::alternate or ::duplicate pseudo-elements for one given element.

The flow property dictates in which flow a pseudo-element participates. A value normal causes the pseudo-element to be included where the element in the document tree to which it is associated would be positioned. It is not allowed that several pseudo-elements associated to the same element participate in the same flow (normal or named flow), nor that they participate in the same flow as the element they are associated to.

Unlike other pseudo-elements, these pseudo-elements inherit from the parent of the element to which it they are associated, not from that element itself.

14.1.3 The flow() function

The flow() function is used to consume named flows, via the content property. The function requires one argument, the name of the flow. Elements in the named flow are rendered as children of the block container on which the content property is specified. In the default case, all elements in a named flow are consumed as many times as there are flow() calls. This behaviour can be overridden with an optional second argument that specifies which elements should be included. Elements in a flow are duplicated as many times as needed in order to meet the demand.

flow() = flow( <custom-ident> [, [ document | volume ] ]? )

The second argument dictates the search direction and range and is one of the following keywords:

document
All the elements that have been added to the flow or will be added later are inserted here.
volume
All the elements that have been added to the flow within the current volume or will be added later within the current volume are inserted here.

14.2 Generated Lists

Books typically have sections that can be referred to as generated lists. They are generated from the main content, and have the nature of lists. Examples include a table of contents, an index, a glossary, a list of figures, a list of tables and an endnote section.

14.3 Footnotes

14.3.1 The @footnotes area

14.4 Endnotes

15. Tables

See braille-css#4.

16. Indication of Original Pagination

See braille-css#14.

<body>
  <span class="pagenum">⠼⠁</span>
  <p>
    ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿
    ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿
  </p>
  <span class="pagenum">⠼⠃</span>
  <p>
    ⠭⠭⠭ ⠭⠭⠭ ⠭⠭⠭ ⠭⠭⠭ ⠭⠭⠭
    <span class="pagenum">⠼⠉</span>
    ⠭⠭⠭ ⠭⠭⠭ ⠭⠭⠭ ⠭⠭⠭ ⠭⠭⠭
  </p>
  <p>
    ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿
    ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿ ⠿⠿⠿
  </p>
</body>

Using the string-set property and the string() function, print page numbers can be rendered in the page footer:

@page {
  size: 12 6;
  margin-bottom: 1;
  @bottom-right {
    content: string(print-page);
  }
}
p {
  display: block;
  text-indent: 2;
}
.pagenum {
  display: none;
  string-set: print-page content();
}
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="6" cols="12" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠀⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠀⠀⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠁</row>
        </page>
        <page>
          <row>⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠀⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠉</row>
        </page>
        <page>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row/>
          <row/>
          <row/>
          <row>⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠉</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠀⠀⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀⠀⠀ ⠀⠀⠭⠭⠭⠀⠭⠭⠭⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠁ ⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭⠀ ⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭⠀ ⠭⠭⠭⠀⠭⠭⠭⠀⠀⠀⠀⠀ ⠀⠀⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠉ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠉

The range of print pages covered on a braille page can be rendered in the page footer:

@page {
  size: 12 6;
  margin-bottom: 1;
  @bottom-right {
    content: string(print-page, start) string(dash-print-page, last-except-start);
  }
}
p {
  display: block;
  text-indent: 2;
}
.pagenum {
  display: none;
  string-set: print-page content(), dash-print-page '⠒' content();
}
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="6" cols="12" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠀⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠀⠀⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠀⠀⠀⠀⠀⠀⠀⠼⠁⠒⠼⠃</row>
        </page>
        <page>
          <row>⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠀⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠀⠀⠀⠀⠀⠀⠀⠼⠃⠒⠼⠉</row>
        </page>
        <page>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row/>
          <row/>
          <row/>
          <row>⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠉</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠀⠀⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀⠀⠀ ⠀⠀⠭⠭⠭⠀⠭⠭⠭⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠼⠁⠒⠼⠃ ⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭⠀ ⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭⠀ ⠭⠭⠭⠀⠭⠭⠭⠀⠀⠀⠀⠀ ⠀⠀⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠀⠀⠀⠀⠀⠀⠀⠼⠃⠒⠼⠉ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠉

The range of print pages covered on the current page spread can be rendered in the footer of the right-hand page:

@page {
  size: 12 6;
  margin-bottom: 1;
}
@page:right {
  @bottom-right {
    content: string(print-page, spread-start) string(dash-print-page, spread-last-except-start);
  }
}
p {
  display: block;
  text-indent: 2;
}
.pagenum {
  display: none;
  string-set: print-page content(), dash-print-page '⠒' content();
}
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="6" cols="12" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠀⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠀⠀⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠀⠀⠀⠀⠀⠀⠀⠼⠁⠒⠼⠃</row>
        </page>
        <page>
          <row>⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠀⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row/>
        </page>
        <page>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row/>
          <row/>
          <row/>
          <row>⠀⠀⠀⠀⠀⠀⠀⠼⠃⠒⠼⠉</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠀⠀⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀⠀⠀ ⠀⠀⠭⠭⠭⠀⠭⠭⠭⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠼⠁⠒⠼⠃ ⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭⠀ ⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭⠀ ⠭⠭⠭⠀⠭⠭⠭⠀⠀⠀⠀⠀ ⠀⠀⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠼⠃⠒⠼⠉

Print page breaks can be indicated with full lines across the width of the page, followed by the page number of the next print page:

@page { size: 12 6; }
p {
  display: block;
  text-indent: 2;
}
.pagenum {
  display: block;
  text-indent: 0;
}
.pagenum::before {
  content: leader('⠒') '⠀';
}
<pef xmlns="http://www.daisy.org/ns/2008/pef" version="2008-1">
  <head xmlns:dc="http://purl.org/dc/elements/1.1/">
    <meta>
      <dc:format>application/x-pef+xml</dc:format>
    </meta>
  </head>
  <body>
    <volume rows="6" cols="12" rowgap="0" duplex="true">
      <section>
        <page>
          <row>⠒⠒⠒⠒⠒⠒⠒⠒⠒⠀⠼⠁</row>
          <row>⠀⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠒⠒⠒⠒⠒⠒⠒⠒⠒⠀⠼⠃</row>
        </page>
        <page>
          <row>⠀⠀⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠒⠒⠒⠒⠒⠒⠒⠒⠒⠀⠼⠉</row>
          <row>⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠭⠭⠭⠀⠭⠭⠭</row>
          <row>⠀⠀⠿⠿⠿⠀⠿⠿⠿</row>
        </page>
        <page>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿</row>
          <row>⠿⠿⠿⠀⠿⠿⠿</row>
        </page>
      </section>
    </volume>
  </body>
</pef>
⠒⠒⠒⠒⠒⠒⠒⠒⠒⠀⠼⠁ ⠀⠀⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀⠀⠀ ⠒⠒⠒⠒⠒⠒⠒⠒⠒⠀⠼⠃ ⠀⠀⠭⠭⠭⠀⠭⠭⠭⠀⠀⠀ ⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭⠀ ⠒⠒⠒⠒⠒⠒⠒⠒⠒⠀⠼⠉ ⠭⠭⠭⠀⠭⠭⠭⠀⠭⠭⠭⠀ ⠭⠭⠭⠀⠭⠭⠭⠀⠀⠀⠀⠀ ⠀⠀⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠿⠿⠿⠀ ⠿⠿⠿⠀⠿⠿⠿⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

A. References

A.1 Normative references

[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119

A.2 Informative references

[CSS2]
Bert Bos; Tantek Çelik; Ian Hickson; Håkon Wium Lie et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 7 June 2011. W3C Recommendation. URL: http://www.w3.org/TR/CSS2
[CSS3BOX]
Bert Bos. CSS basic box model. 9 August 2007. W3C Working Draft. URL: http://www.w3.org/TR/2007/WD-css3-box-20070809
[CSS3BREAK]
Rossen Atanassov; Elika Etemad. CSS Fragmentation Module Level 3. 23 August 2012. W3C Working Draft. URL: http://www.w3.org/TR/2012/WD-css3-break-20120823/
[CSS3COUNTERSTYLES]
Tab Atkins Jr.. CSS Counter Styles Level 3. 3 February 2015. W3C Candidate Recommendation. URL: http://www.w3.org/TR/css-counter-styles-3/
[CSS3GCPM]
Dave Cramer. CSS Generated Content for Paged Media Module. 13 May 2014. W3C Working Draft. URL: http://www.w3.org/TR/2014/WD-css-gcpm-3-20140513/
[CSS3GENCON]
Ian Hickson. CSS3 Generated and Replaced Content Module. 14 May 2003. W3C Working Draft. URL: http://www.w3.org/TR/2003/WD-css3-content-20030514
[CSS3LINE]
Michel Suignard; Eric Meyer. CSS3 module: line. 15 May 2002. W3C Working Draft. URL: http://www.w3.org/TR/2002/WD-css3-linebox-20020515
[CSS3LIST]
Tab Atkins Jr.. CSS Lists and Counters Module Level 3. 20 March 2014. W3C Working Draft. URL: http://www.w3.org/TR/2014/WD-css-lists-3-20140320/
[CSS3PAGE]
Melinda Grant; Elika Etemad; Håkon Wium Lie; Simon Sapin. CSS Paged Media Module Level 3. 14 March 2013. W3C Working Draft. URL: http://www.w3.org/TR/2013/WD-css3-page-20130314/
[CSS3POS]
Bert Bos. CSS Positioned Layout Module Level 3. W3C Working Draft. URL: http://dev.w3.org/csswg/css-position/
[CSS3REGIONS]
Rossen Atanassov; Alan Stearns. CSS Regions Module Level 1. 18 February 2014. W3C Working Draft. URL: http://www.w3.org/TR/2014/WD-css3-regions-20140218/
[CSS3SYN]
David Baron. CSS Syntax Module Level 3. W3C Candidate Recommendation. URL: http://www.w3.org/TR/2014/CR-css-syntax-3-20140220/
[CSS3TEXT]
Elika Etemad; Koji Ishii. CSS Text Module Level 3. 13 November 2012. W3C Working Draft. URL: http://www.w3.org/TR/2012/WD-css3-text-20121113/
[CSS3VAL]
Håkon Wium Lie; Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 3. 30 July 2013. W3C Candidate Recommendation. URL: http://www.w3.org/TR/2013/CR-css3-values-20130730/
[CSSSTYLEATTR]
Tantek Çelik; Elika Etemad. CSS Style Attributes. 7 November 2013. W3C Recommendation. URL: http://www.w3.org/TR/css-style-attr
[PRINCE]
undefined. URL: http://www.princexml.com/doc/9.0/properties/
[SASS]
Sass (Syntactically Awesome StyleSheets). URL: http://sass-lang.com/documentation/file.SASS_REFERENCE.html
[UAX14]
Asmus Freytag. Line Breaking Properties. 29 March 2005. Unicode Standard Annex #14. URL: http://www.unicode.org/unicode/reports/tr14/tr14-17.html