Readium CSS
Implementers’ doc

Readium CSS Fundamental Concepts

[Implementers’ doc] [Authors’ info]

This document serves as an introduction, it explains the fundamental concepts used in designing Readium CSS.

1. We’re the User Agent

In the context of EPUB, we must assume the role of the User Agent.

Indeed, EPUB is not supported natively so we must build on top of web browsers’ rendering engine.

With such a role comes great responsibility: we must try to behave like browsers are behaving – i.e. be liberal in what we accept from authors –, and find a sensible balance between authors’ stylesheets and users’ overrides.

Authors and users have expectations though, and we had to take those into account. For instance, they are used to having EPUB contents laid out in a paged view, with reading modes (paper, sepia, night) and a minimal set of common settings.

By serving as a User Agent, we must make sure:

authors’ EPUB contents are rendered as expected (e.g. their styles are scoped, we don’t override them unless strictly necessary, etc.);

we do serve as a user’s agent by providing a Graphical User Interface to writing a user stylesheet (i.e. user settings) and applying those styles as expected.

2. Aim at Interoperability

Interoperability is the logical result of the User Agent role we’re claiming.

We’ve done our utmost to follow EPUB and CSS recommendations to the letter, but it vastly depends on practical implementations. As a consequence, Readium CSS ships with its own recommendations, so that you don’t need to check every related specification yourself.

Besides, we’ve checked other major EPUB implementations to provide authors with the best interoperability possible. Indeed, they may design their stylesheet against those implementations so we gave priority to building a reliable environment.

We wanted to bring EPUB closer to the web though, and decided to leverage HTML5 Suggested Rendering and improve the current situation whenever possible.

3. Leverage Modern CSS

CSS has a lot to offer nowadays, and it can help solve complex issues in simpler ways.

Readium CSS has been be designed following 4 core principles:

Modularity: Readium CSS is not a monolithic stylesheet but a set of modules;

Separation of Reading System’s Concerns: those modules are task-oriented e.g. paginate, apply default styles, intercept styles for reading modes or user settings, apply a reading mode or user setting, apply a theme, etc.;

Daisy-chainability: those modules can be loaded and daisy-chained (cascade) depending on conditions;

Customization: modules can be customized either before or during runtime (CSS variables), which implies themes can be generated within minutes.

4. Openness and Transparency

This last principle is important since the relationship between authors and Reading Systems’ developers has not been really great so far.

Therefore, feedback has been collected, samples have been used all along development, and decisions impacting authors have been openly discussed. All of this has been publicly documented during research and development.

More importantly, we must clearly state what is UA styles and user styles, and why !important is used. This process has a significant impact when it comes to transparency since it affects the cascade itself (see user settings recommendations). Should an author file an issue scoped to your implementation, please take the time to explain why you decided to differ and use !important, especially as such a decision can likely be backed by users’ feedback in many cases.

Quickstart

[Implementers’ doc]

Readium CSS is a set of reference stylesheets for EPUB Reading Systems. It provides styles for reflowable text:

a CSS normalize for EPUB contents;

paged and scrolled views;

default styles;

reading modes (night, sepia, etc.);

themes;

user settings.

Note: Readium CSS stylesheets were not designed and should not be used for fixed-layout EPUB, nor other file formats like FB2, PRC, Mobi, TEI, etc.

Important info

TL;DR: use the stylesheets in the css/dist folder if you don’t need to customize Readium CSS. All the flags and variables can then be taken at face value in the docs.

The src files, which are modules, can’t be used AS-IS. They indeed have to be processed by PostCSS to create dist stylesheets.

By default, those modules are daisy-chained and compiled into 3 dist stylesheets:

ReadiumCSS-before.css;

ReadiumCSS-default.css (for unstyled ebooks);

ReadiumCSS-after.css.

We’re currently managing RTL and CJK (including horizontal and vertical writing) scripts using specific dist stylesheets:

Right to Left stylesheets are distributed in an rtl folder;

CJK horizontal stylesheets are distributed in an cjk-horizontal folder;

CJK vertical stylesheets are distributed in an cjk-vertical folder.

The build process is currently subpar as it has been designed for our default and must be changed entirely if you want to process and use modules directly – which would make sense with HTTP2 for instance.

How To

Inject ReadiumCSS stylesheets into the <head> of (X)HTML documents.

ReadiumCSS-before.css

Authors’ stylesheet(s) or ReadiumCSS-default.css for unstyled publications

ReadiumCSS-after.css

Check the Stylesheets order doc for further details.

For RTL, you would then have to load the stylesheets in the rtl folder. Same for CJK. Check the “Internationalization” doc for guidance.

By default, we inject all stylesheets on load and rely on custom properties (a.k.a. CSS variables) set on html to apply user settings.

Customize

ReadiumCSS ships with a ReadiumCSS-config.css file you can use to customize it a little bit. It allows implementers to:

define in which conditions the auto pagination model is used;

choose selectors for the user settings’ flags.

In order to provide this customization, we use custom media and custom selectors, which will hopefully become standards implemented at some point, but require PostCSS at the moment. Consequently, you’ll have to rebuild all dist stylesheets if you’re changing this file.

Auto pagination model

The auto pagination model switches from 1 to 2 columns, and vice versa, when the conditions defined in ReadiumCSS-config.css are met. Further details about this model can be found in “Injection and pagination” doc.

On desktop, --responsive-columns is the min-width at which the model must be used. Default is 60em, a relative unit since it is responsive by default and will switch depending on the window’s dimensions and the font size.

Should you want it never or always applied, you can either define a min-width large or small enough, or remove the media queries entirely in ReadiumCSS-pagination.css and ReadiumCSS-colNumber_pref.css.

On mobile, --min-device-columns and --max-device-columns is the range of (minimum and maximum) device widths in which the model must be used. We are forcing the orientation in landscape.

We recommend not trying to apply it in portrait orientation because 2 columns will provide users with quite a terrible reading experience in this configuration.

Those custom medias may be extended at some point, depending on implementers’ feedbacks and issues.

Flags for user settings

By default, we are using flags in the form of CSS variables to manage reading modes and user settings. But you might want to customize those flags in order to use custom attributes (data-*) or good old CSS classes.

A complete list of flags can be found in the User preferences doc.

As an example, if you want to use a CSS class for night mode, it could look like:

@custom-selector :--night-mode .night-mode;

And if you want to use custom attributes for advanced settings, it could look like:

@custom-selector :--advanced-settings [data-settings="advanced"];

Both would then have to be appended to html at runtime.

Once again, you must rebuild dist stylesheets.

Add and remove modules

We have to add and remove modules depending on the language/script of the publication so this need is covered out of the box.

In the css/src folder, you’ll find all the needed stylesheets you will process to css/dist. Those stylesheets contain a list of imports e.g. for ReadiumCSS-before.css:

@import "../ReadiumCSS-config.css";
@import "modules/ReadiumCSS-base.css";
@import "modules/ReadiumCSS-day_mode.css";
@import "modules/ReadiumCSS-fonts.css";
@import "modules/ReadiumCSS-html5patch.css";
@import "modules/ReadiumCSS-safeguards.css";

As a consequence, modules you want to use have to be listed in those -before and -after files. Then rebuild them using PostCSS.

Additional user settings MUST be added to the user-settings-submodules folder, and make the required flag clear, if applicable.

Please remember to take the cascade into account, as issues might arise just because the order has been changed or modules moved from -before to -after – in which case we won’t be able to reproduce and debug an issue if we don’t know this important detail. See Stylesheets order doc for further details.

Reading System variables

If you want to change the name of --RS__ prefixed variables, you will have to change it in every module.

Build dist stylesheets

First, please make sure you have node.js installed. If you don’t, go download it on the official page.

Then navigate to the readium-css folder in your terminal and type:

npm install

This will install all dependencies needed to build dist stylesheets.

Once you have customized src files, in the terminal type:

npm run-script build

This will rebuild all dist stylesheets in their specific folder.

Options

Other scripts are available:

build:ltr for default stylesheets (Left to Right);

build:rtl for Right to Left stylesheets;

build:cjk for CJK scripts;

build:vertical for CJK and the Mongolian scripts in vertical writing.

Additional info

Further details about the build and test processes can be found in the npm doc.

User settings variables

If you want to change the name of --USER__ prefixed variables, you will have to change it in every module.

Manage User Settings

Currently, user settings are managed by setting CSS variables at the :root level (html element).

Flags

At the top of each user settings submodule, you will find the required flag for the preference.

This flag is needed for the setting to work.

User variables

All settings can be set using --USER__ prefixed variables. Set those properties for html and the cascade will automatically do its job.

To set a variable:

var root = document.documentElement || document.getElementById("iframe-wrapper").contentWindow.document.documentElement;
root.style.setProperty("--USER__var", "value");

To remove a variable:

var root = document.documentElement || document.getElementById("iframe-wrapper").contentWindow.document.documentElement;
root.style.removeProperty("--USER__var");

Please note you must implement a fallback strategy if you want to support Internet Explorer 11 and early versions of Microsoft Edge.

Examples

Changing hyphenation and justification

root.style.setProperty("--USER__advancedSettings", "readium-advanced-on");
root.style.setProperty("--USER__textAlign", "justify");
root.style.setProperty("--USER__bodyHyphens", "auto");

Of course this example is simplistic. You could for instance create an helper to set multiple properties at once.

Changing the type scale

You might want to change the type scale in order to adjust the font-size of all elements to the size of the screen and the global font-size set by the user. It can indeed help solve overflow issues for long words in headings, ridiculously large sizes, etc.

root.style.setProperty("--USER__advancedSettings", "readium-advanced-on");
root.style.setProperty("--USER__typeScale", "1.067");

Create Themes

In this model, themes are a set of user settings you can store and retrieve. Add the properties to html and you get a theme.

Check the User Preferences doc for a list of available user variables.

Inject and paginate EPUB contents

[Implementers’ doc] [Authors’ info]

Injection

Depending on the platform and version you’re developing for, contents must be injected into:

a web view;

a chrome view;

an iframe.

Indeed, we must provide authors with a reliable context in which their styles and scripts are scoped.

Margins and dimensions

Since we must take viewport units into account, especially vh (viewport height), at least the top and bottom margins must be set on this container, and not inside it.

You may also want to set left and right margins on this container so that all margins are equal in the two-column view.

Finally, on larger screens, you’ll have to set dimensions on this container so that it doesn’t become too large.

Background color

Please note you must deal with the background-color outside this container, especially as the user can set reading modes (night, sepia, etc.). In other words, it must be synced with this user setting so that the entire screen is the same background-color.

As a friendly reminder, you can allow transparency for the iframe if you’re using one. That should help deal with background-color at the global level.

<iframe src="source.xhtml" allowtransparency="true"></iframe>

Then set the --RS__backgroundColor variable to transparent in ReadiumCSS-base.css, although you will have to modify the current user settings stylesheet so that it can work this way.

Pagination

Contents are paginated using CSS multicolumns, for several reasons:

it’s been cross-platform for a long time;

it’s responsive;

it’s tried and tested;

it brings some kind of interoperability since it has been used by a lot of Reading Systems and authors have been designing against them.

Default

Pagination is responsive by default, which means it is using relative values in order to adapt layout to the viewport and the current font size.

We’ve chosen this approach since it appears setting everything in pixels is more likely to create rounding errors and rendering issues (e.g. cut-off text) than letting the rendering engine deal with relative units on its own.

The responsive design provides other benefits. For instance, if the reader is using an iPad in landscape mode and sets a bigger font size, the two-column view will automatically switch to a single-page view if needed.

You can also limit line-length by setting a max-width for body.

Please note a user setting for the number of columns has been designed so that users can set the layout as they wish.

The RS owns :root and part of body

Since we must inject contents and columns are implemented at the :root level (i.e. html), the Reading System owns the entire styling for this selector.

Font size is an important metric since the responsive design relies entirely on rem (root em) so this style must be enforced by any means necessary.

For body, we own:

overflow;

sizing: (min-|max-)width, (min-|max-)height, box-sizing;

spacing: margin and padding.

You can control horizontal margins in several ways:

using column-gap and padding for :root;

using column-gap and margin for the web view/chrome view/iframe;

using padding for :root and/or body.

Please note that when using padding, you must take it into account when sizing :root and/or body. Their widths contain the padding set for the element.

The auto pagination model

By default, responsive columns are built into Readium CSS, which means the layout will automatically switch from a single page to a two-column spread depending on:

the size of the viewport (by default, the minimum width is 60em or the mobile device is in landscape orientation);

the font-size currently set by the user.

The spread will consequently switch to a single page once the user sets a font-size which is too large for two columns.

The following illustrations are the two models you’ll have to deal with.

A single page is just a column which can grow to the entire width of the web view/iframe since it is declared for html.

Page margins are part of body, hence --RS__maxLineLength. Contents are centered using the auto value for body margins.

In the spread model, i.e. two columns, the --RS__colWidth is a floor: once the minimum width available (viewport) can’t contain 2 columns (the value is computed from the font-size user setting), we switch to the single page model.

For instance, if --RS__colWidth is 20em and the font-size, 100% (16px), then the floor is 320px. If 2 columns can fit in the viewport, the spread model is applied. If they can’t, the page model is applied. Hence, if the user sets the font-size at 200% (32px), the floor is 640px, which means the viewport should be at least 1240px-wide to apply the spread model.

Since we still limit line-length in the spread model, you might want to limit the web view/iframe size so that you don’t end up with wide gaps on large screens (or add padding to :root, and take it into account when scrolling).

Variables you can set

Please note those variables’ value can be redefined using media queries. You don’t need to redeclare entire declarations.

--RS__colWidth

The optimal column’s width. It serves as a floor in our design.

It must not be set in rem as there is currently a bug with this unit in some implementations (the em unit is fine).

--RS__colCount

The optimal number of columns (depending on the columns’ width).

--RS__colGap

The gap between columns. It must be set in pixels so that it won’t resize with font size.

You must account for this gap when scrolling.

--RS__pageGutter

The horizontal page margins. It must be set in pixels so that it won’t resize with font size.

--RS__maxLineLength

The optimal line-length. It must be set in rem in order to take :root’s font-size as a reference, whichever the body’s font-size might be.

Right-to-left progression

The auto pagination model will take care of itself if the correct dir attribute is set on html and body.

In other words, if dir="rtl" is set for both elements, the column-progression will be automatically reversed.

When to use the Right-to-left progression

What implementers need to do:

check the page-progression-direction for the spine item;

check the language – do not forget there can be multiple <dc:language> items;

load specific styles for RTL scripts;

append xml:lang and/or lang attribute if it’s missing in XHTML documents;

append dir="rtl" attributes if they’re missing for both html and body in XHTML documents;

load specific fonts’ lists for user settings, based on the primary language of the publication;

add/remove specific user settings, based on the primary language of the publication;

Apply the correct page-progression-direction (in RTL, next resource is on the left, previous is on the right);

change the direction of the toc and at least some pieces of user settings (e.g. text-align).

The current implementation is limited to the following combinations:

Language | IANA tag | page-progression-direction | dir attribute
Arabic | ar | RTL | rtl
Farsi (Persian) | fa | RTL | rtl
Hebrew | he | RTL | rtl

IANA Language Subtag registery.

We may add others at some point in the future. Please feel free to report the languages or scripts missing in this mapping. Please bear in mind a list of default (preferably system) fonts will greatly help to add support for those languages and scripts. See Default Fonts.

Test files can be retrieved from the Readium CSS’ i18n-samples OPDS feed.

Be cautious, the direction propagates

As explicitly stated in CSS Writing Modes Level 3:

As a special case for handling HTML documents, if the :root element has a <body> child element, the principal writing mode is instead taken from the values of writing-mode and direction on the first such child element instead of taken from the root element.

What this means is that the dir attribute (or the direction CSS property) set for body will override the one set for html. Unlike most other CSS properties, which don’t impact the parent element, the dir attribute (or the direction CSS property) propagates in this very specific case:

<html dir="ltr">
  <body dir="rtl">
    <!-- dir="rtl" should be used. -->

html {
  direction: ltr;
}
body {
  direction: rtl;
  /* rtl propagates to html and overrides ltr.
    You can think of it as a JS event bubbling up
    if that makes more sense. */
}

We MUST consequently force the direction for all documents in the publication, and can’t manage ltr documents in a rtl publication.

Note: While this isn’t necessarily the case in practice, in Blink, Gecko/Quantum and Webkit, and you can emulate a reversed column-progression for ltr documents in a rtl publication, this behavior may change in the future.

The pagination model for vertical writing modes

When publications are in Chinese, Japanese, Korean, and Mongolian, and laid out with a vertical-* writing mode, we must switch to a different model since we can’t do a two-column spread.

Indeed, columns are automatically laid out on the y-axis (vertical) with such writing modes, and the behavior of multi-column in orthogonal flows has been deferred to CSS Writing Modes Level 4.

We consequently use a “Fragmented Model”, as it differs significantly from the “Pagination Model”, especially the column-axis.

One can think of the fragmented model as the single page model rotated 90% clockwise. The only difference is that padding is added to the :root (html) element so that text doesn’t run from edge to edge.

Other options have been explored, e.g. a pseudo-algorithm mimicking margin: auto, using the calc() function, but it proved complex to manage well and raised serious performance issues, especially when resizing the window of a browser with documents making heavy use of text-direction and text-combine-upright.

When to use the fragmented model

What implementers need to do:

check the page-progression-direction for the spine item;

check the language – do not forget there can be multiple <dc:language> items;

load the specific styles for CJK if needed;

append xml:lang and/or lang attribute if it’s missing in XHTML documents;

load specific fonts’ lists for user settings, based on the primary language of the publication;

add/remove specific user settings, based on the primary language of the publication;

Apply the correct page-progression-direction (in RTL, next resource is on the left, previous is on the right).

Here is the correct mapping for combinations resulting in the vertical-* writing mode:

Language | IANA tag | page-progression-direction | Writing-mode
Chinese | zh | RTL | vertical-rl
Chinese (Traditional) | zh-Hant | RTL | vertical-rl
Chinese (Taiwan) | zh-TW | RTL | vertical-rl
Chinese (Hong Kong) | zh-HK | RTL | vertical-rl
Korean | ko | RTL | vertical-rl
Japanese | ja | RTL | vertical-rl
Mongolian | mn-Mong | LTR / Default / None | vertical-lr

IANA Language Subtag registery.

Test files can be retrieved from the Readium CSS’ i18n-samples OPDS feed.

When not to use the fragmented model

If a publication doesn’t need to be laid out in a vertical-* writing mode, the auto pagination model can be used.

There are still specific styles for CJK Horizontal to load though.

Here is the correct mapping for combinations resulting in the horizontal-tb writing mode:

Language | IANA tag | page-progression-direction | Writing-mode
Chinese | zh | LTR / Default / None | horizontal-tb
Chinese (Simplified) | zh-Hans | LTR / Default / None | horizontal-tb
Chinese (Taiwan) | zh-TW | LTR / Default / None | horizontal-tb
Chinese (Hong Kong) | zh-HK | LTR / Default / None | horizontal-tb
Korean | ko | LTR / Default / None | horizontal-tb
Japanese | ja | LTR / Default / None | horizontal-tb
Mongolian | mn-Cyrl | LTR / Default / None | horizontal-tb

IANA Language Subtag registery.

Be cautious, the writing-mode CSS property propagates

As explicitly stated in CSS Writing Modes Level 3:

As a special case for handling HTML documents, if the :root element has a <body> child element, the principal writing mode is instead taken from the values of writing-mode and direction on the first such child element instead of taken from the root element.

What this means is that the writing-mode declared for body will override the one declared for html. Unlike most other CSS properties, which don’t impact the parent element, writing-mode propagates in this very specific case:

html {
  writing-mode: horizontal-tb;
}
body {
  writing-mode: vertical-rl;
  /* vertical-rl propagates to html and overrides horizontal-tb.
     You can think of it as a JS event bubbling up
     if that makes more sense. */
}

We MUST consequently force the writing-mode for all documents in the publication, and can’t manage horizontal-tb documents in a vertical-rl publication.

Patch and safeguards

We’ve designed two extras for pagination:

a patch for HTML5 Suggested Rendering, which takes care of paged media;

safeguards, which make sure some elements will be managed as expected by authors in columns.

Patch

The HTML5 patch deals with:

fragmentation (widows, orphans and page-break);

hyphenation;

open type features;

horizontal margins (pixels have been converted to %);

normalization of abbr and wbr.

You can use it with or without pagination, it should not make any difference.

Safeguards

Safeguards deal with:

media sizing (e.g. img, svg, audio, video);

word wrap for long strings (headings and links);

large table’s overflow.

Once again, you can use it with or without pagination, it should not make any difference.

Variables you can set

--RS__maxMediaWidth

The max-width for media elements i.e. img, svg, audio and video.

--RS__maxMediaHeight

The max-height for media elements i.e. img, svg, audio and video.

--RS__boxSizingMedia

The box model (box-sizing) you want to use for media elements.

--RS__boxSizingTable

The box model (box-sizing) you want to use for tables.

How the multicolumn layout works

[Implementers’ doc] [Authors’ doc]

Global References:

W3C Spec

W3C Mailing List — css-multicol

Introduction

By using columns, content can flow from one column to another, and the number of columns can vary depending on the size of the viewport. The specification was originally designed to replace table-based multicolumn layout.

You can declare a multicolumn layout with one line of CSS:

body { column-width: 15em; }

Or

body { column-count: 2; }

Or

body { columns: 2 15em; }

The multi-column model

Multi-column layout introduces a new type of container between the content box and the content: the column box. This is a significant departure from the traditional box model.

The content of a multicol element is flowed into column boxes, which are arranged into rows, like table cells (inline direction). Consequently:

column width is the length of the column box in the inline direction;

column height is the height of the column box in the block direction;

all column boxes in a row have the same column width and column height;

adjacent column boxes are separated by a column gap, which may contain a column rule;

all column gaps (and column rules) in the same row are equal;

column rules only appear between columns that both have content.

Critical shortcomings can be pointed out in the column box model:

it is not possible to set properties/values on column boxes, which is why you can’t set the background of one specific column;

the column box has no concept of padding, margin or borders;

column boxes don’t establish containing blocks for elements with position: fixed || absolute;

multicol elements with column heights larger than the viewport may pose accessibility issues.

However, floats inside multi-column layouts are positioned with regard to the column box where they appear.

Finally, since a multi-column element establishes a new block formatting context, a top margin set on the first child element will not collapse with the margins of the multicol element.

The number and width of columns

Basically, two properties determine the width of columns:

column-count;

column-width.

A third one, columns, is a shorthand which sets both.

Column width

This property describes the width of columns in multicol elements.

Its values can be:

auto, which means the column width will be determined by other properties (column-count if set);

<length>, which describes the optimal column width.

The actual column width may be wider (to fill the available space), or narrower. But the column width can only be narrower if the available space is smaller that the specified column width.

Notes

To ensure that column-width can be used with vertical text, column width means the length of the line boxes inside the columns.

To set an exact column width, all length values (width, column-width, and column-gap) must be specified.

Column count

This property describes the number of columns of a multicol element.

Its values can be:

auto, which means the number of columns will be determined by other properties (column-width if set);

<integer>, which describes the optimal number of columns into which the content of the element will be flowed.

It is important to note that if both column-width and column-count have non-auto values, the integer value describes the maximum number of columns.

Columns

This is the shorthand property for setting column-width and column-count. Omitted values are set to their initial values (auto).

Pseudo-algorithm

The pseudo-algorithm below determines the used values for column-count (N) and column-width (W). There is one other variable in the pseudo-algorithm: the used width of the multi-column element (U).

The used width of the multi-column element (U) can depend on the element’s contents, in which case it also depends on the computed values of the column-count and column-width properties. The specification does not define how U is calculated.

(01)  if ((column-width = auto) and (column-count = auto)) then
(02)      exit; /* not a multicol element */
(03)  if column-width = auto then
(04)      N := column-count
(05)  else if column-count = auto then
(06)      N := max(1,
(07)        floor((U + column-gap)/(column-width + column-gap)))
(08)  else
(09)      N := min(column-count, max(1,
(10)        floor((U + column-gap)/(column-width + column-gap))))
(11)  W := max(0, ((U + column-gap)/N - column-gap))

What is important to understand there is that the column-width can either be a floor or a ceiling, depending on the value of column-count.

Let’s take some examples.

/* Condition starting at line 3 applies */
body { column-width: auto; column-count: 2; }

The column width is not set, it entirely depends on column-count and column-gap (which suggested default is 1em).

Columns theoretically have a floor (which is suggested to be 1px or less) and a ceiling (line 11)

/* Condition starting at line 5 applies */
body { column-width: 300px; column-count: auto; }

In this example, the number of columns is computed depending on the column width and gap.

In other words, the column width is a ceiling: it can’t be larger than 300px but can shrink if the available width is less.

/* Condition starting at line 8 applies */
body { column-width: 300px; column-count: 2; }

