Skip to content

ContentModifications

Daniel Weck edited this page Apr 22, 2016 · 28 revisions

WORK IN PROGRESS!

EPUB Content Modifications (CSS, DOM, Javascript, etc.)

To perform as a "reading system", Readium's underlying rendering / layout engine injects additional functionality ; such as styling ; into each EPUB content document that it loads (i.e. HTML, SVG).

This page of documentation aims to provide an accurate and exhaustive description of all the CSS, DOM and Javascript modifications that may affect authored content. This is meant to be read in a linear fashion (from top to bottom), as some background information presented at the beginning is not repeated further down.


Fixed layout (FXL)

"Page Blanche" EPUB sample

https://readium.firebaseapp.com/?epub=epub_content%2Fpage-blanche

Note that the above link points to Readium's online "cloud reader". This is the default deployment URL at Firebase, which is the static hosting service currently used for continuous integration of the application builds generated from the develop branches of the ReadiumJS GitHub repositories.

There is an alternate app deployment URL at Surge:

https://readium.surge.sh/?epub=https%3A%2F%2Freadium.firebaseapp.com%2Fepub_content%2Fpage-blanche

Also note that the offline Chrome extension provides near-identical functionality to the online cloud reader (they are both based off the same source code):

https://chrome.google.com/webstore/detail/readium/fepbnnnkkadjhjahcafoaglimekefifl

Layout

With pre-paginated ebooks, each spine item (i.e. HTML or SVG content document) corresponds to a single page. Each HTML page declares its intrinsic dimensions using the "viewport" metadata, for example: html > head > meta @name="viewport" @content="width=1024, height=768". The pages may be displayed on their own, or side-by-side as part of a page spread, or even as a full vertical sequence of pages when the scroll layout is enabled ("continuous" view mode). Irrespective of the rendering mode, each page is hosted in an HTML iframe. Each frame "sandbox" defines the scope of authored styling and scripted behaviors, for one particular HTML / SVG document. From each frame, Readium captures a number of user events in order to perform its reading system logic, see sections down below about keyboard handling and pointing devices.

Styling

By definition, fixed-layout ebooks (aka "pre-paginated" EPUB3) are geared towards visual fidelity, so reading systems are expected to preserve the original layout and styling rules specified by content creators. Readium does not inject any user-defined style preferences in FXL documents, unlike reflowable publications where authored CSS can be overridden, e.g. font-size, line-height, color scheme, etc.

Scaling

By default, Readium displays pages so that they fit entirely within the visible viewport, while preserving the aspect ratio. In other words, wide/tall pages must be scaled down, and ; conversely ; narrow/short pages must be scaled up in order to fit the available screen real estate. Users can choose to display pages at any arbitrary scaling (100% = original dimensions, 200% = twice as large, 50% = half the size, etc.). When the page become larger than the visible viewport, the view can be scrolled / panned.

The actual page scaling is implemented on the HTML root element of each spine item document, using the style attribute to apply a CSS transform:

transform: scale(0.5);
transform-origin: 0px 0px 0px;

opacity: 1;

There is an additional opacity rule to handle the page transition from hidden to visible. No actual fading visual effects are applied, this is just Readium's internal implementation detail.

In more recent Readium versions, there are also min-width and min-height rules matching the unscaled width and height values of the "viewport" meta, to address rendering bugs (surface clipping) in some web browsers, with content that uses some combination of DOM containers and CSS absolute positioning rules.

min-width: 1024px;
min-height: 768px;

