Viewport
The viewport is the visible reading area. It is not to be confused with pagination and navigation.
Purpose of a viewport
Section titled “Purpose of a viewport”The purpose of the viewport is to allow more flexibility in how and what are visible to the user while maintaining stable calculations internally. The pagination and navigation are two of the hardest things to get right in a reader and they need to have stable measures to do so. An extra layer as such allows decoupling the "view" from the "rendering".
For example, zooming out (thumbnails) or in is much easier when manipulating the viewport since you don't mess up with documents or the layout itself. You can imagine the viewport as a virtual layer that can be transformed without affecting the behavior of the engine.
The viewport can be for example wrapped within a scroll navigator and thus take the scrollbar width into account. As a result the entire reader will be updated accordingly to follow the new viewport.
Recommendations and precautions
Section titled “Recommendations and precautions”To avoid conflict between features and undesired behaviors here is a list of recommendations when manipulating or using the viewport:
- Avoid setting style directly on the element. You may inadvertently revert the change of another feature. Prefer using css classes for example and take advantage of inheritance.
- Avoid negative margins
- Avoid mutating the viewport at different places, try to keep a single place of responsibility (or enhancer) to set your viewport.
- Remember to
layout()if you change the viewport style.
Adjusting size, margin, etc
Section titled “Adjusting size, margin, etc”A relatively simple manipulation of the viewport can be to change its size and margin. For example to make more items visible when scrolling. Refit enhancer is a good example taking advantage of the viewport resizing.


Spread mode
Section titled “Spread mode”A spread shows two pages side by side. The spreadMode setting says when you want one:
auto(the default): from the viewport's size and the book'srendition:spread. In landscape (wider than tall), pages pair into spreads unless the book asks fornoneorportrait. In portrait, pages pair only when the book asks forportrait.always: in every orientation.never: one page at a time.
The setting only decides within what the book allows. A book whose rendition:spread is none is never shown in a spread, since the EPUB specification forbids it, and neither is a book whose rendition:flow is scrolled-continuous.
const reader = createReader({ manifest, spreadMode: "never" })
reader.settings.update({ spreadMode: "always" }) // lays the book out againThe viewport resolves the setting in every layout, in the same measurement as the size and the page size, so what it shows only changes during a layout. The setting reads back as you gave it. What the reader actually shows is in the viewport's state:
reader.settings.values.spreadMode // "auto", "always" or "never", as you set itreader.viewport.value.isSpread // true while two pages share the viewport
reader.viewport.watch("isSpread").subscribe((isSpread) => { // emits the current value, then again whenever a layout changes it})To know what a viewport of another size would show, for example after the device rotates, ask the viewport. It applies the rule every layout applies, for the book and the current setting:
const rotatedWouldSpread = reader.viewport.wouldSpreadAt({ width: reader.viewport.value.height, height: reader.viewport.value.width,})Whether the book can be shown in a spread at all is in the context. When it can't, the setting changes nothing for it, so a settings screen can disable its spread choice:
reader.context.value.isSpreadAllowed // false for a `none` spread or a `scrolled-continuous` flowAbsolute vs Relative viewport
Section titled “Absolute vs Relative viewport”The absolute viewport represents the dimensions given when creating the reader and is the dimension used internally for pagination, navigation and all the calculations. The relative viewport represents the viewing area after transformations are applied.