In this example, the column width is a floor: if 2 columns (2 × column width and the gap) can fit, column-count will be honored, else column-width grows to the width available. If there is additional width available when 2 columns fit, column-width will grow as well.

It’s worth noting that the used value for column-count is calculated without regard for explicit column breaks or constrained column heights, while the actual value takes these into consideration.

Stacking contexts

Column boxes do not establish new stacking contexts.

Column gaps and rules

What is important is that column gaps take up space while column rules don’t.

column gaps will push apart content in adjacent columns (within the same multicol element);

if there is a column rule between columns, it will appear in the middle of the gap.

As regards column rules:

they are painted just above the background of the multicol element so that child elements with z-index values to be on top of column rules;

they are only drawn between two columns that both have content.

Fragmentation (column break)

This has been moved to the CSS Fragmentation module.

When a page or column break splits a box, the box’s margins, borders, and paddings have no visual effect where the split occurs. It is important to remark outline and box-shadow are not discussed at all in the spec.

In the previous spec, it was stated that “the margin immediately after a forced page or column break will be preserved” but that isn’t necessarily the case in practice, CSS authors often having to resolve to padding-top to force a margin after a page break.

From experience, avoiding a break-inside elements flowing in 2 or 3 columns can also be problematic (the element vertical alignment is completely off).

Column span

You can only span all columns or none. It is not possible to declare an <integer>.

An element establishes a new block formatting context if its column-span is set to all. In other words, column-span kind of resets the flow to the first column.

We may not necessarily worry about this (in authors’ CSS) because the User Agent can treat it as column-span: none if it can’t find room to make the element spanning. Constraining the height of columns should be enough to prevent a column span, especially with overflow.

Filling columns

By default, columns will be balanced (minimal variation in column length), they won’t be filled sequentially.

This default can be overridden with

body { column-fill: auto; }

It’s worth noting User Agents should try to honor widows and orphans in any case.

Overflow

What is important to remark is that:

content that extends into column gaps is not clipped to the column box;

a multicol element can have more columns that it has room for, additional column boxes are created in the inline direction (page or column break, constrained height, etc.);

columns that appear outside the multicol element are called overflow columns.

Reflow

CSS multicol relies on a complex (fragmentation) logic, and this logic varies for each browser.

In Blink and Webkit for instance, a reflow won’t happen for the document (:root) if we don’t force a reflow at the body level. As a consequence, we’re using the --RS__maxLineLength CSS variable to force this reflow and slightly alter its value whenever needed e.g. “pagination to scroll” in vertical writing, mix-blend-mode in sepia mode, “number of columns” user setting, etc.

This will recalc the body’s max-width, causing a reflow which will propagate to the column layout we set for :root.

Notorious limitations

When the spec was published, the Financial Times immediately switched to its own JavaScript implementation for the following reasons:

configurable column widths, gutters and margins;

better handling of position: absolute || fixed;

support of column-span: <integer>;

better fragmentation (column breaks);

grouping of columns into pages;

enforce a baseline grid;

better handling of box-shadow and outline.

As far as we can tell, this implementation might create some issues, especially when it comes to a11y because it duplicates and hides part of elements to manage fragmentation.

Notes

It is our understanding the Opera implementation of overflow: -o-paged-x in Presto solved most of the spec’s limitations, as listed by the Financial Times:

position: fixed || absolute;

fragmentation;

column-span: integer;

overflow, by switching to paged media;

implementing CSS figures as a bonus.

It is important to note the spec has been republished as a Working Draft. It is very unlikely a level 2 spec will tackle those problems in the short term.

From experience, we can also report there tends to be implementation-specific bugs with newer layout specs e.g. flexbox, grid, etc.

Missing pieces

There are several shortcomings we must deal with:

the column-gap applies to adjacent column boxes, but there is nothing to set a columns-start-margin and columns-end-margin: this is particularly problematic when columns are set at the :root level and overflow;

there is no JavaScript API available, we don’t even know the number of columns which have been created and their real width;

since we can’t use overflow: paged-x, there is no way we can force the scrollWidth to be a multiple of the viewport, we must force the creation of an extra column if needed.

the lack of “column queries” makes it really difficult for authors to do responsive design.

Reading Systems Requirements for reflowable text

[Implementers’ doc] [Authors’ doc]

Source: EPUB Content Documents 3.2

There’s a few criteria Reading Systems must meet in order to be conformant:

it must support the official definition of CSS as described in the W3C CSS Snapshot;

it must support all -epub- prefixed properties (list).

In addition:

it should support all applicable modules in CSS Snapshot which have reached at least Candidate Recommendation status and are widely implemented;

its user agent stylesheet should support HTML Suggested Rendering;

it should respect authors CSS and user styles as defined in Reading System overrides.

CSS Snapshot

Since we’re relying on web browsers’ rendering engine and web views, this should not be an issue. Our main concern should be future-proofing Readium CSS to stay up-to-date with current/modern CSS authoring (cf. issue #12)

Prefixed properties

Blink and Webkit rendering engines may support some but it is unclear how we can be 100% conformant there, as it would require parsing the CSS to replace -epub-properties with the standard ones if the author has not used them.

As a matter of fact,

Authors are advised to use CSS-native solutions for the removed properties where and when they are available.

and,

Authors currently using these prefixed properties are advised to move to unprefixed versions as soon as support allows.

Proposal: let the rendering engine/web view deal with this. We don’t have Houdini yet and parsing CSS is a heavy process altering performance pretty badly.

HTML Suggested Rendering

We made sure we can rely on UA Stylesheets and have created a patch for paged views.

The patch deals with:

fragmentation (widows, orphans, page breaks);

hyphenation;

open type features;

borders;

horizontal spacing;

little normalization between UA stylesheets.

It doesn’t change the nature of HTML Suggested Rendering though, it only builds on it for EPUB rendering (adjustments).

Reading System Overrides

What’s important:

users should be able to override authors’ styles as desired;

reading systems should not override authors’ styles unless strictly necessary, in a way that preserves the Cascade.

We meet both requirements by default.

As regards the cascade, the following list is the priority order we should emulate:

important user agent declarations;

important user declarations;

important author declarations;

normal author declarations;

normal user declarations;

normal user agent declarations.

Most user declarations have to use !important to make sure they are applied, which is conformant. However, we try to manage “normal author declarations” by carefully targeting selectors for each user setting.

Few user agent declarations have to use !important as well, in order to make sure the EPUB file displays as expected (pagination, page margins, etc.). In other words, those overrides are strictly necessary.

Please make sure to check the “CSS User Setting Recommendations” and “Stylesheets Order” to manage overrides as best as possible.

Notes

A conformant author’s stylesheet must not:

use the direction property;

use the unicode-bidi property.

Order in which to append Readium CSS reflowable modules

[Implementers’ doc] [Authors’ info]

Readium CSS is leveraging the cascade in order to provide authors with defaults, paginate contents and apply user overrides and themes. As a consequence, there is a specific order in which reflowable stylesheets must be added. Indeed, conformance with CSS Cascading and Inheritance Level 3 requires that we make authors’ stylesheets an integral part of our cascade.

Dist stylesheets

Inject ReadiumCSS dist stylesheets into the <head> of (X)HTML documents.

ReadiumCSS-before.css

Authors’ stylesheet(s) or ReadiumCSS-default.css for unstyled publications

ReadiumCSS-after.css

For RTL, you would then have to load the stylesheets in the rtl folder. Same for CJK. Check the “Internationalization” doc for guidance.

By default, we inject all stylesheets on load and rely on custom properties (a.k.a. CSS variables) set on html to apply user settings.

Src modules

If you want to customize dist stylesheets, you’ll have to respect the following guidelines and rebuild dist stylesheets.

Insert before the author’s stylesheets

The following modules must be inserted before the author’s stylesheets (ReadiumCSS-before.css), in this exact order:

ReadiumCSS-config.css

ReadiumCSS-base.css

ReadiumCSS-day_mode.css

ReadiumCSS-fonts.css

ReadiumCSS-html5patch.css

ReadiumCSS-safeguards.css (or ReadiumCSS-safeguards-vertical.css for CJK – vertical writing mode)

Append if there is no author’s styles

The following modules must be appended if there is no external stylesheet (<link>), internal stylesheet (<style>) or inline styles in the document (style=" "), in this exact order:

ReadiumCSS-default.css

This default must be appended before all other modules in the next section.

Append after the author’s stylesheets

The following modules must be appended after the author’s stylesheets (ReadiumCSS-after.css), ideally in this order:

ReadiumCSS-config.css

ReadiumCSS-pagination.css (or ReadiumCSS-pagination-vertical.css for CJK – vertical writing mode)

ReadiumCSS-scroll.css (or ReadiumCSS-scroll-vertical.css for CJK – vertical writing mode)

ReadiumCSS-night_mode.css

ReadiumCSS-sepia_mode.css

ReadiumCSS-os_a11y.css

User settings:

ReadiumCSS-colNumber_pref.css (does not apply to CJK – vertical writing mode)

ReadiumCSS-pageMargins_pref.css (or ReadiumCSS-pageMargins-vertical_pref.css for CJK – vertical writing mode)

ReadiumCSS-customColors_pref.css

ReadiumCSS-textAlign_pref.css (does not apply to CJK scripts)

ReadiumCSS-bodyHyphens_pref.css (does not apply to CJK scripts)

ReadiumCSS-fontFamily_pref.css

ReadiumCSS-a11yFont_pref.css (does not apply to RTL and CJK scripts)

ReadiumCSS-fontSize_pref.css

ReadiumCSS-lineHeight_pref.css

ReadiumCSS-paraSpacing_pref.css (or ReadiumCSS-paraSpacing-vertical_pref.css for CJK – vertical writing mode)

ReadiumCSS-paraIndent_pref.css (does not apply to CJK scripts)

ReadiumCSS-wordSpacing_pref.css (does not apply to RTL and CJK scripts)

ReadiumCSS-letterSpacing_pref.css (does not apply to RTL scripts, except in vertical writing mode)

ReadiumCSS-arabicLigatures_pref.css (RTL only)

`ReadiumCSS-ruby_pref.css` (CJK only)

ReadiumCSS-fs_normalize.css

How to use CSS custom properties (a.k.a. variables)

[Implementers’ doc]

Note: CSS variables are not and won’t be supported in IE11. You can either create a static stylesheet for all UA browsers or decide to leverage them in most UA browsers + use a JS fallback for IE11 if you want to support this browser – you can test for CSS variables support in JS.

What are CSS variables?

CSS variables allow an author to assign arbitrary values to a property with an author-chosen name. This custom property must start with --. The var() function then allows the author to use those values elsewhere in the document.

:root {
	--primaryColor: red;
}

a {
	color: var(--primaryColor);
}

button {
	color: white;
	background-color: var(--primaryColor);
}

If you’re familiar with CSS pre-processors (LESS, SASS, Stylus, etc.), you’re probably using variables already. The major difference is that CSS variables are supported in the browser and, consequently, you can access and edit them in real-time using JavaScript.

Global references:

CSS Custom Properties spec

Can I Use

CSS Variables: Why should you care — developers.google.com

CSS Custom Properties in Microsoft Edge

PostCSS plugin to transform CSS variables into a static representation

JS Perf — CSS Variables vs. Inline Styles

CSS Variables are a game changer

Cascade and inheritance

Custom properties follow standard cascading rules. In other words, you can define the same property at different levels of specificity.

:root {
	--fontSize: 16px;
}

aside {
	--fontSize: 12px;
}

body, aside {
	font-size: var(--fontSize);
	/* Will be 16px for body and 12px for aside */
}

You can also use them in media queries.

:root {
	--defaultFontSize: 16px;
}

@media screen and (max-width: 560px) {
	:root {
		--defaultFontSize: 14px;
	}
}

html {
	font-size: var(--defaultFontSize);
	/* Will be 14px if the viewport max-width < 560px and 16px otherwise */
}

To sum things up, variables bring a lot of flexibility and customization to CSS. It can also simplify your stylesheets and make them much more maintainable.

Fallback

In case you want to use them, you’ll have to hardcode values for IE11 (and Edge 14).

:root {
	--primaryColor: red;
}

a {
	color: red; /* Fallback */
	color: var(--primaryColor);
}

button {
	color: white;
	background-color: red; /* Fallback */
	background-color: var(--primaryColor);
}

That could be managed via JavaScript though, so that you don’t need to maintain fallbacks in pure CSS.

It is important to note the var() function provides a fallback mechanism itself, in case your custom property is not set.

The function looks like this:

var(<custom-property-name> [, <declaration-value> ]? )

:root {
	/* No --primaryColor in there */
}

a {
	color: var(--primaryColor, red); /* In which red is the fallback */
}

button {
	color: white;
	background-color: var(--primaryColor, red); /* In which red is the fallback */
}

That could be useful for theming for instance, by setting default values as fallbacks then declaring custom properties using JavaScript.

Although browsers have been optimized to deal with CSS variables, please note performance might suffer in some browsers if you have a lot of variables with a fallback.

Using CSS variables in JavaScript

Feature detect

As seen in this article by Michael Scharnagl, if you want to test for support, you can do the following:

if (window.CSS && window.CSS.supports && window.CSS.supports('--a', 0)) {
	// CSS custom properties supported.
} else {
	// CSS custom properties not supported
}

Since CSS feature queries are not supported by IE11, the previous snippet will return false.

It will return true for browsers which support feature queries since @supports only checks if the syntax is correct (and don’t bother checking if the custom property exists).

Retrieve values

You can retrieve values by using getPropertyValue("--name_of_the_variable") (it is a computed style).

var myColor = window.getComputedStyle(document.documentElement).getPropertyValue("--textColor");

Set values

You can set values by using setProperty("--name_of_the_variable", "value").

document.documentElement.style.setProperty("--textColor", "#000");

If you’re appending a style element in the head of the document, you can also change the value in there, especially if you have a lot of elements to manage. For instance, if a --maxImageHeight variable is defined in the CSS for img, you could do the following:

var newStyles = document.createElement('style');
newStyles.id = "overrides";
var docHeight = window.getComputedStyle(document.body).getPropertyValue("height") + "px";
var newMaxImageHeight = document.createTextNode("img {--maxImageHeight: " + docHeight + ";}");
newStyles.appendChild(newMaxImageHeight);
document.head.appendChild(newStyles);

This will override the value in the original CSS since the img selector is more specific. It is important to notice you could hardcode styles here for browsers which don’t support variables (adding max-height: docHeight to the textNode you’re appending in the stylesheet).

Interesting hacks

CSS variables offer a lot of flexibility.

Avoid JS concatenation

As seen in this article by Zack Bloom, if you want to avoid managing concatenation (value + unit) in JavaScript, you could use the calc() function in CSS.

.element {
	height: calc(var(--element-height) * 1px);
}

Testing active breakpoints

As seen in this article by Eric Ponto, you could create a --breakpoint variable to “emulate” something like container/element queries.

body {
	--breakpoint: medium;
}

@media screen and (max-width: 30em) {
	body {
		--breakpoint: small;
	}
}

@media screen and (min-width: 50em) {
	body {
		--breakpoint: large;
	}
}

Then create a function to return the breakpoint and append styles accordingly.

You could probably leverage such a hack to implement some kind of column-width media query in paged view, but it would require CSS authors to provide specific stylesheets with this non-standard media as a link attribute – otherwise, performance will be really really bad as you would have to hijack the entire stylesheet to retrieve media queries first.

Setting another variable as a value

As seen in the developers.google.com article, you can set the value of the variable to refer to another variable at runtime by using the var() function in your call to setProperty().

document.documentElement.style.setProperty("--primary-color", "var(--secondary-color)");

Abusing CSS variables to make them read and acted on by JavaScript

As seen in the spec itself (example 3), you could create values which sole purpose is to be read and acted on by JavaScript.

While the following variable would obviously be useless as a variable (invalid value):

--foo: if(x > 5) this.width = 10;

You could use it in JavaScript since it’s still a valid custom property.

User themes

You could even go the extra mile and provide an “import theme” feature or implement custom styles inputs (color pickers, font family, etc.) in the UI so that users can create their own theme on the fly, then manage it more easily (storing the user theme as a style element with an id in localStorage for instance).

See this CSS-Tricks’ article for use cases and demos.

Defaults

[Implementers’ doc] [Authors’ info]

Defaults is currently made of 5 stylesheets:

1 base stylesheet for all ebooks;

1 default reading mode stylesheet for all ebooks (day mode);

1 default stylesheet for unstyled ebooks;

1 stylesheet to deal with the OS’ a11y modes.

Note: The default stylesheet should not be appended if there are author styles in the EPUB file.

Base

The base stylesheet deals with:

default typography;

default font-family depending on the language.

Those values are obviously customizable.

It should be appended before any author’s stylesheet.

Variables you can set

Default font-stacks

--RS__oldStyleTf

An old style serif font-stack relying on pre-installed fonts.

Default is "Iowan Old Style", "Sitka Text", Palatino, "Book Antiqua", serif.

--RS__modernTf

A modern serif font-stack relying on pre-installed fonts.

Default is Athelas, Constantia, Georgia, serif.

--RS__sansTf

A neutral sans-serif font-stack relying on pre-installed fonts.

Default is -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif.

--RS__humanistTf

A humanist sans-serif font-stack relying on pre-installed fonts.

Default is Seravek, Calibri, Roboto, Arial, sans-serif.

--RS__monospaceTf

A monospace font-stack relying on pre-installed fonts.

Default is "Andale Mono", Consolas, monospace.

Default font-stacks for Japanese publications

We’ve been trying to follow the recommendations of the EBPAJ File Creation Guide and provide specific font-stacks that can handle both horizontal and vertical writing.

Those font-stacks have been modeled after fonts the templates of this guide use as defaults, and extend support to the largest amount of platforms possible.

--RS__serif-ja

A Mincho font-stack whose fonts with proportional latin characters are prioritized for horizontal writing.

Fonts are not necessarily pre-installed, which is the reason why this font-stack is extensive.

Default is "Hiragino Mincho ProN", "Hiragino Mincho Pro", "YuMincho", "BIZ UDPMincho", "Yu Mincho", "ＭＳ Ｐ明朝", "MS PMincho", serif.

--RS__sans-serif-ja

A Gothic font-stack whose fonts with proportional latin characters are prioritized for horizontal writing.

Fonts are not necessarily pre-installed, which is the reason why this font-stack is extensive.

Default is "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ W3", "YuGothic", "Yu Gothic Medium", "BIZ UDPGothic", "Yu Gothic", "ＭＳ Ｐゴシック", "MS PGothic", sans-serif.

--RS__serif-ja-v

A Mincho font-stack whose fonts with fixed-width latin characters are prioritized for vertical writing.

Fonts are not necessarily pre-installed, which is the reason why this font-stack is extensive.

Default is "Hiragino Mincho ProN", "Hiragino Mincho Pro", "YuMincho", "BIZ UDMincho", "Yu Mincho", "ＭＳ明朝", "MS Mincho", serif.

--RS__sans-serif-ja-v

A Gothic font-stack whose fonts with fixed-width latin characters are prioritized for vertical writing.

Fonts are not necessarily pre-installed, which is the reason why this font-stack is extensive.

Default is "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ W3", "YuGothic", "Yu Gothic Medium", "BIZ UDGothic", "Yu Gothic", "ＭＳゴシック", "MS Gothic", sans-serif.

Absolute defaults for all ebooks

--RS__baseFontFamily

The default typeface for body copy in case the ebook doesn’t have one declared.

Please note some languages have a specific font-stack (japanese, chinese, hindi, etc.)

--RS__baseLineHeight

The default line-height for body copy in case the ebook doesn’t have one declared.

We’re using an algorithm to find the ideal line-height for the current font based on its metrics (see details in the next subsection below).

--RS__lineHeightCompensation

The compensation factor (integer) the dynamic leading pseudo-algorithm must apply, if used. Default is 1 i.e. no compensation.

This variable is redefined by default, in languages and scripts which need compensation due to the characteristics of their average fonts’ metrics.

Dynamic leading (line-height)

If we don’t provide a base line-height and the author hasn’t explicitely set one, then the normal value will be applied. On average, it is less than 1.2, which makes leading quite solid and can quickly become a readability issue with some fonts, especially the ones with a large x-height.

Readium CSS consequently uses an algorithm to find the ideal leading for each font by default (with a fallback value accomodating every script/language it supports).

This algorithm tries to:

automagically adjust the line-height to the current typeface;

adjust this ideal line-height it has just computed to the current font-size the user has set.

calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation))

In which, --RS__lineHeightCompensation is a factor whose default is 1. Indeed, the line-height is usually 15–20% larger in CJK than in other scripts/languages (factor of 1.167), but it can also used for square-ish fonts, especially in Indic.

The results we could get for the vast majority of fonts can be described as good in terms of typographic color. Here is Iowan Old Style for instance.

This isn’t a perfect solution though, and this algorithm may be revisited in the future.

See Further Details for an extensive explanation.

Day Mode

The ReadiumCSS-day_mode.css stylesheet serves as a default and handles background-color and color for :root and ::selection.

Variables you can set

--RS__backgroundColor

The background-color for the entire viewport.

--RS__textColor

The color for body copy.

--RS__selectionBackgroundColor

The background-color for selected text.

It is worth noting it can be customized for each reading mode.

--RS__selectionTextColor

The color for selected text.

It is worth noting it can be customized for each reading mode.

Default

The default stylesheet was designed for unstyled ebooks. It is based on HTML5 Suggested Rendering and can be customized.

Although it must not be used for styled ebooks, it should not impact the author’s styles if it is added before its stylesheet(s).

You can customize:

the typeface for headings (body is in base.css);

the typeface for code;

the font-size for body copy;

the base line-height for all elements;

the vertical margins for block elements;

the vertical margins for paragraphs;

the text-indent for paragraphs;

the typescale;

the color for links (including visited);

a primary accent color (unused by default);

a secondary accent color (unused by default).

It makes use of a typescale so that you can change it dynamically (depending on page size, font size, etc.) so that headings and other elements can be adjusted.

Variables you can set

Typefaces

--RS__compFontFamily

The typeface for headings. The value can be another variable e.g. var(-RS__humanistTf).

--RS__codeFontFamily

The typeface for code snippets. The value can be another variable e.g. var(-RS__monospaceTf).

Typography

--RS__typeScale

The scale to be used for computing all elements’ font-size. Since those font sizes are computed dynamically, you can set a smaller type scale when the user sets one of the largest font sizes.

Possible values: 1 | 1.067 | 1.125 | 1.2 (suggested default) | 1.25 | 1.333 | 1.414 | 1.5 | 1.618

--RS__baseFontSize

The default font-size for body copy. It will serve as a reference font all related computations.

--RS__baseLineHeight

The default line-height for all elements.

Vertical rhythm

--RS__flowSpacing

The default vertical margins for HTML5 flow content e.g. pre, figure, blockquote, etc.

--RS__paraSpacing

The default vertical margins for paragraphs.

--RS__paraIndent

The default text-indent for paragraphs.

Hyperlinks

--RS__linkColor

The default color for hyperlinks.

--RS__visitedColor

The default color for visited hyperlinks.

Accentuation colors

--RS__primaryColor

An optional primary accentuation color you could use for headings or any other element of your choice.

--RS__secondaryColor

An optional secondary accentuation color you could use for any element of your choice.

OS’ a11y modes

This stylesheet is intended to deal with a11y settings users can set at the OS level, whenever possible:

high-contrast mode;

inverted colors;

monochrome;

reduced motion.

For monochrome, we’ll have to adjust reading modes (night, sepia, etc.) in their specific stylesheet; we’ll see if we can at least manage some more global settings in there.

Typefaces and font-stacks

[Implementers’ doc] [Authors’ info]

In order to get the best performance and language support possible, we tried to design off-the-rack font-stacks using pre-installed system fonts.

Those font-stacks cover:

MacOS > 10.9;

iOS > 9;

Windows > 7;

Android > 4.4.4.

The unicode ranges to be found in this document are specifically scoped to their language and are provided in case you want to use other typefaces: it can help you check support and extended coverage, and subset if needed.

Test files

Test files can be retrieved from the Readium CSS’ i18n-samples OPDS feed.

Fundamentals

UA defaults if no font-family is set usually are:

Times (New Roman)

Droid Sans/Roboto on Android

You could force Android using a serif font by declaring

font-family: “Times New Roman”;

But it will be resolved to Droid Serif.

For generic families (sans-serif, serif, monospace), you’ll usually get:

Arial/Helvetica/Roboto for sans-serif;

Times/Times New Roman/Droid Serif for serif;

Courier/Courier New/Droid Mono for monospace.

Historically, monospaced fonts have had a font-size of 13.33px. You’d better be cautious about that since a margin of 1em will indeed be 13.33px for pre.

Finally, rendering engines fall back on a glyph basis. If a glyph is not available in the preferred font, it will check if it is in the second one, and so on and so forth, for each glyph.

UI

If you want a system font stack, it already exists.

font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantrell, "Helvetica Neue", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";

This is a modernized version taking popular Linux distros and emoji into account.