Furthermore, Readium applies the "viewport" dimensions to the body element (also via a style attribute), to ensure correct measurements (see http://www.idpf.org/epub/31/spec/epub-contentdocs.html#sec-fxl-icb-html).

width: 1024px;
height: 768px;

Reflow

"Accessible EPUB3" ebook sample

https://readium.firebaseapp.com/?epub=epub_content%2Faccessible_epub_3

Alternate URL:

https://readium.surge.sh/?epub=https%3A%2F%2Freadium.firebaseapp.com%2Fepub_content%2Faccessible_epub_3

Layout

Just as with fixed-layout ebooks, reflowable documents (i.e. HTML spine items) are individually hosted in HTML iframes. However, in this case a two-page spread is in fact the result of applying a pagination technique inside a single iframe (whereas FXL synthetic spreads effectively consist in two consecutive iframes). Readium can also display a vertical sequence of full-height iframes/documents when the scroll layout is enabled ("continuous" view mode), in which case the internal pagination technique is not applied. Irrespective of the rendering mode, each HTML iframe "sandbox" defines the scope of authored styling and scripted behaviors, for one particular HTML document. From each frame, Readium captures a number of user events in order to perform its reading system logic, see sections down below about keyboard handling and pointing devices.

Styling

It is commonly accepted that with reflowable ebooks, users are given some degree of control over the contents' visual presentation. In other words, authored styles may effectively be overridden by user preferences. Readium currently allows users to change the font size (which automatically adjusts the line height too), and there are predefined color schemes (including a dark one / "night" mode).

Readium's current implementation specifically targets the following HTML markup elements: p, div, span, h1, h2, h3, h4, h5, h6, li, blockquote, td, and pre. The font-size and line-height CSS is applied via the style attribute. In addition, the following attributes are inserted in in the DOM to record the original computed style: data-original-font-size and data-original-line-height. Note that this styling technique may change in a future revision of Readium.

As for "themes", Readium currently changes the foreground and background colors of the body element via the style attribute. For example:

color: rgb(255, 255, 255);
background-color: rgb(20, 20, 20);

Dynamic pagination

Readium utilizes CSS columns to present reflowable documents in a paginated fashion. Each column effectively corresponds to a page, and depending on font size, line height (etc.) the HTML document requires a specific number of columns to be fully laid (i.e. total page count for a given spine item). Readium relies entirely on the web browser (or webview component) to return the correct information about columns allocation, but Readium's pagination engine does have to ensure that the total number of columns is queried only once the document is fully rendered (including all CSS styles, processing of media queries, acquisition of font faces, transformation + presentation of MathML, etc.)

The net result is that:

  1. the body element of HTML content documents receives additional CSS in the style attribute, to reset the margin and padding:
margin: 0px;
padding: 0px;
  1. the html element is where CSS columns are created (note that margin and padding are also reset here):
margin: 0px;
padding: 0px;
border: 0px;

font-size: 100%;

opacity: 1;

position: relative;
left: 0px;
top: 0px;
width: 1160px;
height: 806px;

min-height: 806px;
max-height: 806px;

column-gap: 60px;

column-width: auto;
column-count: 2;

Note that there is a slight difference in the column values when single-page mode is enabled (versus the two-page spread view):

column-width: 550px;
column-count: auto; 

Optimal page width

The pagination engine lays columns of text based on a predefined page width (which is configurable in Readium's latest version), so that runs of text / numbers of characters per line does not exceed a reasonable value (as this would otherwise affect readability). Blank space on the left and right sides of the content viewport can become quite wide when the web browser window is maximized on a large display. Users can choose to disable the width limitation, if they wish to use the entire horizontal screen real estate.

Note that in Readium's current version, the scroll-view mode does not apply any width limitation: the text always stretches horizontally to occupy the maximum available space. This behaviour may change in a future version of Readium to harmonize with the design of the paginated view.

Image resizing

At the time of writing, Readium applies simple styling rules (via the style attribute) to images that are rendered within CSS columns (i.e. dynamic reflowable pages). The desired goal is to ensure that images fit vertically and horizontally within a given column of document text, without overlap / overflow into the next page. There are known issues with the current trivial approach:

max-width: 98%;
max-height: 98%;

height: auto;
width: auto;

EPUB3 Media Overlays

The visually-highlighted synchronization of the text structure with audio clips requires the insertion of CSS styles and classes into the document markup. As per the EPUB3 specification, authors can specify the CSS class name to be injected in the currently-playing element, and the one that gets applied to the root html element of the playing HTML document (authors are expected to define the associated styles within the publication). In the absence of such class declaration in the Media Overlays metadata, Readium's default class name is mo-active-default, and the associated style is:

background-color: yellow !important;
color: black !important;
border-radius: 0.4em;

Readium also allows users to enforce their own choice of style from a predefined set of options, such as:

background-color: yellow !important;
color: black !important;
border-color: transparent !important;
border-radius: 0.4em !important;
box-shadow: 0px 0px 0.4em #333333 !important

MathML and MathJax

Readium inserts the MathJax script in each HTML document that contains MathML markup. The MathML fragments are processed by MathJax and are converted to SVG. MathJax uses its own set of styles, and injects a number of additional fragments in the DOM. There are no external font dependencies. All glyphs are SVG paths. MathJax is configured with accessibility support, so keyboard interaction is handled appropriately (e.g. tab and arrow key navigation).

navigator.epubReadingSystem

As per the EPUB3 specification, Readium injects the navigator.epubReadingSystem object into each loading HTML document (including nested iframes). Readium-specific properties are exposed through navigator.epubReadingSystem.readium.buildInfo to record build / version information (based on Git repository data). Here is a "special" EPUB that displays this information via Javascript: https://readium.firebaseapp.com/?epub=epub_content%2FepubReadingSystem

Annotation highlights

This is currently an experimental feature in Readium (enabled in "development" builds only). A stylesheet element is inserted in the head of each HTML document, to reference a Readium-supplied CSS file (annotation.css). The highlights generated by Readium (based on user text selections) consist in absolutely-positioned div elements that overlay the text using a semi-transparent color. The CSS class .rd-highlight is used in combination with (in this experimental version) .test-highlight and .hover-test-highlight (by default, a red hue).

.rd-highlight.test-highlight {
    position: absolute;
    opacity: 0.2;
    background-color: red;
}

.rd-highlight.hover-test-highlight {
    position: absolute;
    opacity: 0.4;
    background-color: red;
}

Hyperlinking

Authored links are processed by Readium so that the appropriate redirection is performed. For example, external links are opened in a new web browser window or tab. Internal links ; such as chapter1.html#heading2 ; are converted by Readium's navigation mechanism to load the correct spine item, page offset, etc.

Keyboard handling

Readium forwards keyboard events emitted within iframes (i.e. content viewports) to the application's chrome, in order to trigger navigation / interaction commands. More information here: https://github.com/readium/readium-js-viewer/wiki/Keyboard

PS: there are known issues due to how Readium intercepts and prioritizes keyboard input (actual behaviour depends on the platform / web browser). This will be addressed in a future release.

Pointing device (mouse, touch, etc.)

The touch handler is currently disabled in Readium. Previous versions used to intercept swipe gestures within iframes (i.e. content viewports) in order to trigger page navigation commands.

Popup footnotes

There is experimental support for popup footnotes in Readium, not currently publicly available. The basic design principle is to hide note content (e.g. an aside DOM fragment), and to display this content upon explicit user interaction / link activation. The current prototype implementation uses a modal popup dialog to render the extracted note fragment, rather than a callout that would be visually-aligned with the source hyperlink (akin to a "speech bubble"). The modal dialog offers better accessibility, at the cost of the loss of styling for note content that contains rich CSS.