Latin

Old Style (serif)

font-family: "Iowan Old Style", "Sitka Text", Palatino, "Book Antiqua", serif;

Serif will resolve to Droid Serif on Android.

Open Type features available for those fonts are:

Typeface | Small-caps | Oldstyle nums | Linear nums | Proportional nums | Tabular nums
Iowan Old Style | YES | YES | YES | YES | YES
Sitka Text | YES | YES | YES | YES | YES
Droid Serif | NO | NO | NO | NO | NO

Modern (serif)

font-family: Athelas, Constantia, Georgia, serif;

Serif will resolve to Droid Serif on Android.

Open Type features available for those fonts are:

Typeface | Small-caps | Oldstyle nums | Linear nums | Proportional nums | Tabular nums
Athelas | NO | NO | NO | NO | NO
Constantia | YES | YES | YES | YES | YES
Droid Serif | NO | NO | NO | NO | NO

Neutral (sans)

Same as UI font-stack or the following simplified version:

font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Noto, "Helvetica Neue", Arial, sans-serif;

Open Type features available for those fonts are:

Typeface | Small-caps | Oldstyle nums | Linear nums | Proportional nums | Tabular nums
San Fransisco | YES | NO | NO | YES | YES
Segoe UI | YES | YES | YES | YES | YES
Roboto | YES | YES | YES | YES | YES
Helvetica Neue | NO | NO | NO | YES | YES

Humanist (sans)

font-family: Seravek, Calibri, Roboto, Arial, sans-serif;

Sans-serif will resolve to Droid Sans or Roboto on Android.

Open Type features available for those fonts are:

Typeface | Small-caps | Oldstyle nums | Linear nums | Proportional nums | Tabular nums
Seravek | YES | YES | YES | YES | YES
Calibri | YES | YES | YES | YES | YES
Roboto | YES | YES | YES | YES | YES

Monospace

font-family: "Andale Mono", Consolas, monospace;

Monospace will resolve to Droid Sans Mono on Android.

Apple is shipping a monospaced San Fransisco in High Sierra but it is still unclear how you can access it in CSS.

Unicode ranges

Unicode ranges are:

/* Basic Latin */
unicode-range: U+0020-007F;

/* Latin-1 supplement */
unicode-range: U+0080-00FF;

/* Latin extended A */
unicode-range: U+0100-017F;

/* Latin extended B */
unicode-range: U+0180-024F;

In addition, you might want to cover Greek and Cyrillic.

/* Greek and coptic */
unicode-range: U+0370-03FF;

/* Cyrillic */
unicode-range: U+0400-04FF;

/* Cyrillic Supplement */
unicode-range: U+0500-052F;

Amharic (am)

font-family: Kefa, Nyala, Roboto, Noto, "Noto Sans Ethiopic", serif;

Warning: no iOS.

unicode-range: U+1200-137F, U+1380-139F;

Arabic (ar)

font-family: "Geeza Pro", "Arabic Typesetting", Roboto, Noto, "Noto Naskh Arabic", "Times New Roman", serif;

unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF;

Bengali/Bangla (bn)

font-family: "Kohinoor Bangla", "Bangla Sangam MN", Vrinda, Roboto, Noto, "Noto Sans Bengali", sans-serif;

unicode-range: U+0980-09FF;

Tibetan (bo)

font-family: Kailasa, "Microsoft Himalaya", Roboto, Noto, "Noto Sans Tibetan", sans-serif;

unicode-range: U+0F00-0FFF;

Cherokee (chr)

font-family: "Plantagenet Cherokee", Roboto, Noto, "Noto Sans Cherokee";

Warning: no iOS.

unicode-range: U+13A0-13FF;

Persian (fa)

font-family: "Geeza Pro", "Arabic Typesetting", Roboto, Noto, "Noto Naskh Arabic", "Times New Roman", serif;

unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF;

Gujarati (gu)

font-family: "Gujarati Sangam MN", "Nirmala UI", Shruti, Roboto, Noto, "Noto Sans Gujarati", sans-serif;

unicode-range: U+0A80-0AFF;

Hebrew (he)

font-family: "New Peninim MT", "Arial Hebrew", Gisha, "Times New Roman", Roboto, Noto, "Noto Sans Hebrew" sans-serif;

unicode-range: U+0590-05FF;

Hindi (hi)

font-family: "Kohinoor Devanagari", "Devanagari Sangam MN", Kokila, "Nirmala UI", Roboto, Noto, "Noto Sans Devanagari", sans-serif;

unicode-range: U+0900-097F, U+A8E0-A8FF;

Armenian (hy)

font-family: Mshtakan, Sylfaen, Roboto, Noto, "Noto Serif Armenian", serif;

Warning: no iOS.

unicode-range: U+0530-058F;

Inuktitut (iu)

font-family: "Euphemia UCAS", Euphemia, Roboto, Noto, "Noto Sans Canadian Aboriginal", sans-serif;

unicode-range: U+1400-167F;

Japanese (ja)

font-family: YuGothic, "Hiragino Maru Gothic ProN", "Hiragino Sans", "Yu Gothic UI", "Meiryo UI", "MS Gothic", Roboto, Noto, "Noto Sans CJK JP", sans-serif;

unicode-range: U+3000-303F, U+3040-309F, U+30A0-30FF, U+FF00-FFEF, U+4E00-9FAF;

Khmer (km)

font-family: "Khmer Sangam MN", "Leelawadee UI", "Khmer UI", Roboto, Noto, "Noto Sans Khmer", sans-serif;

unicode-range: U+1780-17FF, U+19E0-19FF;

Kannada (kn)

font-family: "Kannada Sangam MN", "Nirmala UI", Tunga, Roboto, Noto, "Noto Sans Kannada", sans-serif;

unicode-range: U+0C80-0CFF;

Korean (ko)

font-family: "Nanum Gothic", "Apple SD Gothic Neo", "Malgun Gothic", Roboto, Noto, "Noto Sans CJK KR", sans-serif;

unicode-range: U+1100-11FF, U+3130-318F, U+A960-A97F, U+AC00-D7AF, U+D7B0-D7FF;

Lao (lo)

font-family: "Lao Sangam MN", "Leelawadee UI", "Lao UI", Roboto, Noto, "Noto Sans Lao", sans-serif;

unicode-range: U+0E80-0EFF;

Malayalam (ml)

font-family: "Malayalam Sangam MN", "Nirmala UI", Kartika, Roboto, Noto, "Noto Sans Malayalam", sans-serif;

unicode-range: U+0D00-0D7F;

Oriya (or)

font-family: "Oriya Sangam MN", "Nirmala UI", Kalinga, Roboto, Noto, "Noto Sans Oriya", sans-serif;

unicode-range: U+0B00-0B7F;

Punjabi (pa)

font-family: "Gurmukhi MN", "Nirmala UI", Kartika, Roboto, Noto, "Noto Sans Gurmukhi", sans-serif;

unicode-range: U+0A00-0A7F;

Sinhalese (si)

font-family: "Sinhala Sangam MN", "Nirmala UI", "Iskoola Pota", Roboto, Noto, "Noto Sans Sinhala", sans-serif;

unicode-range: U+0D80-0DFF;

Tamil (ta)

font-family: "Tamil Sangam MN", "Nirmala UI", Latha, Roboto, Noto, "Noto Sans Tamil", sans-serif;

unicode-range: U+0B80-0BFF;

Telugu (te)

font-family: "Kohinoor Telugu", "Telugu Sangam MN", "Nirmala UI", Gautami, Roboto, Noto, "Noto Sans Telugu", sans-serif;

unicode-range: U+0C00-0C7F;

Thai (th)

font-family: "Thonburi", "Leelawadee UI", "Cordia New", Roboto, Noto, "Noto Sans Thai", sans-serif;

unicode-range: U+0E00-0E7F;

Chinese (zh-CN)

font-family: "方体", "PingFang SC", "黑体", "Heiti SC", "Microsoft JhengHei UI", "Microsoft JhengHei", Roboto, Noto, "Noto Sans CJK SC", sans-serif;

unicode-range: U+3000-303F, U+3040-309F, U+30A0-30FF, U+FF00-FFEF, U+4E00-9FAF;

Chinese – Hong Kong (zh-HK)

font-family: "方體", "PingFang HK", "方體", "PingFang TC", "黑體", "Heiti TC", "Microsoft JhengHei UI", "Microsoft JhengHei", Roboto, Noto, "Noto Sans CJK TC", sans-serif;

Chinese – Taiwan (zh-TW)

font-family: "方體", "PingFang TC", "黑體", "Heiti TC", "Microsoft JhengHei UI", "Microsoft JhengHei", Roboto, Noto, "Noto Sans CJK TC", sans-serif;

Dyslexic

This is a tricky topic, and it needs quite some expertise, so those won’t be recommendations per se but mere insights, since extended research is currently being done in this field. As a consequence, implementers willing to provide the best experience possible should try to keep up-to-date.

Typefaces don’t work in a vacuum

From research conducted by Charles Bigelow – who designed Lucida and Wingdings with Kris Holmes –, on a corpus of existing scientific research and books:

In the scientific literature, I found no evidence that special dyslexia fonts confer statistically significant improvements in reading speed compared to standard, run-of-the-mill fonts. Some studies found that for certain subsets of reading errors, special dyslexia fonts do reduce error rates for dyslexic readers, yet for other subsets of errors, special dyslexic fonts were no better, or in some cases worse; hence, the findings on reading errors are mixed.

Typography is indeed a system and other factors have to be taken into account:

[…] the sizing, spacing, and arrangement of type, but not typeface design per se – a few scientific papers found that certain variations in typography offer statistically significant benefits to dyslexic readers.

If needed, the sources of papers and studies available online at the time of this research are listed in this companion article.

General tips

It is important to emphasize that the user settings (and their values) implementers will offer users is as equally – if not more – important as the typefaces themselves.

A list of general tips:

avoid justified text (text-align setting);

use generous line spacing/leading (line-height setting);

use generous letter spacing (letter-spacing setting);

avoid italics (--USER__a11yNormalize flag);

generally use sans serif faces (font-family setting);

use larger text (font-size setting);

use good contrast (background- and color settings, reading modes, themes);

use clear, concise writing.

The WCAG 2.1 spec, especially the “Adapting text” section, can serve as a starting point to choose the values you might at least offer to users for those settings.

We’ve been trying to define a baseline for a11y-related user settings, and you’ll find further information and extra features you might want to implement in the “Baseline for a11y-related user settings” document (e.g. alternated colors for lines of text or words, etc.).

On typefaces themselves

Although typefaces specifically designed for dyslexia exist, users might prefer system fonts they are used to. The following system typefaces are almost always listed as good for dyslexia:

Arial/Helvetica

Trebuchet MS

Verdana

Those fonts are available on both Windows and MacOS/iOS so it would be a good idea to have at least 2 of them available in the typeface user setting. We are recommending extra options in the Open Source and Libre Fonts though, in case you want to provide users with more specific fonts.

More importantly, preference is a key factor, and implementers might want to give access to user-installed fonts if the platform allows. When doing research, some participants indeed emphasized they installed a specific font for dyslexia, and they want to be able to use it in the reading app as well.

Conclusion

It’s not just about fonts, it’s about typography and user settings allowing its customization.

At the very minimum, you might want to provide:

2–3 system fonts listed as good for dyslexia;

a font specifically designed for dyslexia;

a reliable font-size setting (i.e. that will work for all reflowable EPUB files);

a line-height setting;

a text-align setting;

a letter-spacing setting.

It is noteworthy that everything extra will have to be implemented with great care: too many settings might create a cognitive overload for some users, so UX research should be conducted accordingly.

Math

This is the font-stack used by Webkit, it tries to leverage fonts users might have installed via LaTeX.

font-family: "Latin Modern Math", "STIX Two Math", "XITS Math", "STIX Math", "Libertinus Math", "TeX Gyre Termes Math", "TeX Gyre Bonum Math", "TeX Gyre Schola", "DejaVu Math TeX Gyre", "TeX Gyre Pagella Math", "Asana Math", "Cambria Math", "Lucida Bright Math", "Minion Math", STIXGeneral, STIXSizeOneSym, Symbol, "Times New Roman", serif;

EBPAJ patch for Japanese

The EBPAJ template only references fonts from MS Windows so Readium CSS has to reference fonts from other platforms and override authors’ stylesheets. What this patch does is to keep the default value used in EBPAJ templates and provide fallbacks for all platforms.

Implementers might want to load this patch only if they find one of the following metadata items in the OPF package:

version 1: <dc:description id="ebpaj-guide">ebpaj-guide-1.0</dc:description>

version 1.1: <meta property="ebpaj:guide-version">1.1</meta>

Since @font-face must be used to align with EBPAJ’s specific implementation (rendering engines have to go through 9–11 local sources in the worst-case scenario), implementers should expect a performance debt.

Open Source and Libre Fonts We Can Recommend

[Implementers’ doc] [WIP]

While we recommend using system fonts to get the best performance whenever possible, implementers might want to use Open Source Fonts to offer more choice to users. On the Android platform, for instance, system fonts are limited to one typeface per generic family (serif, sans-serif, fantasy, monospace, and cursive), which means implementers don’t get a lot of options out of the box.

Consequently, amongst the thousands of fonts available online, a pre-selection of 28 typefaces have been reviewed extensively. Those typefaces were selected based on multiple factors:

they have enough styles (at least the 4 “core styles” i.e. regular, italic, bold, bold italic) so that implementers don’t break authors’ expectations;

they can be used in body copy;

they are designed with quality screen rendering in mind;

they can be free alternatives to system fonts available on other platforms;

they offer good-enough support for at least latin-based languages.

Here’s the complete list of those 28 fonts:

Alegreya

Bitter

Charis SIL

Clear Sans

Crimson Text

DejaVu Sans

Faustina

Fira Sans

Gandhi Sans

Gandhi Serif

Gentium Book Basic

Heuristica

IBM Plex Sans

IBM Plex Serif

Libre Franklin

Lora

Literata

Merriweather Sans

Merriweather Serif

Proza Libre

PT Sans

PT Serif

Rosario

Rubik

Source Sans Pro

Spectral

Volkhov

Vollkorn

How were those fonts reviewed

Each of the 28 fonts has been undergoing tests in real rendering situations.

They were rendered on the Android, iOS, MacOS, and Windows platforms, using SD and HD displays when possible, in multiple browsers (IE11, Edge, Safari, Chrome, Firefox), and in different reading modes (day, sepia, night).

Then each font was:

compared to its closest reference (system font);

tested against the latin, cyrillic and greek alphabets and languages;

tested against the small capitals and numeric OpenType features.

Note: For some reason, a lot of Google Fonts don’t have the “™” character. Font stacks should consequently be fine-tuned so that this character doesn’t disrupt the reading experience.

Results

It is important to state that implementers can’t really go wrong with those 27 fonts.

We sometimes forget that users can’t necessarily afford bleeding-edge technology, which is why it was important to review those fonts in various conditions.

The 12 recommended fonts are simply providing the best rendering in the worst situations possible (Windows ClearType on a mediocre screen), and the best language support as well. If you don’t have to support Windows, for instance, then you can try fonts which are not recommended.

For your information, here are the results for Windows ClearType rendering at 1em (or 100%).

Buggy

IBM Plex Sans (will become excellent once hinting issues are fixed)

Mediocre

Alegreya

Crimson Text (but supports latin + cyrillic + greek)

Lora

Spectral (using weight +100 might help e.g. medium as regular and extrabold as bold)

Average

DejaVu Sans

Faustina (Average+)

Gentium Book Basic

Heuristica

Volkhov

Good

Bitter (the Google Fonts version was reviewed but the FontSquirrel version is more complete)

Charis SIL

Gandhi Serif

Literata

PT Sans

PT Serif

Rubik

Source Sans Pro

Vollkorn

Excellent

Clear Sans

Fira Sans

Gandhi Sans

IBM Plex Serif

Merriweather Sans

Merriweather Serif

Proza Libre

Rosario

Recommended Typefaces

An extended selection of 13 typefaces are recommended to offer implementers some flexibility. With an extended solution, it is likely that all apps leveraging Readium CSS won’t end up using the same exact selection.

Note: Supported Languages focus on diacritics. Support for languages using the latin alphabet, like English, is implied.

Serif fonts

Charis SIL

Global info:

Source: https://software.sil.org/charis/

Google Fonts: NO

Design: SIL International

License: SIL-OFL

Technical details:

Reference: Charter

Classification: Slab

Styles: 4

Metrics:

Contrast: TBD

x-height: TBD

weight: TBD

width: TBD

Supported Languages: Albanian, Bosnian, Czech, Danish, Dutch, Estonian, Finnish, French, German, Hungarian, Italian, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish, Turkish, Cyrillic.

OpenType Features: none.

Faustina

Global info:

Source: https://github.com/Omnibus-Type/Faustina

Google Fonts: YES

Design: Omnibus Type

License: SIL-OFL

Technical details:

Reference: Bookerly

Classification: Slab

Styles: 8

Metrics:

Contrast: 0.39

x-height: 0.76

weight: 0.06

width: 0.45

Supported Languages: Albanian, Bosnian, Czech, Danish, Dutch, Estonian, Finnish, French, German, Hungarian, Italian, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish, Turkish.

OpenType Features: none.

IBM Plex Serif

Global info:

Source: https://github.com/IBM/type

Google Fonts: Not Yet

Design: IBM

License: SIL-OFL

Technical details:

Reference: Georgia, Droid Serif

Classification: Modern

Styles: 6

Metrics:

Contrast: TBD

x-height: TBD

weight: TBD

width: TBD

Supported Languages: Albanian, Bosnian, Czech, Danish, Dutch, Estonian, Finnish, French, German, Hungarian, Italian, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish, Turkish.

OpenType Features: none.

Literata

Global info:

Source: https://github.com/googlefonts/literata

Google Fonts: YES

Design: TypeTogether

License: SIL-OFL

Technical details:

Reference: Georgia, Droid Serif

Classification: Modern, Slab

Styles: 8

Metrics:

Contrast: TBD

x-height: TBD

weight: TBD

width: TBD

Supported Languages: Albanian, Bosnian, Czech, Danish, Dutch, Estonian, Finnish, French, German, Hungarian, Italian, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish, Turkish, Cyrillic, Greek.

OpenType Features: small caps, numeric figure values, numeric spacing values.

Merriweather

Global info:

Source: https://fonts.google.com/specimen/Merriweather

Google Fonts: YES

Design: Sorkin Type Co

License: SIL-OFL

Technical details:

Reference: Iowan Old Style

Classification: Modern (but must be mapped to Iowan Old Style because of its metrics)

Styles: 8

Metrics:

Contrast: 0.51

x-height: 0.75

weight: 0.08

width: 0.52

Supported Languages: Albanian, Bosnian, Czech, Danish, Dutch, Estonian, Finnish, French, German, Hungarian, Italian, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish, Turkish, Cyrillic.

OpenType Features: none.

PT Serif

Global info:

Source: https://fonts.google.com/specimen/PT+Serif

Google Fonts: YES

Design: ParaType

License: Paratype PT Serif Free Font License

Technical details:

Reference: Charter

Classification: Slab

Styles: 4 (+ 2 for captions)

Metrics:

Contrast: 0.55

x-height: 0.71

weight: 0.06

width: 0.47

Supported Languages: Albanian, Bosnian, Czech, Danish, Dutch, Estonian, Finnish, French, German, Hungarian, Italian, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish, Turkish, Cyrillic.

OpenType Features: none.

Vollkorn

Global info:

Source: http://vollkorn-typeface.com

Google Fonts: YES

Design: Friedrich Althausen

License: SIL-OFL

Technical details:

Reference: Athelas, Bembo

Classification: Modern

Styles: 8

Metrics:

Contrast: 0.53

x-height: 0.68

weight: 0.06

width: 0.45

Supported Languages: Albanian, Bosnian, Czech, Danish, Dutch, Estonian, Finnish, French, German, Hungarian, Italian, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish, Turkish, Cyrillic.

OpenType Features: small caps, numeric figure values, numeric spacing values (and more).

Sans-serif fonts

Clear Sans

Global info:

Source: https://01.org/clear-SANS

Google Fonts: NO

Design: Intel

License: Apache 2.0

Technical details:

Reference: Trebuchet MS

Classification: Sans

Styles: 8

Metrics:

Contrast: TBD

x-height: TBD

weight: TBD

width: TBD

Supported Languages: Albanian, Bosnian, Czech, Danish, Dutch, Estonian, Finnish, French, German, Hungarian, Italian, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish, Turkish, Cyrillic, Greek.

OpenType Features: none.

Fira Sans

Global info:

Source: https://github.com/mozilla/Fira

Google Fonts: YES

Design: Carrois Apostrophe for Mozilla

License: SIL-OFL

Technical details:

Reference: Seravek

Classification: Humanist

Styles: 18

Metrics:

Contrast: 0.25

x-height: 0.76

weight: 0.07

width: 0.42

Supported Languages: Albanian, Bosnian, Czech, Danish, Dutch, Estonian, Finnish, French, German, Hungarian, Italian, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish, Turkish, Cyrillic, Greek.

OpenType Features: none.

Libre Franklin

Global info:

Source: https://github.com/impallari/Libre-Franklin

Google Fonts: YES

Design: Impallari Type

License: SIL-OFL

Technical details:

Reference: Franklin Gothic

Classification: Sans

Styles: 18

Metrics:

Contrast: 0.28

x-height: 0.71

weight: 0.07

width: 0.44

Supported Languages: Albanian, Bosnian, Czech, Danish, Dutch, Estonian, Finnish, French, German, Hungarian, Italian, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish, Turkish.

OpenType Features: none.

Merriweather Sans

Global info:

Source: https://fonts.google.com/specimen/Merriweather+Sans

Google Fonts: YES

Design: Sorkin Type Co

License: SIL-OFL

Technical details:

Reference: San Fransisco, Roboto

Classification: Sans

Styles: 8

Metrics:

Contrast: 0.30

x-height: 0.75

weight: 0.08

width: 0.45

Supported Languages: Albanian, Bosnian, Czech, Danish, Dutch, Estonian, Finnish, French, German, Hungarian, Italian, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish, Turkish.

OpenType Features: none.

PT Sans

Global info:

Source: https://fonts.google.com/specimen/PT+Sans

Google Fonts: YES

Design: ParaType

License: Paratype PT Sans Free Font License

Technical details:

Reference: Seravek

Classification: Humanist

Styles: 4 (+ 2 for captions + 2 for narrow)

Metrics:

Contrast: 0.16

x-height: 0.71

weight: 0.06

width: 0.39

Supported Languages: Albanian, Bosnian, Czech, Danish, Dutch, Estonian, Finnish, French, German, Hungarian, Italian, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish, Turkish, Cyrillic.

OpenType Features: none.

Source Sans Pro

Global info:

Source: https://github.com/adobe-fonts/source-sans-pro

Google Fonts: YES

Design: Adobe

License: SIL-OFL

Technical details:

Reference: Seravek

Classification: Humanist

Styles: 12

Metrics:

Contrast: 0.20

x-height: 0.74

weight: 0.06

width: 0.39

Supported Languages: Albanian, Bosnian, Czech, Danish, Dutch, Estonian, Finnish, French, German, Hungarian, Italian, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish, Turkish.

OpenType Features: numeric figure values.

Windows

Microsoft has been investing a lot of resources in designing fonts that render perfectly on this platform, especially with ClearType. Typefaces like Cambria, Constantia, Arial Nova, Georgia Pro, Sitka, Verdana Pro, and more, offer a large amount of styles, excellent language support, extensive support of Open Type features, and high quality rendering, even on mediocre screens.

As a consequence, we strongly recommend prioritizing such system fonts for the core selection and using Open Source fonts as extras. A list of system fonts available can be found in Microsoft Typography docs.

Recommended fonts for Accessibility

ReadiumCSS is shipping with 2 a11y-related fonts to be found in the dist/fonts folder:

AccessibleDfA, by Orange;

IA Writer Duospace, by iA;

Those fonts should be applied by those exact names as we need very precise fallbacks for missing characters. We may create variables in the future, once those fonts have been properly reviewed and validated.

We can also recommend Open Dyslexic, either in addition to or replacement of AccessibleDfa.

Recommended fonts for CJK

In addition to Google Noto Fonts, we can currently recommend:

Adobe Source Han Sans;

Adobe Source Han Serif;

KoPub fonts for Korean.

Recommended fonts for Hebrew

In addition to Google Noto Fonts, we can currently recommend:

Alef;

David Libre;

Heebo;

Rubik Hebrew.

Recommended fonts for Arabic and Persian

In addition to Google Noto Fonts, we can currently recommend:

Amiri;

Mirza;

Scheherazade.

Recommended fonts for Indic

In addition to Google Noto Fonts, we can currently recommend:

Catamaran (Tamil script);

Hind Family (Bengali, Devanagari, Gujarati, Gurmukhi, Kannada, Malayalam, Sinhalese, Tamil, and Telugu scripts);

Mutka Family (Devanagari, Gujarati, Gurmukhi and Tamil scripts);

Vesper Libre (Devanagari script).

User Overrides’ Classification

[Implementers’ doc] [Authors’ info]

In order to help you manage user settings, we defined 4 types of overrides:

chrome (UI);

chrome advanced;

user overrides;

user overrides advanced.

Those types can help you decide which settings should be applied to every book, which should be implemented based on your UX approach or the first to be displayed in the customization panel, etc.

Chrome

The following settings are required and should be applied by any means necessary:

reading modes;

paged/scrolled view.

Chrome advanced

The following settings are optional but should be applied by any means necessary, without any flag, if they are provided to users:

number of columns;

page margins;

custom reading modes (background and text color);

filters (darken and invert for night mode).

User overrides

The following settings are required and should be applied with their required flag by any means necessary:

font-family (requires :--font-overide flag);

font-size (requires :--advanced-settings flag).

User overrides advanced

The following settings are optional but should be applied by any means necessary, with the :--advanced-setting flag, if they are provided to users:

line-height;

text-align and hyphens (those two should probably work together);

paragraph spacing;

paragraph indent;

letter-spacing;

word-spacing;

arabic ligatures;

hiding ruby (CJK);

accessibility normalization;

type scale.

Please note this classification might change and additional items be added in the future.

User Settings, Reading Modes and Themes

[Implementers’ doc] [Authors’ info]

The idea is:

appending/removing flags and CSS variables for user settings (inline style on html);

managing user settings entirely via CSS so that we don’t need to manipulate the DOM too much.

There are alternatives approaches you can adopt if this one doesn’t fit.

Note: Possible values are strict i.e. implementers can’t use any other value; recommended values are loose i.e. they are left to implementers’ judgment.

Mechanism for user settings

The ReadiumCSS-after.css stylesheet, which contains user settings, can be appended before runtime; its declarations won’t be applied until user variables are set.

User settings require the following process:

add the flag and its value to html when applicable (font override, font size and/or advanced setting);

add the setting-specific variable and its value to html;

styles are updated live.

The selectors used in user settings are indeed “conditional”, styles are applied if the variable (or a specific value for reading modes) is set as an inline style in html (:root).

Setting and removing a variable

Setting

var root = document.documentElement;
root.style.setProperty("name of var", "value");

You don’t need to remove the variable before setting another value, the new value will simply override the existing one.

Removing

You can either remove the style explicitly with removeProperty():

var root = document.documentElement;
root.style.removeProperty("name of var");

Or implicitly by using an empty string as a value with setProperty():

var root = document.documentElement;
root.style.setProperty("name of var", "");

Setting a property with an empty string as the value will indeed invoke removeProperty(), as defined in the CSS Object Model Spec.

Flags

Some variables behave like flags. You could also use custom data-* attributes or CSS classes to manage the following ones. See the “Quickstart” doc for customization.

By default, those flags are not set. Then their initialization depends on your user settings’ management e.g. apply user settings to all EPUBs, only the ones that have already been customized, etc.

User view

Allows to switch between paged and scroll view.

--USER__view

Supported values: readium-paged-on | readium-scroll-on

Override class: Chrome (should be applied by any means necessary)

If the flag is not set, ReadiumCSS will fall back to the paged view.

Font Family override

Acts as an explicit switch to override the publisher’s font-family.

--USER__fontOverride

Supported value: readium-font-on

Override class: None. This flag is required to change the font-family user setting.

To switch back to the publisher’s font, you can either set an empty string as a value or remove the property.

Advanced Settings

Acts as an explicit switch to override the publisher’s styles.

If you provide users with a “Publisher’s styles” toggle, it must be enabled and disabled accordingly.

--USER__advancedSettings

Supported value: readium-advanced-on

Override class: None. This flag is required to apply the font-family, the font-size and/or advanced user settings.

To switch back to the publisher’s styles, you can either set an empty string as a value or remove the property. This will disable all advanced settings requiring the flag.

Reading Modes

We currently have two reading modes for night and sepia.

--USER__appearance

Supported values: readium-day-on | readium-sepia-on | readium-night-on

Override class: Chrome (should be applied by any means necessary)

If the flag is not set, ReadiumCSS will fall back to the day mode.

Filters

Please note night mode provides two extra specific variables:

--USER__darkenFilter

Supported value: readium-darken-on

Override class: Chrome advanced (optional but should be applied by any means necessary if provided to users)

To disable the filter, you can either set an empty string as a value or remove the property.

--USER__invertFilter

Supported value: readium-invert-on

Override class: Chrome advanced (optional but should be applied by any means necessary if provided to users)

To disable the filter, you can either set an empty string as a value or remove the property.

Accessibility Normalization

Users may want to normalize text (no bold, no italics, etc.) for accessibility reasons, using a non a11y-specific typeface.

--USER__a11yNormalize

Supported value: readium-a11y-on

Required flag: --USER__fontOverride: readium-font-on

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

To disable the normalization, you can either set an empty string as a value or remove the property.

Hiding Ruby Text

Users may want to hide ruby annotations for accessibility reasons.

--USER__no-ruby

Supported value: readium-noRuby-on

Required flag: --USER__advancedSettings: readium-advanced-on

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

To disable the hiding and show ruby annotations, you can either set an empty string as a value of remove the property.

List of variables

Layout

The user can set the number of columns and page margins.

Number of columns

--USER__colCount

Possible values: 1 | 2 | auto (default)

Required flag: none

Override class: Chrome advanced (optional but should be applied by any means necessary if provided to users)

To reset, change the value to auto.

By default, this setting behaves as an auto value, it will switch to 1 or 2 columns depending on the minimum width available and font-size.

It is up to implementers to decide whether they want this setting to be available and override any configuration or only some (e.g. setting only available in landscape and/or larger screens).

Page margins

--USER__pageMargins

Recommended values: a range from 0.5 to 2. Increments are left to implementers’ judgment.

Required flag: none

Override class: Chrome advanced (optional but should be applied by any means necessary if provided to users)

To reset, change the value to 1.

The user margins are a factor of the reference we set.

This will probably be fine-tuned in the next version (beta).

Themes (background and text colors)

The user can set a background-color and color.

The following two variables must be used together.

--USER__backgroundColor --USER__textColor

Possible values: Color HEX (e.g. #FFFFFF), rgb(a), hsl.

Required flag: none

Override class: Chrome advanced (optional but should be applied by any means necessary if provided to users)

To reset, remove both variables.

Hyphenation and justification

The user can set text-align and hyphens for body copy contents.

Text align

--USER__textAlign

Possible values: left (LTR) or right (RTL) | start (logical property resolving to left in LTR, right in RTL) | justify

Required flag: --USER__advancedSettings: readium-advanced-on

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

Note: the value start can be used to let all rendering engines, excepted Trident (IE11) and EdgeHTML (Edge), automatically deal with left and right based on the direction (dir attribute) set for the document and its nested elements.

Hyphens

--USER__bodyHyphens

Possible Values: auto | none

Required flag: --USER__advancedSettings: readium-advanced-on

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

Warning: for the time being, automatic hyphenation won’t work if you are using the Blink rendering engine (either via Chrome or a Webview, including Electron’s) on ChromeOS, Linux and Windows. It indeed is not implemented yet and we recommend not trying to polyfill it using JavaScript as it will create a11y issues, especially with screen readers.

As a consequence, we strongly advise implementers against providing users with an hyphenation-specific setting if targeting this rendering engine.

Typography

The user can set font-family, font-size and line-height for body copy contents.

Font family

--USER__fontFamily

Possible values: var(--RS__oldStyleTf) | var(--RS__modernTf) | var(--RS__sansTf) | var(--RS__humanistTf) | <string>

For Japanese, possible values become: var(--RS__serif-ja) (horizontal writing) | var(--RS__sans-serif-ja) (horizontal writing) | var(--RS__serif-ja-v) (vertical writing) | var(--RS__sans-serif-ja-v) (vertical writing) | <string>

Required flag: --USER__fontOverride: readium-font-on

Override class: User settings (should be applied by any means necessary)

To reset, remove the required flag.

Font size

We have to normalize font-size for body copy elements so that it can work in pure CSS. In order to do so, we are using a normalize. The --USER__advancedSettings: readium-advanced-on inline style must be set for html in order for the font-size setting to work.

Although it might be an issue to authors at first sight, this approach is backed by actual data.

--USER__fontSize

Recommended values: a range from 75% to 250%. Increments are left to implementers’ judgment.

Required flag: --USER__advancedSettings: readium-advanced-on

Override class: User settings (should be applied by any means necessary)

Type scale

If the --USER__advancedSettings: readium-advanced-on style is set for html, you can customize the font-size of all elements using a factor. This may come in handy on mobile devices, if the user sets a large font-size.

--USER__typeScale

Possible values: 1 | 1.067 | 1.125 | 1.2 (suggested default) | 1.25 | 1.333 | 1.414 | 1.5 | 1.618

Required flag: --USER__advancedSettings: readium-advanced-on

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

You can use different type scale values depending on the font-size. For instance, if the user sets a large one, you might want to decrease the type scale so that headings are not super large.

Line height

--USER__lineHeight

Recommended values: a range from 1 to 2. Increments are left to implementers’ judgment.

Required flag: --USER__advancedSettings: readium-advanced-on

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

Paragraphs’ formatting

The user can set margin-top, margin-bottom and text-indent for paragraphs.

Paragraphs’ spacing

--USER__paraSpacing

Recommended values: a range from 0 to 2rem. Increments are left to implementers’ judgment.

Required flag: --USER__advancedSettings: readium-advanced-on

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

Paragraphs’ indent

--USER__paraIndent

Recommended values: a range from 0 to 3rem. Increments are left to implementers’ judgment.

Required flag: --USER__advancedSettings: readium-advanced-on

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

Characters’ spacing

The user can set word-spacing and letter-spacing for headings and body copy contents.

Word spacing

--USER__wordSpacing

Recommended values: a range from 0 to 1rem. Increments are left to implementers’ judgment.

Required flag: --USER__advancedSettings: readium-advanced-on

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

Letter spacing

--USER__letterSpacing

Recommended values: a range from 0 to 0.5rem. Increments are left to implementers’ judgment.

Required flag: --USER__advancedSettings: readium-advanced-on

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

Arabic Ligatures

--USER__ligatures

Possible values: none | common-ligatures

Required flag: --USER__advancedSettings: readium-advanced-on

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

Themes

In this model, themes are just a set of user variables with specific values.

It becomes even easier to override them for the user as the values are already user settings.

In other words, think of preset and custom themes as a set of variables, which makes it easier to create, manipulate and cache them.

Alternative options

There is not a lot of alternatives when it comes to managing user settings. Options include:

appending/removing stylesheets (either link or style element) dynamically;

traversing the DOM and appending inline styles using JavaScript;

using classes or custom attributes for a limited subset of settings (e.g. reading modes);

leveraging native features web views have to offer.

Please bear in mind Readium CSS provides a baseline, it resonably manages all those issues using CSS only. But if you want to offer users the most advanced experience there can be, you’ll end up with a mix of all those options.

For instance, you can’t really manage text-align perfectly if you don’t traverse the DOM to find elements for which the user setting should not apply, CSS has no way to retrieve those elements.

It is worth mentioning that at least some rendering engines are optimized to manage global CSS variables (i.e. the ones declared in :root) and reserve a special cache for faster lookup and updates. Changes should consequently be handled as inline styles in the html element if you want the best performance possible.

User settings can be language-specific

It is important to note that the list of user settings you may provide users with can change depending on the primary language of the publication.

Indeed, it doesn’t make sense to have some user settings in some languages, and they would do more harm than good e.g. hyphens in CJK. Ideally, those settings should therefore be removed from the UI, or at least disabled, if needed.

All languages other than Latin

Implementers will need to load different list of fonts based on the languages listed in Default Fonts.

The most complex issue is finding fonts for those languages, especially as mobile systems often ship with the minimum amount of fonts possible to support Indic, Arabic, Hebrew, CJK, etc. And when the platform provides an extended selection, users often have to download them beforehand.

The following is provided as guidance only:

the app should at least offer the publisher’s font and the default (var(--RS__baseFontFamily)) for the language – which should work automatically if the correct language is set for each document;

if implementers want to extend the list:

use pre-installed fonts if the system offers some;

use downloadable fonts if the system offers some;

carefully pick fonts supporting the language and the idiosyncrasies of its typography;

fall back to Google Noto Fonts.

users probably have fonts already installed, re-use those fonts if possible (advanced setting in which they can access or declare those fonts).

Right to left scripts

User settings to disable are:

--USER__bodyHyphens;

--USER__wordSpacing;

--USER__letterSpacing.

User settings to add are:

--USER__ligatures.

CJK

For Chinese, Japanese, and Korean, implementers must manage both horizontal and vertical writing modes, since the pagination model differs.

Horizontal writing mode

User settings to disable are:

--USER__textAlign;

--USER__bodyHyphens;

--USER__paraIndent;

--USER__wordSpacing.

User settings to add are:

--USER__noRuby.

Finally, --USER__letterSpacing should be treated as an exception. We are aware it can be useful in Japanese, but don’t know what the situation is as regards Chinese and Korean. It’s up to implementers to decide whether it should be enabled or disabled for each of these languages.

Vertical writing mode

This also impacts the Mongolian script.

User settings to disable are:

--USER__colCount;

--USER__textAlign;

--USER__bodyHyphens;

--USER__paraIndent;

--USER__wordSpacing.

User settings to add are:

--USER__noRuby.

Finally, --USER__letterSpacing should be treated as an exception. We are aware it can be useful in Japanese, but don’t know what the situation is as regards Chinese and Korean. It’s up to implementers to decide whether it should be enabled or disabled for each of these languages.

Baseline for a11y-related user settings

[Implementers’ doc] [Authors’ info]

Our current baseline for user settings includes:

night/sepia modes, and custom background-color and color;

text-align and hyphens;

font-size and line-height;

a11y-related typefaces;

letter- and word-spacing;

removing italics, subscrips and superscripts, and drop caps.

We should probably consider additional options:

forcing an outline for focused elements;

unfloating elements;

removing images.

Please note some or all of those settings may be added in Readium CSS at some point.

A few notes:

The a11y-related typefaces are not necessarily typefaces which were specifically designed for a11y. A typeface a reader is used to, like Verdana, Trebuchet, etc., can be a11y-related as well. From research, the more varied typefaces available, the better. There is no silver bullet there, some people don’t like Open Dyslexic for instance, and prefer sans-serif typefaces they are used to.

Removing italics, subs and sups, drop caps and floated elements should probably be automatic if the typeface or theme selected was explicitly designed for dyslexia. Additionnaly, the --USER__a11yNormalize: readium-a11y-on flag is available and bring this feature to other typefaces.

OS settings

Some Operating Systems provide users with global settings. We must take those settings into account, which is the purpose of the “OS a11y” module. This module still needs some improvements.

We’ll have to make decisions about reading modes there: if the user sets the monochrome option, how are we supposed to deal with sepia and colors? If the user sets an inverted high-contrast mode, what happens in night mode? There can indeed be multiple users for the same computer, using the same account, and we should cover this case out of the box.

Current a11y Features on the market

There are features you might want to add to your Reading System so that it can cover the needs of all readers.

Readium CSS can help but can’t manage all of those features. Indeed, CSS might fall short of your expectations, especially on reliability. In other words, CSS is not necessarily the best way to manage features which could be considered in its scope at first sight.

As a rule, CSS can be used for styling (colors, highlights, etc.) but can’t be used to target contents (text nodes) directly. As a consequence, you’ll need to add hooks in the DOM (extra markup, classes, attributes, etc.) for some features.

Dyslexia

Luc Maumet (EDRLab) has conducted an analysis on the features available in dedicated software. Here are the features Readium CSS can manage and those it can’t.

Features in Readium CSS Scope

Create and personalize a profile (customizable theme which can be saved and retrieved)

Add space between words

Add space between letters

Change the typeface

Offer a dyslexia typeface

Change the font-size

Improve line-height

Features outscoping Readium CSS

Alternate colors for words

Alternate colors for lines

Highlight a specific letter

Highlight uppercase letters

Highlight punctuation

Highlight syllabes

Highlight consonants and vowels with different colors

Text to Speech

Highlight a specific sound in the text

Export contents with the customized layout

Vestibular disorders

There’s an a11y “issue” which is quite unknown, but may impact a lot of people, either temporarily or permanently: vestibular disorders.

To put it simply, some interactions can make the user dizzy, uneasy, and in some cases ruin her/his entire day, because the user feels like they can’t keep balance when walking or even staying up, or feel vertigo. See this article for further details and illustrations.

At the very minimum, allow the user to disable animations which may create effects (e.g. page-transition animation). But everything else will vary from implementation to implementation.

On iOS/Mac, there’s a system setting which has been implemented and browsers increasingly support the prefers-reduced-motion media query to design accordingly.

There’s little we can do about interactive EPUB contents themselves, but we can at least promote what Mozilla got wonderfully right from the start to authors, i.e. an overlay asking users to set their preference.

Internationalization

Very little information on a11y is currently available in the W3C Text Layout and Typography Requirements.

All we know at the moment is that, in the Arabic and Farsi scripts, disabling ligatures might help for dyslexia.

Recommendations for User Settings Management

[Implementers’ doc] [Authors’ doc]

User settings are a complex issue as CSS authoring is liberal by nature.

In theory, this issue should be easily solvable using UA and user stylesheets as they turn precedence upside down for !important. In practice, we don’t have any universal mechanism to set a stylesheet as an UA or user stylesheet: all the stylesheets we manipulate are created equal in scope; they are considered authors’ stylesheets by the rendering engine.

The following list is the order of priority we should emulate:

important user agent declarations;

important user declarations;

important author declarations;

normal author declarations;

normal user declarations;

normal user agent declarations.

Managing conflicts

We’re referring to the W3C’s priority of constituencies. In other words:

Users’ styles > Authors’ styles > Implementers’ styles

Which is why conceptualizing this issue as intents may help.

Typography is not just a set of settings though, it’s a complex system in which some settings impact others. For instance, font-size impacts line-height and line-length, which impacts the number of columns.

It is up to implementers to pick their preferred approach (minimal set, presets, minimal set/presets with advanced settings, maximal set) since it is primarily an UX issue.

!important

User’s intent

Does not apply as we basically manage important declarations for them.

Author’s intent

In theory, using !important is a clear intent the author is willing to enforce some specific style.

What do do

In practice, !important may be abused, it may be a quick fix to solve a cascading issue – and the author didn’t bother taking user settings into account –, it may be used to enforce some styles in Reading Systems overridding a lot of styles by default, etc.

This case is a complex one. We’re designing Readium CSS with the minimum amount of overrides possible but authors’ !important may conflict with some user settings. Please refer to the following cases.

Number of columns

User’s intent

The user intends to set a personnal preference. They may be used to reading newspapers, where the column length is quite small, but that can create extra issues on the implementers’ side.

Author’s intent

Does not apply to authors.

What to do

It depends on the implementers’ approach (presets with typographic rules as references Vs. the user can override on a setting-by-setting basis).

Page margins

User’s intent

The user intends to adjust line-length.

Author’s intent

We have to override margins for pagination so the most important style is max-width, if set.

What to do

The author intends to limit line-length, but it is unclear they are doing it because some Reading Systems don’t or because they want to enforce one specific (max) line-length.

Reading modes

User’s intent

The user intends to improve visual comfort.

Author’s intent

Does not apply to authors but it could if we create a public “API” for authors to express intents related to reading modes.

Since authors have filed very few use cases at the moment, this is highly conditional.

What to do

Implementers should take two main variables into account: contrast and luminosity, which means they might want to invert some images or get rid of backgrounds in night mode.

Inverting images that should be inverted in night mode can’t be done well without an author’s intent though.

Please note Readium CSS provides two extra options to manage images in night mode:

darken;

invert.

Those are two opt-in mechanisms for users, ideally set on a book-by-book basis since they may work well with some publications but badly with others.

Font family (typeface)

User’s intent

The user intends to at least override the typeface used for body copy.

For a11y-related typefaces (Open Dyslexic, bold style of sans-serif family), the user probably intends to replace headings, scripts and italics as well.

Author’s intent

Declaring a font-family for body, p and p.class is so common that it should not be considered an intent per se. While p.class is debatable, it is so widespread in practice (some authoring tools output font-family for every paragraph style) that it can’t be considered an intent in pure CSS. Implementers indeed have to validate it against the document’s font-family using JavaScript to make sure it shouldn’t be overridden.

A different font-family can be set for headings (h1, h2, h3, etc.), blockquote, i, span, etc.

What to do

A different font-family for specific elements should be considered a proper intent: a font may indeed be used to make the structure clearer, achieve visual effects (e.g. manuscript letter) or make sure different languages are displayed correctly.

For a11y-related settings (e.g. Open Dyslexic), you should override those elements too, as not doing it will impact the reading experience negatively. Please make sure to provide a font-stack that covers a large amount of different languages though.

In any case, math and SVG contents should not be overridden.

Font size

User’s intent

The user intends to adjust the font-size, either because it is too small or too large by default.

Author’s intent

This may be considered an intent if a font-family is set for body copy.

What do do

The author could be trying to compensate for a smaller or larger x-height.

You might want to normalize font-size (à la iBooks) if the user changes the typeface.

Line height (leading)

User’s intent

The user intends to adjust line height, either because it is too solid or too loose by default.

Author’s intent

The author may be trying to enforce vertical rhythm but you really can’t tell if you don’t analyze the entire stylesheet.

What do do

Common elements for the body copy should be overridden (paragraphs, lists…).

Text align (justification)

User’s intent

The user intends to set a personnal preference. Although it is a bad practice in typography, some may prefer justified text without hyphenation.

Author’s intent

If set for body copy, this is a publisher’s or author’s preference.

If explicitly set to right and center for paragraphs, to which left is added for headings, it is a clear intent.

What do do

Clear intents should not be overridden. This requires JavaScript though, and it could be easier to manage exceptions than all the elements which must be overridden (less DOM manipulation).

Elements such as headings, tables, pre, etc. should not be overridden: declaring text-align: justify for those elements would indeed degrade legibility.

Hyphenation

User’s intent

The user intends to enable/disable justification, possibly depending on the default/author’s styles.

Author’s intent

Since hyphenation works in combination with justification in proper typography, this should be considered a preference or the enforcement of a typographic rule.

What to do

Typography-wise, it is OK to hyphenate body copy with text-align: left, it is critical to hyphenate body copy with text-align: justify.

We are taking care of elements which should not be hyphenated in the patch stylesheet so that you don’t have to.

Paragraphs’ formatting

User’s intent

The user intends to change the paragraph styling i.e. text-indent and vertical margins. Problem is this can either be a preference or a specific need (e.g. dyslexia).

Author’s intent

This is a publisher’s or author’s preference.

There indeed is two accepted options for styling paragraphs:

vertical margins without indent;

indent without vertical margins.

What to do

Ideally, paragraphs’ formatting should be handled as a whole. There is nothing preventing implementers to provide users with both settings though.

Characters’ spacing

User’s intent

The user intents to customize word-spacing and/or letter-spacing, which can help for dyslexia for instance.

Author’s intent

It is very rare authors’ will use those CSS properties for body copy. They may use it for headings though (small capitals, large font-size, etc.).

What to do

In any case, implementers should force those settings for body copy.

Ligatures (Arabic & Persian scripts)

User’s intent

The user intends to disable ligatures. This setting applies to the Arabic and Persian scripts, and is believed to help dyslexic readers as word-spacing in Latin.

Author’s intent

In those scripts, ligatures will be enabled by default. It’s neither an intent or preference, it is just the way it works.

What to do

Implementers must enforce the user preference, as it is primarily related to a11y.

User preferences’ insights

[Implementers’ info] [Authors’ info] [WIP]

In case you don’t have solid data related to user preferences, here is some information to help you kickstart your UX.

It is worth noting this should not be considered a guide, this is just a list of interesting observations, notes and remarks. UX research is critical and there’s not a lot available for ebooks so far, so you’ll have to do it yourself to see what works and what doesn’t.

This is really tricky as there may be a cultural factor to take into account. In our research, results varied significantly from one market to another. Unfortunately, it is impossible to tell how important this cultural factor is compared to others. In other words, if you’re going global, it might be interesting to do some specific research on this.

User Settings

When asked directly, the vast majority of users will say they prefer basic settings (reading modes, typeface, and font size) over other options (maximum amount of settings possible, themes, customizable themes). Customizable themes and advanced settings are equally popular, at a distant second place.

Once again, this is a complex UX issue and your mileage may vary. On Android for instance, there is a lot of apps with advanced settings as the default, and millions of people are using them daily. So it’s primarily about your UX proposal, people using it, etc.

Hopefully, Readium CSS was designed to take all those options into account: modules are take or leave, which implies you can build any UX from them.

Typography

We’ve been running forms on this topic but answers can’t be taken at face value since they might well be biased – given the eprdctn and a11y communities on social networks, and the probable tech-savyness of people who came across those forms in the first place; what is the most interesting is the open-ended questions and how you can interpret them.

People change the publisher’s typeface

People keeping the publisher’s typeface are in the minority (< 15%). Most users at least change the typeface occasionally (see reasons below), although they don’t necessarily do it for each ebook – some ebooks simply use the default typeface so it’s quite complex to measure.

What’s important is that you’d better have some kind of bulletproof selection of RS typefaces. “Bulletproof” is the keyword here, since it is difficult to imagine a selection that will satisfy everybody. There won’t be any silver bullet.

Since more people systematically change the publisher’s typeface than those who never do it, implementers might end up with a huge share of users systematically changing the typeface and could adjust the UX accordingly (global setting applying the typeface in all books).

It also implies you’d better have fonts providing with the largest characters set possible.

Why do people change the typeface?

Legibility. We’re including dyslexia typefaces since it is kind of related to this issue.

In some way, this justifies we must change the typeface for (at least) body copy by any means necessary – and absolutely everything for dys.

As an aside, respondents didn’t hesitate to criticize the publisher/graphic designer when they feel they made an abysmal choice of typeface(s). Please pick the typefaces you want to provide carefully. There can be language subtleties to take into account, and pairs, ligatures, kerning, etc. might have been done well for one latin language but not other latin languages for instance – especially when those other languages are using diacritics.

Other reasons were given, the most interesting ones being:

trying new fonts for fun: maybe you can find some way to leverage the fun factor, by implementing a little game to teach typography fundamentals or something like this, it is usually a good idea to leverage the fun factor since it will put the user in a super good mood (UX);

mood i.e. some pick a typeface that fits the mood of the publication;

on the one hand, consistency i.e. all ebooks have the same typeface;

on the other hand, breaking the monotony i.e. changing the typeface for each book.

Typefaces that should be included in a reading app

Users can be gathered in diverse categories.

The Minimalists

They don’t want an awful lot of fonts, they want the best option possible for serif and sans-serif, which means typefaces of outstanding quality (good legibility, perfect kerning, OpenType Features, etc.).

The Defaulters

Arial, Georgia, Verdana, Calibri, Times (New Roman), Segoe UI…

In other words, the fonts they find and use in MS Word.

On a related note, The defaults for Kindle (Bookerly) and Play Books (Literata) have become pretty popular. It is worth noting these custom fonts were commissioned, and it could be an alternative if you can afford it.

The eInkers

Basically, you’re given a list of typefaces you can find on a Kobo, Pocketbook or Kindle. This might primarily impact some companies doing both eInk Readers and apps but there could well be a possibility to make the user feel “at home” there, by having a few of those typefaces as well.

The Slabs

Cæcilia seems to be one of the must-haves, and it’s a slab serif, so you might want to at least provide one in this category or even a lookalike.

The Librists

Those ones are more interested in libre/open source fonts you can find at Google Fonts, Font Squirrel, Github, SIL, etc. More on that later.

Answers include Merriweather, Bitter (slab), Vollkorn, Gentium, Ubuntu, Lato, etc.

The A11ys

Unsurprisingly, you’ll need a11y-related fonts: Open Dyslexic is a popular one, but other fonts cited in dyslexia guidelines are mentioned as well (Verdana, Trebuchet, Comic Sans, etc.).

The Printers

Some people would like to have typefaces like Garamond, Bembo, Baskerville, Times New Roman, etc. Some respondents explained that they wanted the ebook to be more like a print book.

It is important to note that their screen rendering can be utterly terrible (cf. what Steve Matteson has to say about Times New Roman on screen). A lot has changed in designing typefaces for the screen since they were digitized and reworked versions may be available.

The Full Metal Typographers

To sum things up, they want all the fonts the platform has to offer, which means all system and locally-installed fonts.

With the advancement of Open Type Features, some issues may arise though: stylesets are unreliable, all fonts don’t manage features the same way e.g. subs, sups, ordinal, or diagonal-fraction, etc. This applies anyways, but could become especially complex if the user can access all the fonts available on the platform.

A few remarks there:

if you’re reading between the lines, you’ll see people list typefaces they’re used to – this is kind of obvious in Literata/Bookerly –, so you’d better focus on their category, traits and personality, which implies lookalikes/alternatives could do as well;

if you want to meet the Printers’ demand, you should check the modern versions of those fonts first, as they have been fine-tuned for screen rendering and can offer a lot more legibility (cf. Linotype’s eText collection);

you could bet on a flagship typeface like Amazon & Google but that’s a huge investment (custom typeface);

you’d better be cautious about OTF as soon as possible since the user may find itself with some weird results: letters and numbers as ordinal, decorative glyphs replacing the latin alphabet as the typeface designer used stylesets for this, etc.

Installing extra fonts

It actually is a thing.

Once again, there may be a huge bias there (tech-savvy users), but we were surprised to find out that not only respondents would be willing to install extra fonts, quite a significant number is already doing it. Think of users installing fonts on their eReaders for instance.

However, that opens the possibility to manage/install extra fonts. The major source of custom fonts seems to be Google Fonts for respondents but others go the extra mile and install licensed fonts locally, in which case they might want access to all the fonts installed on the system.

You’d better be cautious about Google Fonts as they are often a few versions behind, and the typeface designer could have added support for extra languages, OpenType Features, etc.

This obviously is a feature requiring some extra work, and some platforms may impose limitations, so it should just be considered an interesting piece of information.

An important note: some users had to install a font for a11y purposes (e.g. dyslexia) so it’s important you meet this requirement out of the box so that they don’t have to take that extra step.

Internationalization

[Implementers’ doc] [Authors’ doc] [WIP]

The aim of this document is to provide implementers with a baseline for internationalization.

The current situation

Internationalization is an ongoing process, with browsers offering subpar interoperability (typography, writing modes, etc.), Operating Systems sometimes lacking fonts for some languages, and documentation providing little information on topics of interest to Reading Systems (a11y, settings, etc.).

This could well explain why the most popular Reading Apps tend to implement the least common denominator for all languages, especially when it comes to user settings, and to not support more complex languages implementers either know they can’t support well or are used on smaller markets the app/service is not targeting.

Occasionally, when an app does support a language, it can put some constraints on authors, as there is no other way to make sure the publication will be handled well otherwise e.g. specifying the Hans or Hant script for Chinese (zh).

We can’t overemphasize the importance of the internationalization process though, as the 24 languages we added extend support to 3,049,150,507 speakers, from the 1,150 people speaking Western Canadian Inuktitut, to the 1,200,000,000 speaking Chinese. Implementing right to left scripts will extend support to 411,000,000 native speakers, while vertical writing to at least 130,200,000 – excluding Chinese and Korean.

In total, we can cover the needs of 5,262,900,507 speakers. Credit where credit is due, this wouldn’t have been possible if Operating Systems and browsers didn’t tackle this process upstream, added fonts for those languages and improved support in rendering engines.

Resources

W3C Internationalization Working Group Home Page

Creating HTML Pages in Arabic, Hebrew and Other Right-to-left Scripts (tutorial)

Styling vertical Chinese, Japanese, Korean and Mongolian text

International text layout and typography index

Requirements for Japanese Text Layout

Requirements for Chinese Text Layout

Requirements for Hangul Text Layout

Requirements for the Arabic Script

Requirements for Hebrew Text Layout

Requirements for Indic Text Layout

EBPAJ File creation guide

What implementers need

Supporting the maximum amount of languages and scripts is a complex process.

As a consequence, work for internationalization should be tackled early, as the changes and adaptations needed will have a significant impact on an existing implementation. It indeed impacts the entire implementation, and not only CSS.

Retrieving the significant information in the OPF

Implementers will need a way to retrieve page-progression-direction and the primary language (<dc:language>) of the publication.

Page-progression-direction

This attribute is set on the <spine> item, and the value rtl should be considered important information for the whole process.

This value signals the publication is either an RTL script, or is using the vertical-rl writing mode, which is the reason why we must find the primary language of the publication next.

The value is important to store, as it will be the one used for the dir attribute to append if it is missing in a document.

Primary Language

It is very important to note the primary language must be checked in all cases, and not only when the page-progression-direction is set or has an rtl value.

Indeed, this piece will be even more critical in the following steps, as it will trigger the list of fonts to load for the publication, the user settings to provide, and the xml:lang attribute to append if it is missing in a document.

Possible issues

The OPF file should not be considered a single source of truth for the publication, since issues may arise relatively quickly. We can’t call the process “heuristics” per se, it’s more of a chain of educated guesses.

Multiple language items

There exists an increasing corpus of EPUB files with multiple <dc:language> items. Some authoring tools, for instance, list all languages a publication contains.

In this case, page-progression-direction should serve as a hint, if present. For instance:

the first <dc:language> item is English;

the second <dc:language> item is Japanese;

the page-progression-direction is rtl;

the primary language is Japanese.

Obviously, this can quickly become an issue if both languages share the same page-progression-direction…

the first <dc:language> item is English;

the second <dc:language> item is Japanese;

the page-progression-direction is missing;

we can’t guess the primary language from the OPF.

In such an edge case, to achieve the best interoperability possible, the first <dc:language> element must be considered the primary language, unless you can pre-process all documents in a publication to determine it beforehand.

Missing page-progression-direction

For some reason the page-progression-direction may be missing in the OPF, which can be true if the publication is EPUB2 for instance – which supports the direction CSS property and, in theory, could support RTL scripts.

The following guidance is informal:

if the page-progression-direction is missing;

if there is only one <dc:language> item which clearly signals the page-progression-direction:

ar, fa, and he;

zh-Hant, or zh-TW.

then you can assume the page-progression-direction is rtl.

The decision to handle this edge case is up to each implementer, especially as it can be considered a patch of an authoring failure.

Triggering the correct page-progression-direction

Once the page-progression-direction is defined as rtl, it must be reversed in the app:

the previous resource (document) is on the right;

the next resource (document) is on the left.

Navigating the publication should follow this pattern.

Appending information into documents

Missing attributes in each document is far from an uncommon or edge case.

Since the page-progression-direction or <dc:language> are already set in the OPF, some authors might think they will automatically apply to all the resources in the EPUB file, and explicitly set it only when it differs from those global values. More importantly, some Reading Apps are automatically managing this, and should authors only check their files in those apps, it could lead them to believe it just works.

Language

The language is important as it will enable hyphenation and use the proper rules specific to each language if a dictionnary is available, change the default typeface for some languages, and even apply language-specific styles for layout (e.g. pagination, defaults for unstyled publications, etc.).

The following process must be implemented:

if xml:lang can’t be found on html;

check if xml:lang can be found on body, copy and set it to html, and stop there if it is;

if it can’t be found on body, use the primary language retrieved from the OPF file and set it to html and body.

Direction

The dir attribute is critical too, as it will reverse the column direction for RTL scripts.

The following must only apply if the primary language is ar, fa, and he. It MUST NOT apply to CJK.

The following process must be implemented:

if the dir attribute can’t be found on html;

check if dir can be found on body:

if it is the same value as the one retrieved from the OPF file, copy it;

if it differs from the one retrieved from the OPF file, change the value;

set the dir attribute with the correct value on html.

Loading the correct styles

Readium CSS provides implementers with specific stylesheets for RTL scripts and CJK (including the Mongolian script), those styles must be loaded accordingly. Otherwise, styles for LTR scripts in the horizontal writing mode will apply.

Guidance can be found in the Injection and Pagination document.

Modifying the UI of the app

Ideally, several parts of the app should be customizable depending on the publication. Another option is implementing the least common denominator for all languages.

All Languages

The list of fonts the app offers to users should be specific to the primary language of the publication, and writing-mode if it applies – Japanese currently.

This means fonts for Latin language can’t be reused for Indic, RTL scripts, CJK, etc.

RTL

Several parts of the UI must follow the direction (rtl) of the primary language:

the running header (title of the publication or chapter);

the toc and its entries;

user settings e.g. text align;

implementers might want to localize the interface based on the language set at the system level, or at least fall back to English.

Moreover, some user settings should be removed if used (letter- and word-spacing) and another one added (arabic ligatures in ar and fa).

CJK

Although the UI can keep an ltr direction with a horizontal-tb writing mode, some extra attention should be paid:

make sure the “UI font” can display the characters needed in those languages;

implementers might want to allow authors to set a vertical-* writing mode for the navigation document (nav.xhtml);

implementers might want to localize the interface based on the language set at the system level, or at least fall back to English.

Moreover, some user settings should be removed if used (text-align, hyphens, letter- and word-spacing, number of columns in vertical writing, etc.). See User Prefs for further details.

Internationalize features

Implementers should make sure features like search, highlighting, etc. can work well with bidirectional text and unicode – CJK, especially as some characters change from horizontal to vertical writing modes.

Another issue to take into account is that input methods might not allow users to use some features easily, in which case extended research should be made to check realistic options.

Fonts

Implementers should make sure they offer at least two options: the publisher’s font and the default. If they want to extend the list of fonts they provide for some languages, they should follow guidance in the User Preferences doc.

How authors can help

Authors can help in different ways, from authoring files to giving valuable information we can use to improve the entire Readium CSS project.

Authoring

In some cases, EPUB files themselves will help us improve support tremendously.

The metadata in the OPF file will help us trigger the expected behavior. For instance:

declaring only one <dc:language> will help us determine the primary language of the publication;

if this is not possible, add the primary language as the first <dc:language> item in the OPF;

declaring the script e.g. zh-Hant or mn-Mong will help us trigger the correct writing-mode;

using the EBPAJ guide meta will help us improve support across platforms.

Setting attributes in each document of the publication will also help us make educated choices and could eventually allow us to handle some edge cases like mixed directions or mixed writing modes. Our aim is obviously not to put the burden on authors there, but collaboration is the only solution to get around those edge cases the EPUB specification doesn’t discuss.

What you can do:

embed fonts when necessary, so that users have at least two options to choose from in settings and/or proper support of the language;

set the xml:lang attribute on html;

set the dir attribute on html;

avoid using the direction CSS property, as it is now recommended.

Reporting issues

First and foremost, please be assured that we’re as annoyed as you are if there is an issue. It doesn’t mean we don’t care, far from it… it just means we lacked information or misunderstood some requirements when designing Readium CSS. Our goal is to achieve the best support possible, and we know we can’t fulfill it without your expertise.

If you encounter any issue specific to a language or script, do not hesitate to open a new issue in the github repository. A reduced sample will definitely help. Check our guidelines for further details.

The most information we have, the better the fix will be. Please feel free to go into extensive details and provide links, documentation, examples, etc. we can check to get a solid grasp of the issue we have to fix.

Sending feedback

We’re not saying you should implement a support of script yourself if we don’t support it at all or very well, but it is noteworthy that we can’t necessarily get all the details right, especially when we don’t know how to speak and write the language you wish were supported or improved.

If our font-stacks are not good enough, a solider one will help. If we don’t have any font-stack for a language, a basic one will do. Additionally, you can point us to libre/open-source fonts which you think should be recommended to implementers.

If we’ve got something wrong in terms of typography, an example – picture, codepen demo, etc. – will help us see how we got there. Please bear in mind we might be limited by what web browsers can do though, and some issues could be consequently deemed “out of scope.” We will at least do our best to report the issue to whom it may concern whenever possible.

Check our contribution guidelines for further details.

Overarching issues

Implementers should be aware there are overarching issues for which we haven’t reached consensus, or couldn’t discuss yet.

The most important issue, by very far, is that checking the writing-mode at runtime can blow performance in extreme ways. It can indeed take 15 seconds to render some complex XHTML files in vertical-*. Needless to say, this would obviously be worse in terms of UX. And this is the reason why we try to guess the writing-mode from the OPF file.

Longer terms issues include:

polyfilling -epub-properties for web apps;

mixed directions (LTR document in a RTL publication) and mixed writing modes (horizontal-tb document in a vertical-rl publication);

support for alternate stylesheets, which is critical if the implementer wants to offer a horizontal/vertical-writing user setting;

support for rendition: align-x-center;

support for ibooks:respect-image-size-class (gaiji) and ibooks:scroll-axis metadata items (see EPUB Compat doc);

rendition: flow of scrolled-doc.

Out of scope

There are some typography and layout issues which are not the responsibility of apps’ implementers but rendering engines’. Those issues include:

line-adjustment and justification (RTL and CJK);

run-in headings (display: run-in), which is popular in CJK;

ruby and its styling;

bidi;

Kashida Elongation (Arabic);

joining forms (Arabic);

single-letter styling (Arabic).

If those issues arise, please report them to whom it may concern (e.g. Chromium, Firefox, Microsoft, Webkit, etc.). The entire web platform will indeed benefit. You can additionally report the issue to us so that we can document it for other implementers.

Glossary

Check the i18n Glossary doc for a glossary of terms you may encounter during bug reports, issues, or feedbacks.

Internationalization – A Typography Primer

[Implementers’ doc]

The aim of this document is to provide implementers with a typography baseline for internationalization.

Abstract

Various scripts and/or languages can vary from the typography rules implementers may be accustomed to in Latin. There are important idiosyncrasies to take into account, as it will impact the text layout of documents, base and default styles, and user settings.

The best way to keep up with best practices and requirements is the International text layout and typography index. In case of doubt, do not hesitate to check this index.

Fonts

In some scripts, it is common to use different fonts for headings or emphasis, rather than bolding or italicisation. For instance, Chinese, Japanese and Korean fonts almost always lack italic or oblique faces, because those are not native typographic traditions.

Proper italic glyphs in Cyrillic text can look very different from normal variants, so synthesising italics can produce poor results. This is the reason why implementers should make sure they provide an italic style for the Cyrillic fonts they are offering to users.

Special OpenType features may need to be supported, especially for the Arabic script, which needs ligatures.

Complex scripts have rules about how characters combine in syllabic structures, and scripts like Arabic may need controls to indicate where ligatures are wanted or not wanted. Authors may consequently use the zero-width joiner and zero-width non-joiner characters to force or disable ligatures, which can impact some features like search.

In CJK, fonts must support both horizontal and vertical writing modes, and extra attention must be paid as some characters will change depending on the writing mode of the document. It is for instance important to be able to convert between half-width and full-width presentation forms, and make sure the correct quotation marks are used – they are not the same depending on the writing mode.

Text decoration

Underlines need to be broken in special ways for some scripts, and the height of underlines, strike-through and overlines may vary depending on the script.

For vertical text the placement needs to be to the right or left of the line of text, rather than under or over.

Emphasis

Bold and italic are not always appropriate for expressing emphasis, and some scripts have their own unique ways of doing it.

In Japanese, a sans-serif font, or emphasis dots (horizontal writing) and sesame (vertical writing) may be used to express emphasis.

In the Amharic Script (Ethiopic), underlines, larger text or a different color may be used to express emphasis.

In Tibetan, marks and colors may be used to express emphasis.

Line breaking

In some scripts like Chinese and Japanese, text is set solid, which means there is no space between words. These scripts tend to break a line in the middle of a word (with no hyphenation) – even in Korean, which has spaces between words.

It would be strange to offer a word-spacing setting to users in those languages, and letter-spacing may create extra justification issues you won’t be able to resolve, for lack of more precise controls.

It is common for certain characters to be forbidden at the start or end of a line, but which characters these are, and what rules are applied when depends on the script or language. In some cases, such as Japanese, there may be different rules according to the type of content or the user's preference.

Hyphenation

Although CJK doesn’t use hyphenation, documents may contain other scripts which use hyphenation e.g. Latin in Japanese.

Justification

Typographic conventions for full text justification depend on the writing system, the content language, and the calligraphic style of the text. Some scripts have complex methods the rendering engine doesn’t necessarily support.

Kashida elongation is not supported for the Arabic script for instance (text-justify), but authors may be using the tatweel joining character (see i18n glossary doc) to elongate some words.

Chinese and Japanese are using inter-character justification for instance, while Latin uses inter-word.

Indents

In some scripts like CJK, indents are really important. Implementers should not try to provide users with such a setting, or apply a default designed for Latin.

Vertical text

Implementers must not try to provide a setting allowing users to switch from the vertical to horizontal writing mode, and vice versa, unless they support alternate stylesheets and the publication provides one for each mode. Indeed, characters, punctuation, emphasis marks, quotes, and so on and so forth, depend on the writing mode used, and an automatic switch would provide users with a subpar experience.

It's common for content authors to want to mix short horizontal runs of text, such as the tate-chu-yoko i.e. 2-digit numbers (text-combine-upright) or acronyms (text-orientation), in a vertical text.

Hanging punctuation at the end of lines can help improve justification for CJK in the vertical writing mode, but may be considered strange in the horizontal writing mode in some languages.

In Mongolian, it would be unexpected to have text written horizontal-tb if it is not using the Cyrillic script. The Mongolian script is indeed written vertical-lr and, unlike Chinese, Japanese, and Korean, can’t be written horizontal-tb.

Readium CSS Further Details: Explaining the CSS Voodoo

[Implementers’ doc]

Some parts of Readium CSS might feel like CSS voodoo at first sight. The goal of this document is to clarify how those parts actually work.

The Internal Framework

Readium CSS ships with a minimum viable framework to typeset unstyled publications (ReadiumCSS-default.css). Layout is managed by the “base” styles, used for all publications.

This stylesheet is based on HTML Suggested Rendering. Consequently, it will work if the markup is semantic.

If you’re familiar with CSS preprocessors (LESS, SASS, Stylus, etc.), you already know how to use it. It indeed relies on variables and functions, which are available in vanilla CSS today.

What’s noteworthy is that you can customize the entire publication by setting CSS variables (a.k.a. custom properties) and either use AS-IS at runtime or compile as a static representation before runtime (PostCSS config coming soon).

The stylesheet will then use those variables defined at the :root level.

Finally, a simplified version of the font-size normalize is embedded in this stylesheet (see next section).

Variables you can set

Typefaces

--RS__compFontFamily

The typeface for headings. The value can be another variable e.g. var(-RS__humanistTf).

--RS__codeFontFamily

The typeface for code snippets. The value can be another variable e.g. var(-RS__monospaceTf).

Typography

--RS__typeScale

The scale to be used for computing all elements’ font-size. Since those font sizes are computed dynamically, you can set a smaller type scale when the user sets one of the largest font sizes.

Possible values: 1 | 1.067 | 1.125 (suggested default) | 1.2 | 1.25 | 1.333 | 1.414 | 1.5 | 1.618

The suggested default will accomodate most configurations, from small to large screens. Please note it is different from the --USER__typeScale suggested default, which was designed to accomodate the publisher’s styles.

--RS__baseFontSize

The default font-size for body copy. It will serve as a reference for all related computations.

--RS__baseLineHeight

The default line-height for all elements.

Vertical rhythm

--RS__flowSpacing

The default vertical margins for HTML5 flow content e.g. pre, figure, blockquote, etc.

--RS__paraSpacing

The default vertical margins for paragraphs.

--RS__paraIndent

The default text-indent for paragraphs.

Hyperlinks

--RS__linkColor

The default color for hyperlinks.

--RS__visitedColor

The default color for visited hyperlinks.

Accentuation colors

--RS__primaryColor

An optional primary accentuation color you could use for headings or any other element of your choice.

--RS__secondaryColor

An optional secondary accentuation color you could use for any element of your choice.

Font Size Normalize and the Type Scale

The assumption is that at least basic semantic elements’ font-size can be interpolated to a type scale, with minimal variation (±1–2 pixels difference for each element) in comparison to authors’ styles.

We’re using the calc() function to emulate the following:

h1 = base font-size × typeScale ^ 3 (power of 3)
h2 = base font-size × typeScale ^ 2 (power of 2)
h3 = base font-size × typeScale
h4 = base font-size
body = base font-size

In which typeScale can be customized to match the actual scale used in the publication. There lies the flexibility of this normalize.

Getting the type scale is a one-two punch:

parseInt of the computed font-size for a heading and the base (division = result)*

Math.pow(result, 1/n), in which n is 3 for h1 (cubic root) and 2 for h2 (square root).

* h3 stops here.

Then the font-size for each heading and body copy element will be recomputed based on this type scale.

Of course this approach is limited, there is little we can do to account for ids, classes, etc.

But it can at least be used for themes, or an opt-in user setting.

Dynamic leading

Readium CSS automagically finds the ideal line-height of the current font and font-size in use if the author hasn’t set an explicit value.

We’re using the current algorithm in the calc() function:

(1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation))

Therefore, the line-height is:

1em = the size of the font-size;

2ex - 1ch = 2 x-height - 1 character width (0), in order to take the typeface’s proportions into account e.g. if the font has a small x-height, leading will be more solid, and vice versa;

1rem - 16px = the current user’s font-size minus the one at 100% (base font-size);

0.1667 = a scale which has been defined from an optimal range (it is a magic number which has been retro-engineered from a set containing hundreds of samples);

var(--RS__lineHeightCompensation) is a factor (integer) to compensate a less than ideal line-height, especially in non-Latin scripts, where fonts tend to be square-ish.

This isn’t a perfect solution though, and this algorithm may be revisited in the future. Indeed, caveats are:

leading also depends on line-length, which is not addressed in the algorithm itself, line-length must therefore be constrained by other means – we couldn’t rely on the viewport width anyway;

sometimes, the User Agent default font-size is not 16px (e.g. Kindle experimental browser, user setting a larger font-size, etc.);

0.1667 feels like a magic number, or at least a weird number as it was retrofitted after testing hundreds of typefaces;

it’s clearly a natural logarithmic function i.e. it increases rapidly and then slows towards a zero rate of change, which will give mediocre results for very large font sizes (e.g. 400%);

it doesn’t work ideally for slab serif fonts with a large x-height, thick stroke and medium character width i.e. square-ish metrics – we don’t have any in the default font-stacks so we had to introduce a compensation factor to address this particular issue.

Conditional Selectors for user settings

Use settings are appended on load and won’t have any effect until a user-setting variable is set.

In order to do that, we must use “conditional selectors.” Problem is there is no if/else statements in CSS so how do we achieve this?

:root[style*="--USER__variable"]

Attribute selectors with pseudo-regex.

As soon as you set a property and its required flag to the html (or root) element, the user setting applies.

Whenever needed, we’re leveraging explicit inheritance (inherit value) so that the :root value can be passed throughout the DOM.

We’re also relying on the :not() pseudo-class to exclude some elements. Think of it as the following command prompt: “make all elements in the DOM inherit the value, excepted this one and that one.”

Performance of those selectors should not necessarily be a major concern. Indeed, authors’ stylesheets (weight, complexity, etc.) and expensive properties will have a much larger impact on performance.

The biggest issue with this is that it requires some time to get accustomed to, as it objectively feels like some kind of CSS trick borderline to CSS voodoo. It has proved reliable during testing though, and already deals with user settings issues other Reading Systems might have had troubles addressing so far. In addition, it automagically forces the necessary recalc some user settings absolutely require.

Themes

In this design model, themes can be a simple set of user settings. They consequently can be treated as objects you can parse to add properties to the html (root) element, and stringify to save/cache if the user creates a custom theme. No extra stylesheet needed.

Readium CSS Variables API

[Implementers’ doc]

This document is meant to list all the customizable medias and flags (to be found in ReadiumCSS-config.css), as well as all the CSS variables for Reading System and User styles available in the dist stylesheets.

As a reminder, the priority is, in general:

USER > AUTHOR > RS

How to set and remove user preferences

Setting a user preference

var root = document.documentElement; root.style.setProperty("--USER__var", "value");

You don’t need to remove the variable before setting another value, the new value will simply override the existing one.

Removing a user preference

var root = document.documentElement; root.style.removeProperty("--USER__var");

Customizable medias

You will find those customizable medias in ReadiumCSS-config.css. The values defined are used in media queries to control use of the auto pagination model.

--responsive-columns

Default is 60em

The min-width at which the auto pagination model must be used – will switch from 1 to 2 columns and vice versa.

--min-device-columns

Default is 36em

The minimum device width of the mobile device for which the auto pagination model must be used.

--max-device-columns

Default is 47em

The maximum device width of the mobile device for which the auto pagination model must be used.

Warning: if you customize those medias, all ReadiumCSS dist stylesheets must be rebuilt.

Customizable flags

You will find those customizable flags in ReadiumCSS-config.css, and can think of the preset values as boolean inline styles: if they are set on the :root element (i.e. html) then the flag is enabled. If another value is, or they are removed, then the flag is disabled.

Those custom selectors can only be customized before runtime. You could for example use a class or a custom attribute instead of an inline style. Check the “User Settings” and “Quickstart” docs for further details.

Note: The preset is not a default implementers should use. Indeed, the initialization of those flags depends on your user settings’ management e.g. apply user settings to all EPUBs, only the ones that have already been customized, etc.

:--paged-view

Preset: --USER__view: readium-paged-on

Scope: html

Override class: Chrome (should be applied by any means necessary)

:--scroll-view

Preset: --USER__view: readium-scroll-on

Scope: html

Override class: Chrome (should be applied by any means necessary)

:--font-override

Preset: --USER__fontOverride: readium-font-on

Scope: html

Override class: None. This flag is required to change the font-family user setting.

:--advanced-settings

Preset: --USER__advancedSettings: readium-advanced-on

Scope: html

Override class: None. This flag is required to apply the font-family, the font-size and/or advanced user settings.

:--sepia-mode

Preset: --USER__appearance: readium-sepia-on

Scope: html

Override class: Chrome (should be applied by any means necessary)

This flag applies the sepia reading mode.

:--night-mode

Preset: --USER__appearance: readium-night-on

Scope: html

Override class: Chrome (should be applied by any means necessary)

This flag applies the night reading mode.

:--darken-filter

Preset: --USER__darkenImages: readium-darken-on

Scope: html

Override class: Chrome advanced (optional but should be applied by any means necessary if provided to users)

This will only apply in night mode to darken images and impact img.

:--invert-filter

Preset: --USER__invertImages: readium-invert-on

Scope: html

Override class: Chrome advanced (optional but should be applied by any means necessary if provided to users)

This will only apply in night mode to invert images and impact img.

:--a11y-normalize

Preset: --USER__a11yNormalize: readium-a11y-on

Scope: html

Required flag: :--fontOverride

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

It impacts font style, weight and variant, text decoration, super and subscripts.

:--no-ruby

Preset: --USER__noRuby: readium-noRuby-on

Scope: html

Required flag: :--advancedSettings

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

This will hide ruby annotations i.e. rt and rb.

Warning: if you customize those flags, all ReadiumCSS dist stylesheets must be rebuilt.

Reading System Styles

Custom properties for the Reading System are prefixed with --RS__.

Pagination

--RS__colWidth

The optimal column’s width. It serves as a floor in our design.

--RS__colCount

The optimal number of columns (depending on the columns’ width).

--RS__colGap

The gap between columns. It must be set in pixels so that it won’t resize with font size.

You must account for this gap when scrolling.

--RS__pageGutter

The horizontal page margins. It must be set in pixels so that it won’t resize with font size.

--RS__maxLineLength

The optimal line-length. It must be set in rem in order to take :root’s font-size as a reference, whichever the body’s font-size might be.

Safeguards

--RS__maxMediaWidth

The max-width for media elements i.e. img, svg, audio and video.

--RS__maxMediaHeight

The max-height for media elements i.e. img, svg, audio and video.

--RS__boxSizingMedia

The box model (box-sizing) you want to use for media elements.

--RS__boxSizingTable

The box model (box-sizing) you want to use for tables.

Default font-stacks

--RS__oldStyleTf

An old style serif font-stack relying on pre-installed fonts.

Default is "Iowan Old Style", "Sitka Text", Palatino, "Book Antiqua", serif.

--RS__modernTf

A modern serif font-stack relying on pre-installed fonts.

Default is Athelas, Constantia, Georgia, serif.

--RS__sansTf

A neutral sans-serif font-stack relying on pre-installed fonts.

Default is -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif.

--RS__humanistTf

A humanist sans-serif font-stack relying on pre-installed fonts.

Default is Seravek, Calibri, Roboto, Arial, sans-serif.

--RS__monospaceTf

A monospace font-stack relying on pre-installed fonts.

Default is "Andale Mono", Consolas, monospace.

Default font-stacks for Japanese publications

--RS__serif-ja

A Mincho font-stack whose fonts with proportional latin characters are prioritized for horizontal writing.

Default is "Hiragino Mincho ProN", "Hiragino Mincho Pro", "YuMincho", "BIZ UDPMincho", "Yu Mincho", "ＭＳ Ｐ明朝", "MS PMincho", serif.

--RS__sans-serif-ja

A Gothic font-stack whose fonts with proportional latin characters are prioritized for horizontal writing.

Default is ""Hiragino Sans", "Hiragino Kaku Gothic ProN", "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ W3", "YuGothic", "Yu Gothic Medium", "BIZ UDPGothic", "Yu Gothic", "ＭＳ Ｐゴシック", "MS PGothic", sans-serif.

--RS__serif-ja-v

A Mincho font-stack whose fonts with fixed-width latin characters are prioritized for vertical writing.

Default is "Hiragino Mincho ProN", "Hiragino Mincho Pro", "YuMincho", "BIZ UDMincho", "Yu Mincho", "ＭＳ明朝", "MS Mincho", serif.

--RS__sans-serif-ja-v

A Gothic font-stack whose fonts with fixed-width latin characters are prioritized for vertical writing.

Default is "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ W3", "YuGothic", "Yu Gothic Medium", "BIZ UDGothic", "Yu Gothic", "ＭＳゴシック", "MS Gothic", sans-serif.

Base styles for all ebooks

--RS__baseFontFamily

The default typeface for body copy in case the ebook doesn’t have one declared.

Please note some languages have a specific font-stack (japanese, chinese, hindi, etc.)

--RS__baseLineHeight

The default line-height for body copy in case the ebook doesn’t have one declared.

Default colors for all ebooks

--RS__textColor

The default color for body copy’s text.

--RS__backgroundColor

The default background-color for pages.

--RS__selectionBackgroundColor

The background-color for selected text.

It is worth noting it can be customized for each reading mode.

--RS__selectionTextColor

The color for selected text.

It is worth noting it can be customized for each reading mode.

Default styles for unstyled publications

Typefaces

--RS__compFontFamily

The typeface for headings. The value can be another variable e.g. var(-RS__humanistTf).

--RS__codeFontFamily

The typeface for code snippets. The value can be another variable e.g. var(-RS__monospaceTf).

Typography

--RS__typeScale

The scale to be used for computing all elements’ font-size. Since those font sizes are computed dynamically, you can set a smaller type scale when the user sets one of the largest font sizes.

Possible values: 1 | 1.067 | 1.125 | 1.2 (suggested default) | 1.25 | 1.333 | 1.414 | 1.5 | 1.618

--RS__baseFontSize

The default font-size for body copy. It will serve as a reference font all related computations.

--RS__baseLineHeight

The default line-height for all elements.

Vertical rhythm

--RS__flowSpacing

The default vertical margins for HTML5 flow content e.g. pre, figure, blockquote, etc.

--RS__paraSpacing

The default vertical margins for paragraphs.

--RS__paraIndent

The default text-indent for paragraphs.

Hyperlinks

--RS__linkColor

The default color for hyperlinks.

--RS__visitedColor

The default color for visited hyperlinks.

Accentuation colors

--RS__primaryColor

An optional primary accentuation color you could use for headings or any other element of your choice.

--RS__secondaryColor

An optional secondary accentuation color you could use for any element of your choice.

Reading Modes

Custom properties for reading modes are prefixed with --RS__.

--RS__backgroundColor

The background-color which must be applied to the entire screen in the reading mode.

--RS__textColor

The color for text in the reading mode.

--RS__linkColor

The color for the links in the reading mode.

--RS__visitedColor

The color for visited links in the reading mode.

--RS__selectionBackgroundColor

The background-color for selected text in the reading mode.

--RS__selectionTextColor

The color for selected text in the reading mode.

User Settings

Custom properties for user settings are prefixed with --USER__.

--USER__colCount

The number of columns (column-count) the user wants displayed (one-page view or two-page spread).

Scope: html

Possible values: 1 | 2 | auto (default)

Required flag: none

Override class: Chrome advanced (optional but should be applied by any means necessary if provided to users)

To reset, change the value to auto.

--USER__pageMargins

A factor applied to horizontal margins (padding-left and padding-right) the user wants to set.

Scope: html

It impacts body.

Recommended values: a range from 0.5 to 2. Increments are left to implementers’ judgment.

Required flag: none

Override class: Chrome advanced (optional but should be applied by any means necessary if provided to users)

To reset, change the value to 1.

--USER__backgroundColor

The background-color for the whole screen.

Scope: html

It impacts all elements in the DOM.

Possible values: Color HEX (e.g. #FFFFFF), rgb(a), hsl.

Required flag: none

Override class: Chrome advanced (optional but should be applied by any means necessary if provided to users)

To reset, remove the CSS variable.

--USER__textColor

The color for textual contents.

Scope: html

It impacts all elements but headings and pre in the DOM.

Possible values: Color HEX (e.g. #FFFFFF), rgb(a), hsl.

Required flag: none

Override class: Chrome advanced (optional but should be applied by any means necessary if provided to users)

To reset, remove the CSS variable.

--USER__textAlign

The alignment (text-align) the user prefers.

Scope: html

It impacts body, li, and p which are not children of blockquote and figcaption.

Possible values: left (LTR) or right (RTL) | start (logical property resolving to left in LTR, right in RTL) | justify

Required flag: :--advancedSettings

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

Note: the value start can be used to let all rendering engines, excepted Trident (IE11) and EdgeHTML (Edge), automatically deal with left and right based on the direction (dir attribute) set for the document and its nested elements.

--USER__bodyHyphens

Enabling and disabling hyphenation.

Scope: html

It impacts body, p, li, div and dd.

Possible Values: auto | none

Required flag: :--advancedSettings

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

Warning: for the time being, automatic hyphenation won’t work if you are using the Blink rendering engine (either via Chrome or a Webview) on ChromeOS, Linux and Windows. It indeed is not implemented yet and we recommend not trying to polyfill it using JavaScript as it will create a11y issues, especially with screen readers.

--USER__fontFamily

The typeface (font-family) the user wants to read with.

Scope: html

It impacts body, p, li, div, dt, dd and phrasing elements which don’t have a lang or xml:lang attribute.

Required flag: :--fontOverride

Override class: User settings (should be applied by any means necessary)

To reset, remove the required flag.

--USER__fontSize

Increasing and decreasing the root font-size. It will serve as a reference for the cascade.

Scope: html

Possible values: var(--RS__oldStyleTf) | var(--RS__modernTf) | var(--RS__sansTf) | var(--RS__humanistTf) | <string>

For Japanese, possible values become: var(--RS__serif-ja) (horizontal writing) | var(--RS__sans-serif-ja) (horizontal writing) | var(--RS__serif-ja-v) (vertical writing) | var(--RS__sans-serif-ja-v) (vertical writing) | <string>

Required flag: :--fontOverride

Override class: User settings (should be applied by any means necessary)

To reset, remove the required flag.

--USER__typeScale

The type scale the user wants to use for the publication.

Scope: html

It requires the ReadiumCSS-fs_normalize.css stylesheet.

It impacts headings, p, li, div, pre, dd, small, sub, and sup.

Recommended values: a range from 75% to 250%. Increments are left to implementers’ judgment.

Required flag: :--advancedSettings

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

--USER__lineHeight

Increasing and decreasing leading (line-height).

Scope: html

It impacts body, p, li and div

Recommended values: a range from 1 to 2. Increments are left to implementers’ judgment.

Required flag: :--advancedSettings

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

--USER__paraSpacing

The vertical margins (margin-top and margin-bottom) for paragraphs.

Scope: p

Recommended values: a range from 0 to 2rem. Increments are left to implementers’ judgment.

Required flag: :--advancedSettings

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

--USER__paraIndent

The text-indent for paragraphs.

Scope: p

Recommended values: a range from 0 to 3rem. Increments are left to implementers’ judgment.

Required flag: :--advancedSettings

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

--USER__wordSpacing

Increasing space between words (word-spacing, related to a11y).

Scope: h1, h2, h3, h4, h5, h6, p, li, div

Recommended values: a range from 0 to 1rem. Increments are left to implementers’ judgment.

Required flag: :--advancedSettings

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

--USER__letterSpacing

Increasing space between letters (letter-spacing, related to a11y).

Scope: h1, h2, h3, h4, h5, h6, p, li, div

Recommended values: a range from 0 to 0.5rem. Increments are left to implementers’ judgment.

Required flag: :--advancedSettings

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

--USER__ligatures

Enabling and disabling ligatures in Arabic (related to a11y).

Scope: html

It impacts all text.

Possible values: none | common-ligatures

Required flag: :--advancedSettings

Override class: User settings advanced (optional but should be applied by any means necessary if provided to users)

List of proposals and specs impacting Readium CSS

[Implementers’ doc]

Here is a list of all the specs and proposals which are likely to impact Readium CSS in the future. Some of them are still in their early days but you’ll probably have to review implementations once they are clearly defined and Readium CSS is updated accordingly.

The W3C CSSWG-Drafts repo is a good way to keep up.

Readium CSS’ fundamental approach has been reviewed and should be future proof, but you’ll have to keep the following in mind since EPUB 3.2 is now using CSS snapshots – those specs and proposals are very likely to be listed in future snapshots.

Media Queries Level 5

Source

Impact: Global (a11y)

CSSWG Issues

Logical Properties and Values

Source

Impact: Global (esp. vertical writing and RTL)

CSSWG Issues

CSS Extensions

Source

Impact: Global (CSS architecture)

CSSWG issues

Note: this specification defines methods for extending several CSS features (custom selectors, custom properties, custom functions, custom combinators, custom @ rules).

Calc notation: min() and max()

Source

Impact: Global

Note: this could help us define floor and ceiling values for a lot of configurations (e.g. have a ceiling for headings font-size when a large user font-size is set)

User Agent Properties

Source

Impact: Default, Themes, User Settings

CSS Rhythmic Sizing

Source

Impact: Pagination, User settings

CSSWG Issues

CSS Fonts Module Level 4

Source

Impact: Default (Variable fonts), User settings (font-min|max-size)

CSSWG Issues

COGA Semantics to Enable Personalization

Source

Impact: Implementations, User settings (related draft)

Related TF: PWG Personalization Task Force

Multicol editing

Source

Impact: Pagination

CSSWG Issues

W3C i18n

Source

Impact: CJK & RTL

CSSOM (a.k.a. Houdini)

Source

Impact: Implementations

CSSWG Issues

EPUB Compatibility

[Implementers’ doc] [Authors’ info]

This document describes a collection of non-standard CSS properties, metadata, and attributes that implementers should take into account to support for compatibility with the de facto EPUB ecosystem.

It also lists important standard features that authors are accustomed to or might rely upon in the future.

Introduction

There exists an increasingly large corpus of ebook content that depends on non-standard CSS properties, metadata and attributes. This document aims to describe the minimal set that Reading Systems might be willing to support for optimal ebook compatibility.

CSS At-rules

@page

@page

The @page CSS at-rule is used to modify the page margins in Adobe’s “Legacy RMSDK” (the one managing EPUB 2 files).

Margins applied in this rule will apply to any “screen” in paged views, unlike the ones set for html or body. It could therefore be used to apply extra margins to the web view or iframe for instance.

The @page at-rule can be accessed via the CSS object model interface CSSPageRule.

MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/@page

@supports

@supports

The @supports CSS at-rule lets authors specify declarations that depend on a browser’s support for one or more specific CSS features. This is called a feature query.

It is critical for the advancement of modern CSS that implementers try their best at supporting this rule, especially when pre-processing EPUB files before distribution. It indeed is one of the very few mechanisms allowing authors to do progressive enhancement (layout, typography, etc.), especially as it helps get around older Reading Systems which have no concept of fault tolerance, and will consequently ignore the entire stylesheet if they encounter some of those more modern properties.

The hard truth is that if authors feel this is not well-supported, they won’t use it. It will then be a lot more difficult to make progress happen.

MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/@supports

Non-standard Kindle Media queries

Since 2012, Amazon has been providing authors with non-standard media queries so that they specific styles can be declared for the old format (Mobi7) and the latest ones (KF8 and above).

@media amzn-kf8
@media amzn-mobi

Authors expect the styles in those declarations to be ignored by EPUB Reading Systems. Do not try to support them.

Docs: Kindle Publishing Guidelines

Interactive and Fixed-layout EPUB 2

There exists a significant corpus of fixed-layout and/or interactive files which leveraged the display options created by iBooks and Kobo for EPUB 2.

Kobo

To declare an EPUB as a FLEPUB (Fixed-Layout EPUB), a file named com.kobobooks.display-options.xml must be present inside the EPUB’s META-INF folder (where the container.xml resides).

The contents of this display options file seem to always be:

<?xml version="1.0" encoding="UTF-8"?>
<display_options>
  <platform name="*">
    <option name="fixed-layout">true</option>
  </platform>
</display_options>

As of November 2011, FLEPUB supports embedded fonts, audio, JavaScript (partially), media overlays (smil). It doesn’t support video and SVG.

Apple

To declare an EPUB 2 file as fixed-layout or interactive, a file named com.apple.ibooks.display-options.xml must be present inside the EPUB’s META-INF folder (where the container.xml resides).

Display Options

Supported display options are:

platform: *, iphone, or ipad

specified-fonts: true or false

interactive: true or false

fixed-layout: true or false

open-to-spread: true or false

orientation-lock: landscape-only, portrait-only, or none (default).

Example

<?xml version="1.0" encoding="UTF-8"?>
<display_options>
  <platform name="*">
    <option name="specified-fonts">true</option>
    <option name="interactive">true</option>
    <option name="fixed-layout">true</option>
    <option name="open-to-spread">true</option>
  </platform>
  <platform name="iphone">
    <option name="orientation-lock">landscape-only</option>
  </platform>
</display_options>

Metadata

Calibre

Calibre is using specific metadata for sorting, series and rating.

This metadata has a calibre: prefix.

Title sort

<meta content="Title of the Book, The" name="calibre:title_sort" />

This item allows Reading Systems to sort books in a non-stricly alphabetical way, by moving articles such as “The” and “An” to the end of the string.

Series

<meta content="Title of the Series" name="calibre:series" />

This item indicates the series the publication is part of.

Series index

<meta content="1.0" name="calibre:series_index" />

This item designates the position (index) of the publication in this series.

It can be a floating point number with up to two digits of precision e.g. 1.01, and zero and negative numbers are allowed.

Rating

<meta content="10.0" name="calibre:rating" />

This item stores the rating (integer) the user has explicitely set for the publication. In Calibre, 0.0 is unrated, 2.0 is one star, and 10.0 is five stars.

iBooks

iBooks is using specific metadata for embedded fonts, versioning, gaiji, scroll axis, and the EPUB3 files created with iBooks Author.

This metadata has an ibooks: prefix.

Authors must add the following prefix attribute in their <package> first:

prefix="ibooks: http://vocabulary.itunes.apple.com/rdf/ibooks/vocabulary-extensions-1.0/"

Then, they can use the ibooks-specific metadata.

Book versioning

<meta property="ibooks:version">1.0.0</meta>

When using book versioning, content providers are allowing iBooks customers who have downloaded the old version of the book to be notified that a new version is available for download. If the customer chooses to download it, the new version will replace the prior version on its devices.

Unfortunately, there is no way to retrieve the changelog for each version since this is managed at the iTunes level.

Docs: iBooks Asset Guide

Embedded fonts

<meta property="ibooks:specified-fonts">true</meta>

Authors can use the specified-fonts attribute to indicate the EPUB files contains embedded fonts, or override a user’s justification and hyphenation preferences. In other words, it preserves the font-family, text-align, and hyphens declarations as specified in the CSS stylesheet, as long as the user does not choose a different typeface when reading the book.

Docs: iBooks Asset Guide

Gaiji and image sizing

<meta property="ibooks:respect-image-size-class">className</meta>

Gaiji are small, inline images that represent characters that are not available in a character or font set. Gaiji are typically used for older symbols or characters in Japanese that have fallen out of use. Authors can define a custom class name for which iBooks will respect an image’s dimensions. Those inline images will then not be altered like other images, for which iBooks may force sizing.

Some authors may have used this metadata to force sizing for specific images, and not only gaiji. Moreover, some might use it to invert specific images like illustrations in night mode, since iBooks does it automatically in order for gaiji to be the same color as text’s.

Docs: iBooks Asset Guide

Scroll axis

<meta property="ibooks:scroll-axis">vertical | horizontal | default</meta>

iBooks’ scroll theme scrolls vertically for books with horizontal text, and scrolls horizontally for books with vertical text. By default, Japanese and Chinese books will thus scroll horizontally, while all other languages scroll vertically. This meta allows authors to redefine the scroll direction.

Docs: iBooks Asset Guide

iBooks Author EPUB3 output

<meta property="ibooks:format">RMT</meta>

This meta is automatically added to EPUB3 files generated with iBooks Author. It is probably used to trigger another rendering engine which supports very specific -ibooks- prefixed CSS properties (i.e. -ibooks-layout-hint, -ibooks-list-text-indent, -ibooks-strikethru-type, -ibooks-strikethru-width, -ibooks-underline-type, -ibooks-underline-width, -ibooks-stroke, -ibooks-popover-background, and -ibooks-popover-shadow) and the Tab Stops for CSS.

Moreover, this format is using interactive widgets which are managed at the Reading System level (the EPUB file contains <object> with a type of application/x-ibooks+widget and custom data-attributes for styling).

It could be used as a flag to indicate that the EPUB file was meant for iBooks and there will be rendering issues, especially interactive widgets since they won’t work as intended by the author.

Kindle

Kindle is using specific metadata for the primary writing mode and Fixed Layout – for both rendition and enabling FXL-specific features.

This metadata has no prefix.

Docs: Kindle Publishing Guidelines

Further details and undocumented metadata.

Primary writing mode

<meta name="primary-writing-mode" content="horizontal-rl"/>

Values can be horizontal-lr, horizontal-rl, vertical-lr, or vertical-rl.

This is a recent addition to the set of Kindle-specific metadata, probably as part of an internationalization effort.

It indicates the writing mode that should be used for the entire publication, including the flow in which virtual panels and magnification regions must progress when swiped in Fixed Layout (manga/comics and children books).

Fixed layout

<meta name="fixed-layout" content="true"/>

This is an older version of

<meta property="rendition:layout">pre-paginated</meta>

It should therefore be considered an alias.

Original resolution

<meta name="original-resolution" content="1024x600"/>

This indicates the original design resolution of the content.

Orientation lock

<meta name="orientation-lock" content="landscape"/>

This is an older version of

<meta property="rendition:orientation">landscape</meta>

It should therefore be considered an alias.

Book type

<meta name="book-type" content="children"/>

Values can be children or comic.

This removes reader functionality which may not be relevant for those genres (e.g. search, share, etc.). For more details, see this chart.

Blank pages

<itemref idref="blank-page" properties="layout-blank"/>

This property can be used to indicated a page is blank. If set, the page will be rendered in landscape mode (spread) but not in portrait mode (single page).

Region magnification (deprecated)

<meta name="regionMagnification" content="true"/>

This property was used to indicate the Region Magnification feature should be used for the Fixed-Layout book. It is now set automatically if the required markup is found in XHTML documents.

The Region Magnification feature allows users to zoom text (pop-up view) and comics’ panels, as well as navigating panel by panel. Authors must however provide specific markup (i.e. using a app-amzn-magnify class and storing targetId, sourceId and ordinal attributes in a JSON object as part of a data-app-amzn-magnify value).

Note: authors may be using a JavaScript polyfill to re-use this markup in EPUB apps that support scripting. We recommend not trying to implement those features in your app unless JavaScript is strictly disabled for authoring purposes.

Attributes

The iBooks Reading System is using a set of custom attributes to manage styling and features.

iBooks writing mode

__ibooks_writing_mode

Values can be the ones for the CSS property writing-mode i.e. horizontal-tb, vertical-rl, or vertical-lr.

This attribute is used to style pagination and scroll, the “page” dimensions, and vertical-alignment of some elements.

Authors’ usage of this attribute is unknown.

iBooks theme

__ibooks_internal_theme

Values can be BKWhiteStyleTheme, BKSepiaStyleTheme, BKGrayStyleTheme, or BKNightStyleTheme.

This attribute is used to apply reading modes (background-color, color and filter).

A handful of authors have been using them as a replacement to alternate stylesheets in iBooks.

iBooks font-family override

__ibooks_font_override

Value can be true.

This attribute is used to indicate DOM elements for which the font-family must be changed when the user applies a typeface.

Authors’ usage of this attribute is unknown, but it may have set expectations and/or CSS hacks which aim is getting parts of the content not impacted by this user setting.

iBooks text-align override

__ibooks_align_override

Value can be true.

This attribute is used to indicate DOM elements for which text-align must be changed when the user sets justification preferences.

Authors’ usage of this attribute is unknown, but it may have set expectations (e.g. elements with text-align: right won’t be impacted).

iBooks respect image size (gaiji)

__ibooks_respect_image_size

Value can be true.

This attribute is used to style images which class have been explicitly set in the ibooks:respect-image-size-class meta.

Authors’ usage of this attribute is indirect since they set the class name for which this attribute must be added.

Webkit’s CSS multi-column extensions

Apple extended the CSS multi-column specification with non-standard CSS properties to handle RTL scripts and vertical writing modes in iBooks. They were primarily designed for the setPagination API in the iOS UIWebView but works as expected in Safari/iOS webviews.

Column axis

-webkit-column-axis

Value can be auto, horizontal or vertical.

This CSS property can be used on iOS/Safari to force the column axis whenever needed. It allows the Reading App to lay out columns on the x-axis (horizontal) when the document is in a vertical-* writing mode for instance, which permits a two-column spread view as expected in print – CSS multicol being automatically laid out on the y-axis in those writing modes.

This property was removed from Blink in 2014.

It is noteworthy that columns, column-width, and column-count will be ignored when using this non-standard -webkit-column-axis property, and the width and height of the root (html) element will be used to lay out columns. Moreover, box-sizing may not work as expected, and impact padding and column-gap.

You can check this demo in Safari to see the effect this CSS Property has.

Column progression

-webkit-column-progression

Value can be normal or reversed.

This CSS property can be used on iOS/Safari to force the column progression whenever needed. It allows the Reading App to reverse the column progression for LTR documents in a RTL publication, and vice versa.

This property was removed from Blink in 2014.

You can check this demo in Safari and uncomment the CSS property in :root to see the effect it has.

Non-standard CSS properties

EPUB authors may have used the following non-standard properties to achieve specific styling or get around Reading Systems’ overrides.

Adobe text layout

adobe-text-layout

Values can be optimizeSpeed and (probably) optimizeLegibility, or auto.

Although this property and (especially) its values look closely related to text-rendering – so close that authors might have been using text-rendering instead –, it isn’t exactly the same.

At the time RMSDK 9.2 was released, this CSS property allowed authors to disable the typography enhancements, including hyphenation, by forcing the older text engine. It was thus primarily used to disable hyphenation, as some devices didn’t support adobe-hyphenate – and they could not disable hyphens for headings for instance.

Source: MobileRead Forums

Overflow scrolling

-webkit-overflow-scrolling

Values can be auto or touch.

The -webkit-overflow-scrolling CSS property controls whether or not touch devices use momentum-based scrolling for a given element.

Some authors may have been using this CSS property to improve the scrolling of overflowing elements, especially in fixed-layout.

Docs: Safari Docs

Non-breaking space mode

-webkit-nbsp-mode

Values can be normal or space.

The -webkit-nbsp-mode CSS property specifies the behavior of non-breaking spaces within an element.

This CSS property might pop up in files generated with the built-in MacOS’ (Cocoa) HTML generator.

Please note that although it might fix an issue in some languages like English, it might also create other issues in other languages, where non-breaking space shouldn’t be treated as a normal space (e.g. punctuation in French).

Docs: Safari Docs

Text fill

-webkit-text-fill-color

The -webkit-text-fill-color property defines the foreground fill color of an element’s text content e.g. headings or links.

Authors may have used this property to force a color for text in night mode, especially when targeting iBooks.

Text stroking

-webkit-text-stroke
-webkit-text-stroke-color
-webkit-text-stroke-width

The -webkit-text-stroke-color property specifies a stroke color for an element’s text, the -webkit-text-stroke-width property specifies the width of the stroke drawn at the edge of each glyph of an element’s text.

This can be used to achieve text with a stroked effect, or faux bolding, although this is pretty rare.

Background color and gradients

-webkit-linear-gradient()

The -webkit-linear-gradient() function must be treated as an alias of linear-gradient().

Some authors might have been using this to force a background-color in night mode. It would consequently be used in combination with -webkit-text-fill-color so that the text color is forced as well.

Mobile Text Size Adjustment

-webkit-text-size-adjust

The -webkit-text-size-adjust property allows control over the text inflation algorithm used on some mobile devices, many mobile browsers indeed apply a text inflation algorithm to make the text larger and more readable. By using this property, authors can simply opt out or modify this behavior.

Some web authors and/or authoring software might be using this property out of habit, but it actually breaks iBooks’ font-size user setting for instance. This should not be an issue in Readium CSS.

Docs: CSS Mobile Text Size Adjustment Module Level 1

Text decoration styling

-webkit-text-decoration-line
-webkit-text-decoration-color
-webkit-text-decoration-style

The -webkit-text-decoration-line CSS property sets the kind of decoration that is used on text in an element, the -webkit-text-decoration-color CSS property sets the color of the decorative additions to text and the -webkit-text-decoration-style CSS property sets the style of the lines.

There are standard unprefixed properties for these but some authors may have been using the -webkit- ones only.

MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Text_Decoration

Hyphenation

adobe-hyphenate

Values can be none, explicit, or auto.

This must be treated as an alias of hyphens (with explicit as an alias of manual).

A very large part of authors have been using this CSS property to control hyphenation. It should not be an issue as they probably at least used -webkit-hyphens and -epub-hyphens in addition to this adobe-hyphenate CSS property.

Source: MobileRead Forums

Hyphenate limit

-webkit-hyphenate-limit-before
-webkit-hyphenate-limit-after
-webkit-hyphenate-limit-lines

The -webkit-hyphenate-limit-before CSS property indicates the minimum number of characters in a hyphenated word before the hyphenation character, the -webkit-hyphenate-limit-after CSS property indicates the minimum number of characters in a hyphenated word after the hyphenation character, and the -webkit-hyphenate-limit-lines CSS property indicates the maximum number of successive hyphenated lines in an element.

Those properties are standardized in CSS Text Module Level 4, but -webkit-hyphenate-limit-before and -webkit-hyphenate-limit-after have been replaced with the hyphenate-limit-chars CSS property.

Docs: CSS Text Module Level 4

EPUB properties

Some authors might have used -epub- prefixed properties only, thinking they were enough since those CSS properties were standardized. Authors are now strongly encouraged to use unprefixed properties in EPUB 3.2.

In the meantime, implementers may want to polyfill at least some of those properties, especially those related to vertical writing, as practical issues may arise due to the lack of file updates on the authoring side. A mapping is available in the EPUB 3.2 spec if needed.

A PostCSS Plugin has been specifically created to unprefix those properties and change their value whenever needed – PostCSS can indeed be browerified. Implementers’ best option is running this process once and for all before distribution or file opening.

Install, test and build Readium CSS

[Implementers’ doc]

Install and init references for regression tests

First, navigatate to the project’s folder in your terminal,

cd path/to/readium-css

then type:

npm install

This will install all dev dependencies needed and make npm scripts available to ease all processes you’ll need to run later.

Then, once the install is finished, type:

npm run test:ref

This will create reference screenshots for the CSS regression tests.

Build

We are using PostCSS, a tool for transforming CSS with JavaScript. It comes with a vast amount of task-oriented plugins and allows authors to use modern specs which are not implemented yet.

PostCSS official website

PostCSS tutorial

PostCSS plugins list

PostCSS Dependencies

ReadiumCSS is relying on a PostCSS config to build dist stylesheets. If you npm install the repository, all those dependencies will be installed as well.

Here is the current list of dependencies:

stylelint (link);

postcss-cli (link);

postcss-import (link);

postcss-sorting (link);

postcss-custom-media (link);

postcss-custom-selectors (link);

postcss-discard-comments (link);

postcss-css-variables (link) [disabled];

postcss-alter-property-value (link) [disabled].

Build dist stylesheets

If you customize ReadiumCSS-config.css, you will have to rebuild stylesheets.

Note: the current build process is subpar – to say the least. Please feel free to improve it (gulp, grunt, etc.).

Available scripts

By default, the following scripts are available:

build, will build all stylesheets;

build:ltr, will build default stylesheets (Left to Right scripts);

build:rtl, will build stylesheets for Right to Left scripts;

build:cjk, will build stylesheets for Chinese, Japanese, and Korean in horizontal writing mode;

build:vertical, will build stylesheets for Chinese, Japanese, Korean, and Mongolian in vertical writing mode.

Those scripts will overwrite the files in the css/dist folder, the stylesheets you’ll use in your app.

Usage

First navigate to the readium-css folder if you didn’t already, then…

npm run build

Building dist stylesheets for browsers which don’t support CSS variables

If you need to build stylesheets for IE11 or an early version of Edge (e.g. 14), then you can use most of ReadiumCSS, excepted user settings. You’ll consequently have to customize the src’s ReadiumCSS-before.css, ReadiumCSS-default.css and ReadiumCSS-after.css and remove the user settings submodules.

Then you must customize the selectors in ReadiumCSS-config.js and replace them with either CSS classes or custom attributes so that reading modes and flags can work as expected.

Finally you will have to enable the postcss-css-variables and postcss-alter-property-value in the postcss.config.js file to be found at the src folder’s root.

The following must be added to plugins:

require("postcss-css-variables")({
  "preserve": true
}),
require("postcss-alter-property-value")({
  declarations: {
    "*": {
      task: "remove"
    , whenValueEquals: "undefined"
    }
  }
})

This will:

interpolate CSS variables into a static representation, while preserving variables for other browsers ("preserve": true);

remove static representations which can’t be interpolated and are undefined (remove task).

We recommend managing user settings via JavaScript in this case, especially as you can test support for CSS variables, as described in the CSS Variables primer.

Useful PostCSS plugins

Here is a list of additionnal PostCSS plugins which might prove useful to implementers.

Unprefix EPUB properties: EPUB interceptor

Adding vendor prefixes: Autoprefixer

Test

Once you have build dist stylesheets, you can run regression tests using Backstop.js.

It helps you check if you didn’t accidentally create a breaking change when customizing stylesheets, and make sure pagination, reading modes, and user settings work as expected.

Config

You will find the configuration file, backstop.json at the root of the project. By default, it runs those tests for a smartphone (portrait) and a tablet (landscape) viewports using Chrome, but you can customize it to fit your needs.

For instance, if you don’t need to support mobile, you could modify viewports:

"viewports": [
  {
    "label": "desktop small",
    "width": 800,
    "height": 600
  },
  {
    "label": "desktop large",
    "width": 1600,
    "height": 900
  }
]

And if you want to run tests using Webkit instead of Blink because you’re developing iOS apps:

"engine": "phantomjs"

Test files

If you customize flags in ReadiumCSS-config.css, you must modify HTML files in the tests folder; user settings are indeed set as inline styles on the html element and are using the default flags.

Available scripts

By default, the following scripts are available:

test, will run tests;

test:ref, will create reference screenshots;

test:approve, will update reference screenshots from the current test.

Usage

First navigate to the readium-css folder if you didn’t already, then…

npm run test

The regression tests will run against the newly-created dist stylesheets, which is why you must build them beforehand.

Once all scenarios are tested for the viewports you created, which can take up to a minute, a report will automatically open in your browser.

If a unit test is marked as “failed”, it doesn’t necessarily mean the user setting failed, it just means you made a significant change which impacts rendering. Take a closer look at the diff, and if you’re happy with the result, head to the terminal and type:

npm run test:approve

This will make the current test screenshots the new reference for the next test.

Note: on some occasions, an error might happen during tests and the process won’t stop. Try ctrl + c to stop the current process and run the test again.

Fixed-layouts’ Reading Systems Requirements

[Implementers’ doc] [Authors’ doc]

Source: EPUB Content Documents 3.2

There’s a few criteria Reading Systems must meet in order to be conformant:

it should allocate the full content display area (i.e. as much of the available Viewport area as possible) for the document;

it must use the dimensions expressed in the viewport meta tag to render XHTML Content Documents;

it must use the dimensions expressed in the viewbox, and/or x, y, width and height attributes in SVG to render SVG Content Documents.

Styling

You should not inject additional content such as borders, margins, headers or footers into the viewport or the appplication area surrounding the viewport.

Scaling

XHTML (viewport meta)

When the aspect ratio does not match the aspect ratio of the Reading System, you may position the containing block inside the area to accommodate the user interface (letter-boxing).

Content positioned outside the containing block will not be visible.

SVG

SVG is a little bit more complex as there are different options to take into account.

Viewbox attribute

If the SVG only has a viewbox attribute, the coordinate system it defines is mapped to the viewport, keeping the aspect ratio.

Sizing and positioning attributes

If the pixel values defined by x, y, height and width exceed the viewport’s pixel values, the graphic must not be rescaled (it must be clipped on the viewport boundaries).

Both

The coordinate system defined by the viewbox is mapped to the viewport, keeping the aspect ratio.

Notes

The rendition:spread portrait and rendition:viewport are deprecated in EPUB 3.2.

Consequently, the rendition:spread-portrait spine override is deprecated as well.

E-production feedback and requests

[Implementers’ info]

One important part of the Readium CSS project is collecting feedback and queries from the e-production community (CSS authors). This is a summary.

CSS Authors’ typical profile

The typical CSS author has been doing e-production for 3 years or more (76%), is primarily concerned about interoperability (80%) and feels like he/she gets at least CSS fundamentals (88%). Most of his/her queries are related to layouts you can do in print but you can’t in ebooks yet.

A few notes:

interoperability implies Kindle, back to Mobi7 on the north-american market (Mobi7 is ± HTML 3.2);

specific versions of EPUB files for more advanced RS like iBooks or Readium exist, and this issue is partly related to distribution: authors don’t know the app the reader will use and don’t want risking rendering issues;

sometimes, specific versions mean authors (and/or software) will fall back to EPUB 2 files, in order to get around support uncertainty;

one key is probably progressive enhancement techniques, but that’s more of an education/evangelization issue and not in implementations’ scope per se.

Workflow and authoring

Workflow is still print-centric

From the feedback we could get, DTP software is still prevalent (more than 2/3 of answers), but automation is a thing (XML and even Node.js).

This means that should we provide new design options, change won’t happen overnight. Authors would have to add them to their workflow first (manual editing or automation upgrade), then authoring software would have to support them.

What’s interesting is that most authors would appreciate having such design options (more than 75%, on two polls), but if there isn’t any side-effects in other apps (cf. interoperability). Of course that would require production moving to EPUB 3 (EPUB 2 still makes up roughly 70% of all incoming content @ Kobo for instance).

So once again, we have an education/evangelization issue to deal with there.

Authoring practices

CSS authoring varies greatly.

Almost 2/3 of authors use a custom stylesheet that they adjust for every book, very few actually rely on the styles output by their DTP tools. As a consequence, there’s no consensus when it comes to the CSS selectors authors use. It can be:

p

.class

p.class

div.class p.class

[epub|type="semantic-inflection"] p

greatly-specified selectors with or without combinators (from actual samples).

Reasons include:

ease of use;

complexity and variety of the publication’s contents;

semantics (especially with epub:type);

production being outsourced with no specification – i.e. this is how the contractor do things.

If we want to solve the user settings issue well, we’ll probably have to find clever and inventive ways, selectors specificity being a dead-end in practice.

There’s a proposal for user agent properties and a draft for customization, they have some potential for upcoming files if EPUB gets a “do not touch my CSS” flag at some point – what’s already distributed is probably lost. With user agent properties, authors could design user-centric stylesheets so, in theory, RS could not override styles at all and just set values for those properties.

In the meantime, we have to “emulate” the cascade and resolve to !important. So that’s trying to make an unperfect mechanism into something more elegant, which requires a lot of fine-tuning.

Worries and issues

Worries

What bothers authors the most:

the app overriding styles without an explicit demand from the user (a.k.a. changing a setting);

the complete lack of control over page layout (margins, background, etc.);

user overrides which are all or nothing.

Interestingly, reading modes’ adjustments and user settings exposure are not priorities – which doesn’t mean they aren’t concerns. There are two assumptions we could make:

providing readers with images filters in night mode is probably the best first step we can make since a significant part of authors might not use extra markup to deal with it on an image-per-image basis (especially if no other RS supports it);

user settings exposure is probably one of the best practical ways to deal with non-binary user settings and overrides (cf. user agent properties proposal) so, once again, education/evangelization kicks in.

Issues

Top issues are, in order of priority:

images’ sizing e.g. author’s sizing is not respected, image is cut-off;

broken media queries (which makes responsive design impossible);

lack of support for modern CSS;

Math.

This shouldn’t come as a surprise; those are long-standing issues in need of practical solutions (media queries don’t work in columned-content) and fixes (flexbox, grid, and modern layout specs have a lot of bugs in columns’ implementations). Our best bet there is collaborating with the CSS-multicol spec editors since we’re probably one of the major use cases for this spec.

Popular requests

Unsurprisingly, a lot of requests are about layouts possible in print but not (yet) in e-books:

full bleed (container, image, background-color);

support for paged-media (running header/footer, float figures top/bottom, etc.);

vertical centering and alignment;

floated shapes (wrapping the image and not its bounding box);

option to put contents like page numbers, icons, etc. in the margins;

using a baseline grid;

forcing the chapter title as the running header;

proper support of page-breaks;

media queries for reading modes (sepia, night, etc.);

stylable popup footnotes.

A few notes:

in theory, putting contents in the margins and full-bleed are (almost) possible in Readium CSS: it depends on its implementation. Consequently, don’t be surprised if some authors make some experiments and raise issues;

some requests are already possible in some rendering engines: vertical-centering and alignment, floated shapes, and using a baseline grid is already possible on some platforms (depends on the web view/browser used) so it is more of an authors’ issue;

anything related to paged-media has had low traction at the browser vendors level so far, you’ll probably have to polyfill those features if you want to meet those expectations.

Interoperability issues reported

We care deeply about interoperability. Although Readium CSS has been designed from scratch, a lot of research has been put into other Reading Systems in order to improve interop (and not introduce breaking changes/side-effects). To our knowledge, we’re even the first project openly tackling EPUB implementations’ interoperability. Indeed, one of our main goals is to provide authors with a solid bedrock so Readium CSS should not become an issue for them.

A few interop issues have been reported:

page margins: some apps/devices have huge page margins, others don’t have any, it’s really hard for authors to know what they should be doing here (margin: 0 or margin: value);

support of existing specifications is lacking (the issue being that some existing specs are really hard to implement well in practice);

images optimization (this could be related to picture and srcset);

font obfuscation isn’t implemented everywhere, which is a huge issue for fixed-layout.

CSS Performance Hacks

[Implementers’ doc]

This document discusses the CSS specs implementers can use in case they have performance issues:

will-change;

CSS containment.

At first sight, using those 2 specs can give tremendous results but you sometimes have to use them in clever ways: it’s not just about adding a line of CSS in your stylesheet.

Will-change

The fundamental rule of will-change

Set will-change to the properties you’ll actually change, on the elements that are actually changing. And remove it when they stop.

Abstract

The will-change property allows an author to inform the UA ahead of time of what kinds of changes they are likely to make to an element. The UA can then try to optimize how they handle the element ahead of time, performing potentially-expensive work preparing for an animation before the animation actually begins.

In other words, will-change is a UA hint, it doesn’t have any styling effect on the elements for which you’re using it. It’s worth noting it can have appearance effects though, if a new stacking context is created.

It is, in many ways, an official property for the infamous “translate-z hack.” Although it was meant for animation, it can also deal with more simple changes.

Usage

will-change: <animateable-feature> = scroll-position || contents || <custom-ident>

Scroll-position

Indicates that the author expects to animate or change the scroll position of the element in the near future.

A browser might take this value as a signal to expand the range of content around the scroll window that is rendered, so that longer/faster scrolls can be done smoothly.

Contents

Indicates that the author expects to animate or change something about the element’s contents in the near future.

A browser might take this value as a signal to cache less aggressively on the element, or avoid caching at all and just continually re-render the element from scratch.

custom-ident

Indicates that the author expects to animate or change the property with the given name on the element in the near future.

A browser might take a value of transform as a signal that it should go ahead and promote the element to its own layer immediately, before the element starts to be transformed, to avoid any delay involved in rerendering the old and new layers.

Drawbacks

By using will-change, you’re basically telling the browser the element is a few moments away from changing, the browser consequently dedicates memory and resources to this element. If you use it for too many elements, it will thus degrade performance.

This property should be considered a last resort, it was not meant for premature optimization. You should use it only if you have to deal with performance issues.

Do’s and Dont’s

Do’s

Use will-change sparingly in stylesheets

Give will-change sufficient time to work

Use <custom-ident> to target super specific changes (left, opacity, etc.)

Use it in JavaScript if needed (add and remove hint)

Remove will-change after the changes are done

Dont’s

Don’t declare changes to too many properties

Don’t apply it to too many elements

Don’t waste resources on elements that have stopped changing

Examples

UI elements

Specifying will-change for a small number of persistent UI elements in a page which should react snappily to the user is appropriate:

body > .sidebar {
	will-change: transform;
	/* Will use 'transform' to slide it out when the user requests. */
}

Because this is limited to a small number of elements, the fact that the optimization is rarely actually used doesn’t hurt very much.

User click

If an element is going to change when a user clicks on it, setting will-change on hover will usually give at least 200 milliseconds for the optimizations to be set up, as human reaction time is relatively slow.

.element {
	transition: opacity 0.2s;
	opacity: 1;
}

.element:hover {
	will-change: opacity;
}

.element:active {
	opacity: 0.3;
}

Adding and removing the hint with JavaScript

This is probably the way to go, should you try using will-change to optimize performance.

Here we have the hint added on :hover, then removed when the animation has ended.

var el = document.getElementById('element');

// Set will-change when the element is hovered
el.addEventListener('mouseenter', hintBrowser);
el.addEventListener('animationEnd', removeHint);

function hintBrowser() {
	// The optimizable properties that are going to change
	// in the animation's keyframes block
	this.style.willChange = 'transform, opacity';
}

function removeHint() {
	this.style.willChange = 'auto';
}

References

CSS Will Change Module Level 1

Can I Use

Mozilla Dev Network

Everything you need to know about the CSS will-change property

CSS ‘will-change’ Property: A Performance Case Study

CSS Containment

Note: This is only implemented in Blink (Chrome + Opera). It is under consideration for Microsoft Edge.

Abstract

The contain property indicates that the element and its contents are, as much as possible, independent of the rest of the page.

This allows the browser to recalculate layout, style, paint, size, or any combination of them for a limited area of the DOM and not the entire page. To put it simply, it lets developers limit the scope of the browser's styles, layout and paint work.

It was primarily meant for webpages which contain a lot of widgets that are all independent as it can be used to prevent one widget's CSS rules from changing other things on the page.

Usage

contain: strict || content || size || layout || style || paint

Strict

This is a shorthand for all values, it is equivalent to contain: size layout style paint.

Content

This is a shorthand for all values but size, it is equivalent to contain: layout style paint.

Size

It indicates that the element can be laid out without the need to examine its descendants.

Layout

It indicates that nothing outside can affect the element’s internal layout, and vice versa.

Style

It indicates that, for properties which can have effects on more than just an element and its descendants, those effects don’t escape the containing element.

Paint

It indicates that the descendants of the element don’t display outside its bounds, so if an element is off-screen or otherwise not visible, its descendants are also guaranteed to be not visible.

Possible optimizations

In theory, huge performance gains are possible, but it requires a solid knowledge of how browsers work and what causes reflow, relayout, repaint, etc. Judging by examples, I can see how it could be useful but we’ll probably have to find inventive and clever ways to leverage it since our scope is very often the root document.

If you need a refresher:

How browsers work

What force layout/reflow

Layout

When laying out the page, the contents of separate containing elements can be laid out in parallel, as they’re guaranteed not to affect each other.

When laying out the page, if the containing element is off-screen or obscured and the layout of the visible parts of the screen do not depend on the size of the containing element (for example, if the containing element is near the end of a block container, and you’re viewing the beginning of the block container), the layout of the containing elements' contents can be delayed or done at a lower priority.

Layout is normally document-scoped so if you change an element's left property, every single element in the DOM might need to be checked. Enabling containment here can potentially reduce the number of elements to just a handful, rather than the whole document, saving the browser a ton of unnecessary work and significantly improving performance.

Style

Whenever a property is changed on a descendant of the containing element, calculating what part of the DOM tree is “dirtied” and might need to have its style recalculated can stop at the containing element.

Containment here is purely about limiting the parts of the tree that are under consideration when styles are mutated, not when they are declared.

Paint

If the containing element is off-screen or obscured, the UA can directly skip trying to paint its contents, as they’re guaranteed to be off-screen/obscured as well.

Unless the clipped content is made accessible via a separate mechanism such as the overflow, resize, or text-overflow properties, the UA can reserve “canvas” space for the element exactly the element’s size.

Because they are guaranteed to be stacking contexts, scrolling elements can be painted into a single GPU layer.

It acts as a containing block for absolutely positioned and fixed position elements: any children are positioned based on the element, not the document.

It becomes a stacking context: things like z-index will have an effect on the element, and children will be stacked according to the new context.

It becomes a new formatting context: a block level element will be treated as a new, independent layout environment. Layout outside of the element won’t typically affect the containing element's children.

Size

It ensures you don’t rely on child elements for sizing, but by itself it doesn’t offer much performance benefit.

References

CSS Containment Module Level 1

Can I Use

Mozilla Dev Network

CSS Containment in Chrome 52

i18n glossary

[Implementers’ doc] [WIP]

This document aims to list terms implementers might not be familiar with. It can be useful when encountering one of those terms in bug reports, issues, or feedbacks.

Arabic

This glossary has been created from the Arabic Script Requirements.

Eastern Arabic numerals (الأَرقَامْ العَرَبِيَّة المَشْرِقِيَّة)

Numerals used in Arabic-Indic and Eastern Arabic-Indic (٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩). Use the preferred terminology to avoid confusion.

Elongation (التَّطْوِيلْ)

See Tatweel.

European numerals (أَرْقَامْ أُورُوبِيَّة)

Any of the symbols in [0-9] used to represent numbers. Some cultures are used to call them ”Arabic numerals.” Use “European numerals” to avoid confusion.

Harakat (حَرَكَاتْ)

Tashkil marks representing short vowel sounds.

Ihmal (إِهْمَالْ)

See Tashkil.

Ijam (إِعْجَامْ)

Diacritical marks applied to a basic letter shape (or skeleton) to derive a new letter. For example a dot under a “curve” to get the letter Beh. In Unicode each letter plus ijam combination is encoded as a separate, atomic character.

Joining forms

Arabic script is a cursive writing system; every Arabic letter has one, two, or four different joining forms (isolated, initial, medial, final), which allow the letter to join to its neighbors, if applicable. See the Joining section of the Arabic Script Requirements for further details.

Kashida (الْكَشِيدَة)

A method of aligning both edges of all lines to be the same given length by extending the horizontal connection between joined letters. See the Kashida section of the Arabic Script Requirements for further details.

Mabsut (مَبْسُوطْ)

Kind of writing style that tends to rigidity and firmness with pronounced angularity.

Mukawwar (مُكَوَّرْ)

Kind of writing style, generally opposed to mabsut, that is more flexible and rounded.

Shadda (شَدَّة)

A tashkil mark indicating gemination of the base consonant.

Sukun (سُكُونْ)

A tashkil mark indicating the lack of a vowel after the consonant to which it is attached.

Tanwin (تَنْوِينْ)

Tashkil marks indicating postnasalized or long vowels at the end of a word, and indicated by doubling the sign of one of the harakat diacritics.

Tashkil (تَشْكِيلْ)

Marks that are added to letters to indicate vocalisation of text or to correct pronunciation.

Tatweel (التَّطْوِيلْ)

Tatweel is a dual-joining character that can be inserted between two joined letters to widen their connection. See the Tatweel section of the Arabic Script Requirements for further details.

Chinese

This glossary has been created from the Chinese Text Layout Requirements.

Annotation text / Zhùwén (注文)

Interlinear text run indicating pronunciation or definitions.

Base text (基文)

A character to be annotated by ruby, ornament characters, or emphasis dots.

Big5 (大五码)

Big-5 or Big5 is a Chinese character encoding method used in Taiwan, Hong Kong, and Macau for Traditional Chinese characters. A total of 13,060 Traditional Chinese characters are encoded with Big5.

Bilingual annotations (中外文对照)

To prompt a Chinese term with its original or translation in the form of annotation text or base text, an instance of interlinear annotation.

Bopomofo / Zhuyin (注音符号)

The general name of Mandarin Phonetic Symbols and Taiwanese Phonetic Symbols.

End point / Mòduān (末端)

The ending point of a line, meaning the bottom side in vertical writing mode, or the right side in horizontal writing mode.

Fixed inter-character spacing setting / Shūpái (疏排)

A text setting with a uniform inter-character spacing.

Fullwidth (全角/全形)

A square character frame that has a character advance of character size.

Grid alignment / Zònghéng duìqí (纵横对齐)

The process, under the premise of justification, of arranging characters within grids to make sure that they are aligned in both horizontal and vertical axes.

Halfwidth (半形/半角)

A square character frame that has a character advance of 1/2 character size.

Han characters / Hànzì (汉字)

Characters that form the basis of the Chinese language.

Hanging punctuation (行尾点号悬挂)

Typesetting punctuation for line endings outside the margin of alignment, also known as hanging punctuation or exdentation.

Hanyu Pinyin (汉语拼音)

Hanyu Pinyin provides a method of using Latin characters with diacritics to indicate tone. It is often used to teach Standard Chinese and encourage its use as a common language for communication.

Horizontal writing mode / Héngpái (横排)

The process or the result of arranging characters on a line from left to right, of lines on a page from top to bottom, and/or of columns on a page from left to right.

Horizontal-in-vertical setting / Zòngzhōnghéngpái (纵中横排)

To typeset a (small) group of characters horizontally within a vertical line of main text.

Interlinear annotations (行间注)

Annotations between lines used to indicate the pronounciation of a word or an explanation of a word.

Interlinear comments (行间批语)

Comments included between lines, generally free-form with no restrictions on line length. These can exceed the length of a single line.

Hindu–Arabic numerals (阿拉伯数字)

Hindu–Arabic numerals, also called Arabic numerals or European digits are the ten digits: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, based on the Hindu–Arabic numeral system.

Phonetic annotation (标音)

The way to indicate the pronunciation of the Chinese characters, e.g. interlinear annotations.

Proportional type (比例字体)

A proportional typeface contains glyphs of varying widths in order to make the glyphs properly related in size. It is widely used in Latin characters.

Rhotacization of syllable finals (儿化音)

In standard Chinese and certain dialects, some words have rhotacized endings that result in phonetic changes to how the word sounds.

Romanization (罗马拼音)

The conversion system of writing from Chinese pronunciation into Roman/Latin script.

Simplified Chinese (简体中文)

The writing system of Chinese using characters that are relatively simpler in structure and stroke count, mainly refer to Jianhuazi (Simplified Character) published and revised in 1960s in Mainland China.

Solid setting / Mìpái (密排)

To arrange characters with no inter-character space between adjacent character frames.

Starting point / Shǐduān (始端)

The text or character that is near the beginning of the line. Normally, when the text is in vertical writing mode, the starting point is on the top; in horizontal writing mode, the starting point is on the left.

Traditional Chinese (繁体中文)

The writing system of Chinese using characters that are relatively more complex in structure and stroke count. Known as Traditional Chinese because of its long history of use.

Vertical writing mode / Zhípái / Shùpái (直排/竖排)

The process or the result of arranging characters on a line from top to bottom, of lines on a page from right to left, and/or of columns on a page from top to bottom.

Western scripts / Xīwén (西文)

Writing systems derived from Greek and Latin.

Indic

This glossary has been created from the Indic Text Layout Requirements.

Akhand Ligatures

Required consonant ligatures that may appear anywhere in the syllable. They have the highest priority and are formed first.

Anuswara

A modifier denoted by a dot above the letter after which it is to be pronounced.

Augmented Backus-Naur Form (ABNF)

A meta-language based on Backus-Naur Form (BND), but consisting of its own syntax and derivation rule. The linguistic definition of the Indic orthographic syllable has been mapped to ABNF for the purpose of text segmentation, line breaking, drop letter, and letter spacing. See the Indic Text Layout Requirements for further details.

Avagraha

A modifier shaped like the letter “S” used in the Sanskrit text.

Bengali

A script used in the Bengali, Assamese, and Manipuri languages.

Chandrabindu

A modifier denoted by a breve with a dot superposed above the letter after which it is to be pronounced.

Danda (purna viram)

A Devanagari phrase separator used to mark the end of the verse in Sankrit text, shlokas, etc. The properties of the Danda and double Danda should be the same as other punctuation marks, and a line should never start with those characters.

Devanagari

A script used in the Hindi, Sanskrit, Marathi, Konkani, Nepali, Maithili, Sindi, Bodo, Dogri, Santhali, and Kashmiri languages.

Gurmukhi

A script used in the Punjabi language.

Halant (Virama)

The character used after a consonant to strip it of its inherent vowel.

Indic orthographic syllable

The effective orthographic unit of Indic writing systems, consisting of a consonant and a vowel core, and optionally preceded by one or more consonants. The syllable is indivisible, thus it can not be possible to position the cursor within it.

Matra

A character used to represent a vowel sound that is not inherent to the consonant.

Nukta

A character that alters the way a preceding consonant is pronounced.

Visarga

A modifier denoted by two dots place one above the other (it looks like a colon).

Japanese

This glossary has been created from the Japanese Text Layout Requirements.

Base character / Oya moji (親文字)

A character to be annotated by ruby, ornament characters, or emphasis dots.

Base line / Narabi sen (並び線)

A virtual line on which almost all glyphs in Western fonts are designed to be aligned. (JIS Z 8125)

Block heading / Betsugyōmidashi (別行見出し)

A kind of heading styles. The heading is set as an independent line from basic text. (JIS Z 8125)

Bound on the left-hand side / Hidari toji (左綴じ)

Binding of a book to be opened from the left (horizontal writing mode).

Bound on the right-hand side / Migi toji (右綴じ)

Binding of a book to be opened from the right (vertical writing mode).

Bousen (sideline) / Bōsen (傍線)

A line drawn by the left or right side of a character or a run of text in vertical writing mode. (JIS Z 8125)

Character advance / Jihaba (字幅)

Size of a character frame in the inline direction, generally indicated as a ratio of the size of a full-width character, as in full-width, half-width, or quarter em width. Character advance is the width of a given character in horizontal writing-mode, while it is the height in vertical writing-mode.

Character frame / Sotowaku (外枠)

Rectangular area occupied by a character when it is set solid.

Characters not ending line / Gyōmatsu kinsoku moji (行末禁則文字)

Any character for which "line-end prohibition rule" is invoked. (JIS Z 8125)

Characters not starting line / gyōtō kinsoku moji (行頭禁則文字)

Any character for which "line-start prohibition rule" is invoked. (JIS Z 8125)

Chu-boso-kei / Chūbosokei (中細罫)

Middle width line, usually about 0.25mm.

Column spanning heading / Dannuki no midashi (段抜きの見出し)

Headings using multiple columns.

Compound word / Jukugo (熟語)

A combination of two or more kanji characters which makes one word.

Cut-in heading / Madomidashi (窓見出し)

A style of headings. Headings do not occupy the full lines, but share lines area with following main text lines.

Emphasis dots / Kenten (圏点)

Symbols attached alongside a run of base characters to emphasize them. (JIS Z 8125)

European numerals / Arabia sūji (アラビア数字)

Any of the symbols in [0-9] used to represent numbers. (JIS Z 8125)

Even inter-character spacing / Kintō wari (均等割り)

A text setting with uniform inter-character spacing per line so that each line is aligned on the same line-head and line-end. (JIS Z 8125)

Fixed inter-character spacing / Aki gumi (アキ組)

A text setting with a uniform inter-character spacing. (JIS Z 8125)

Fixed-width / Monosupēsu (モノスペース)

A characteristic of a font where the same character advance is assigned for all glyphs. (JIS Z 8125)

Footnote / Kyakuchū (脚注)

A note in a smaller face than that of main text, placed at the bottom of a page. (JIS Z 8125)

Full-width / Zenkaku (全角)

Character frame which character advance is equal to a given character size. A full-width character frame is square in shape by definition.

Futoji (太字)

A kind of font style. Similer to bold in western typograpy.

Furigana (振り仮名)

A method of ruby annotation using kana characters to indicate how to read kanji characters. This term derives from a Japanese verb “furu” (to attach alongside) and “kana”, and has been used synonymously with “ruby.”

Furikanji (振り漢字)

A method of ruby annotation using Kanji characters for ruby instead of kana characters.

Furiwake (振分け)

A method of placing multiple runs of text in a line. (JIS Z 8125)

Gaiji (外字)

Gaiji are small, inline images that represent characters that are not available in a character or font set. Gaiji are typically used for older symbols or characters in Japanese that have fallen out of use. It should be treated as text, especially in reading modes e.g. inverted in night mode.

General-ruby / Sō rubi (総ルビ)

A method of ruby annotation that attaches ruby text for all Kanji characters in the text. (JIS Z 8125)

Group-ruby / Gurūpu rubi (グループルビ)

A method of ruby character distribution such that the length of ruby text matches to that of the base text by giving the same adjusted amount of space between ruby characters.

Gyodori (行取り)

To keep block direction area for headings and so on, along with line units in kihon-hanmen. The width of the gyodori space is calculated with following fomula: line width × number of lines + line gap × (number of lines − 1). Implementers can think of it as something like “vertical rhythm.”

Half-width / Hankaku (半角)

Character frame which has a character advance of a half em.

Han-tobira (半扉)

A simplified version of naka-tobira, the verso side of which text of the new part starts. (JIS Z 8125)

Hanmen (版面)

Actual printed area in a page excluding the margins. It is the page content area.

Horizontal writing mode / Yokogumi (横組)

The process or the result of arranging characters on a line from left to right, of lines on a page from top to bottom, and/or of columns on a page from left to right. (JIS Z 8125)

Ideographic numerals / Kansūji (漢数字)

Ideographic characters representing numbers.

Inline cutting note / Warichu (割注)

A note of two or more lines inserted in the text. It includes brackets which surround the note (JIS Z 8125)

Inseparable characters rule / Bunri kinshi (分離禁止)

A line adjustment rule that prohibits inserting any space between specific combinations of characters. (JIS Z 8125)

Inter-character space / Jikan (字間)

Amount of space between two adjacent character frames on the same line.

Itemization / Kajō gaki (箇条書き)

To list ordered or unordered items one under the other. (JIS Z 8125)

Japanese gothic face / Goshikku tai (ゴシック体)

A Japanese typeface, with strokes almost the same in thickness, and no special ornament on a stroke such as a triangular element commonly seen in the Mincho typeface. Used for text emphasis and/or headings. Similar to “sans serif” in Western typography.

Jidori (字取り)

A method of aligning a run of text to both edges which is specified by a position to start and the length calculated by a specified number of a given size of characters. (JIS Z 8125)

Jouyou Kanji Table / Jōyō kanji hyō (常用漢字表)

The official list of Kanji characters “for general use in society. such as in legal and official documents, newspapers, magazines, broadcasting and the like.” It was established in 1981 as a reference guide for people in composing contemporary Japanese. It listed 1,945 of Kanji characters together with their orthographic shapes, Japanese native reading (Kun), Chinese derived reading (On) and other useful information.

Jukugo-ruby (熟語ルビ)

A method of ruby character distribution determined by two functions, one is to provide reading for each Kanji character, the other is to give a united appearance attached to a word.

Kanbun (漢文)

Chinese classic text (or text in the same style) with various auxiliary symbols so that it can be read as Japanese text.

Katatsuki (肩付き)

A method of attaching ruby at the upper right of each base character. (JIS Z 8125)

Kihon hanmen (基本版面)

The default dimensions of the main area of a typeset page specified by text direction, number of columns, character size, number of characters in a line, number of lines in a column, inter-line spacing and inter-column spacing. (JIS X 4051)

Line adjustment by hanging punctuation / Burasage gumi (ぶら下げ組)

A line breaking rule to avoid commas or full stops at a line head (which is prohibited in Japanese typography) by taking them back to the end of the previous line beyond the specified line length. (JIS Z 8125)

Line breaking rules / Kinsoku shori (禁則処理)

A set of rules to avoid prohibited layout in Japanese typography, such as “line-start prohibition rule,” “line-end prohibition rule,” inseparable or unbreakable character sequences and so on. (JIS Z 8125)

Line feed / Gyō okuri (行送り)

The distance between two adjacent lines measured by their reference points. (JIS Z 8125) Implementers can think of it as the line-height CSS property.

Line gap / Gyōkan (行間)

The smallest amount of space between adjacent lines.

Line-end prohibition rule / Gyōmatsu kinsoku (行末禁則)

A line breaking rule that prohibits specific characters at a line end. (JIS Z 8125)

Line-start prohibition rule / Gyōtō kinsoku (行頭禁則)

A line breaking rule that prohibits specific characters at a line head. (JIS Z 8125)

Mincho typeface / Minchōtai (明朝体)

A major style of Japanese font. Horizontal lines are thin and vertical lines are thick. At the start position and the end position, there are triangular figure representing press of brush. Kana are designed to balance the Kanji design. In Japanese text setting, Mincho typeface is most frequently used for main text, especially for long text. Similar to “serif” in Western typography.

Mono-ruby (モノルビ)

A method of ruby distribution where a run of ruby text is attached to each base character. (JIS Z 8125)

Naka tobira (中扉)

A recto or a page inserted to divide two different parts in a book. It often has a title or other text to describe the new part. (JIS Z 8125)

Nakatsuki (中付き)

A method of ruby character distribution where each ruby character is aligned to the vertical center of the corresponding base character in vertical writing mode, or to the horizontal center of the base character in horizontal writing mode. (JIS Z 8125)

Omotekei (表罫)

Thin width line. Usually about 0.12mm. (JIS Z 8125)

One-third-ruby / Sanbu rubi (三分ルビ)

Ruby characters, narrow enough so that three can fit within the width of a full-width base character.

Para-ruby (パラルビ)

A method of ruby annotation where ruby text is only attached to selected Kanji characters in the text. (JIS Z 8125)

Parallel note / Heiretsuchū (並列注)

Areas of notes are kept when the kihon-hanmen is designed. Related notes are set in these areas, with page unit or spread unit. Parallel-note is the general name for head note (in vertical writing mode), foot note (in vertical writing mode) and side note (in horizontal writing mode).

Proportional / Puropōshonaru (プロポーショナル)

A characteristic of a font where character advance is different per glyph. (JIS Z 8125)

Ruby (ルビ)

Supplementary small characters indicating pronunciation, meaning, etc. for the character or the block of characters they annotate. (JIS Z 8125) (Sometimes these annotations are referred to as “furigana.”)

Run-in heading / Dōgyōmidashi (同行見出し)

A kind of heading style to continue main text just after the heading without line break.

Sidenote / Bōchū (傍注)

A kind of notes, in vertical writing mode with spread unit, and related notes are set from the left end of left page with smaller size font than the main text. A kind of notes, in horizontal writing mode, the realm is kept beforhand in right side or fore-edge side of kihon-hanmen, and related notes are set in the realm with smaller size font than main text.

Small kana / Kogaki no kana (小書きの仮名)

Kana with smaller letter faces to be used mainly for representing contracted sounds or prolonged vowels. (JIS Z 8125)

Solid setting / Beta gumi (ベタ組)

To arrange characters with no inter-character space between adjacent character frames.

Tate-chu-yoko / Tate chū yoko (縦中横)

To typeset a (small) group of characters horizontally within a vertical line of main text, e.g. abbreviations, digits, etc.

Touyou Kanji Table / Tōyō kanji hyō (当用漢字表)

The official list of Kanji characters established in 1946, which was designed to restrict the Kanji characters for general use in society to only those 1850 specified in the list. The list together with other related tables was superseded by the Jouyou Kanji Table.

Tsumegumi (詰め組)

Adjustment of inter-character space by making the distance between the letter face of adjacent characters shorter than that produced by solid setting. (JIS Z 8125)

Unbreakable characters rule / Bunkatsu kinshi (分割禁止)

A line breaking rule that prohibits breaking a line between consecutive dashes or leaders, or between other specific combinations of characters.

Underline / Kasen (下線)

A line drawn under a character or a run of text in horizontal writing mode. (JIS Z 8125)

Urakei (裏罫)

Thick width line. Usually about 0.4mm. (JIS Z 8125)

Vertical writing mode / Tate gumi (縦組)

The process or the result of arranging characters on a line from top to bottom, of lines on a page from right to left, and/or of columns on a page from top to bottom. (JIS Z 8125)

Widow Adjustment / Danraku matsubi shori (段落末尾処理)

A method of line composition to adjust lines in a paragraph so that the last line consists of more than a given number of characters.

Features that were considered but not implemented

[Implementers’ doc] [WIP]

This document aims to list features that were considered but not implemented in ReadiumCSS, and clarify the reasons why they weren’t.

It is important to highlight that in most cases, features were not implemented because ReadiumCSS wasn’t the best way to handle them, not because they didn’t have strong use cases. If they were considered for implementation in the first place it is because they were useful, but ReadiumCSS couldn’t really implement them properly, or would have created issues for app developers, etc.

In other words, this document may also serve as a list of features you could choose to contribute in the various Readium SDKs and test apps if they aren’t already implemented.

Alternate background colors for lines (A11Y)

Related issue: #39

The idea was to add an alternate background-color to each line. Since CSS doesn’t have any concept of nth-line, you have to cheat and use a linear-gradient switching colors based on the current line-height.

Unfortunately, this doesn’t work well with fragmentation, and the linear gradient quickly becomes offset.

In addition, CSS is too limited to handle more complex cases such as images and, more generally, more complex structures. So you need JS for a good enough implementation.

Contrasting text against backgrounds in custom user themes

Related issue: #74

The idea was to handle the text color (using the calc() function) when the user picks a background color in custom themes. For instance, text would have been automatically inverted (white instead of black) with a dark background. Obviously, that wouldn’t have prevented the user from picking another text color.

However, implementing this feature in ReadiumCSS would have made it unpredictable for app developers. Indeed, it would have made it difficult for them to synchronize the User Interface, and label the correct text color as active.

This feature should therefore be implemented in the app, as part of the custom themes component.

Handle day/night theme based on OSs’ light/dark mode

Related issue: #75

The idea was to switch day/night theme based on the mode the user set in the Operating System’s preferences – using the prefers-color-scheme media query.

Once again, implementing this feature in ReadiumCSS would have made it unpredictable for app developers. Without any control over the application of themes, it would have been impossible to sync both the app UI and EPUB theme – resulting in a visible flash of unsynced content –, made it more difficult to handle the theme the user has set, etc.