Vivliostyle
Vivliostyle is an open-source CSS typesetting engine (AGPL-3.0) built on the full CSS Paged Media specification. It covers the same core features as Paged.js — running headers, cross-references, facing pages — and additionally supports complex book layouts, EPUB output, and vertical writing modes.
Unlike Paged.js, which transforms the document in-place with a single script tag, Vivliostyle uses a viewer approach: you provide a content HTML file and a separate wrapper page that loads the engine. PolyDoc captures the rendered output from that wrapper.
Setup
Content document
Keep all CSS Paged Media rules in the content HTML file. This is the document Vivliostyle will typeset.
<!-- content.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
@page {
size: A4; margin: 2.5cm 2cm;
@top-center { content: string(chapter); font-size: 9pt; color: #888; }
@bottom-center { content: counter(page) " / " counter(pages); font-size: 9pt; }
}
h1 { string-set: chapter content(); break-before: page; }
</style>
</head>
<body>
<h1 style="break-before: auto">Introduction</h1>
<p>Your content here...</p>
</body>
</html>
Viewer page
The viewer page loads the Vivliostyle Core engine and signals PolyDoc when rendering is complete via a
data-* attribute.<!-- viewer.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>body { margin: 0; } #viewer { width: 100%; height: 100vh; }</style>
</head>
<body>
<div id="viewer"></div>
<script src="https://unpkg.com/@vivliostyle/core/lib/vivliostyle.min.js"></script>
<script>
const viewer = new vivliostyle.CoreViewer({
viewportElement: document.getElementById("viewer"),
});
viewer.addListener("readystatechange", () => {
if (viewer.readyState === "complete") {
document.body.setAttribute("data-vivliostyle-ready", "true");
}
});
viewer.loadDocument("https://your-server.com/content.html");
</script>
</body>
</html>
API request
{
"source": "https://your-server.com/viewer.html",
"render": {
"waitForFunction": "document.body.getAttribute('data-vivliostyle-ready') === 'true'",
"mediaType": "screen"
},
"layout": {
"preferCSSPageSize": true
},
"timeout": 120
}
Features
Dynamic headers
Vivliostyle supports both
string-set / string() for text-only content, and the running() / element() approach that pulls a full DOM element — including images or styled markup — into a margin box. Both are for dynamic headers that change per section; static page numbers are already covered by PolyDoc templates./* Option A: text-only running string */
h1 { string-set: chapter content(); }
@page { @top-center { content: string(chapter); font-size: 9pt; } }
/* Option B: pull a full element (e.g. with a logo) into the header */
.running-header { position: running(header); }
@page { @top-center { content: element(header); } }
Cross-references
target-counter() resolves to the page number of the linked element. Use it to build tables of contents or "see page X" references that always stay in sync with the document layout..toc a::after {
content: leader(".") " " target-counter(attr(href url), page);
}
Facing pages
:left and :right pseudo-classes give even and odd pages different margins, which is essential for double-sided printing where the spine side needs extra space. Use case: books, reports, legal documents intended for binding.@page :left { margin-left: 2.5cm; margin-right: 1.5cm; }
@page :right { margin-left: 1.5cm; margin-right: 2.5cm; }
Advanced layout
Vivliostyle supports CSS multi-column layout across paginated output, and vertical writing modes for CJK typesetting — features that go beyond what Paged.js currently covers. Use case: magazines, academic journals, Japanese or Chinese publications.
/* Magazine-style two-column body text */
.article-body {
column-count: 2;
column-gap: 1.5cm;
}
/* Vertical writing (Japanese, Chinese) */
body { writing-mode: vertical-rl; }
@page { size: A5; }
Paged.js vs Vivliostyle
Both libraries cover the same core CSS Paged Media features. The main differences are setup complexity, DOM impact, and a few specialised capabilities at each end.
| Aspect | Paged.js | Vivliostyle |
|---|---|---|
| Integration | Single script tag in your HTML | Separate viewer page + hosted content |
| License | MIT | AGPL-3.0 |
| DOM impact | Heavy — rewrites entire document | Isolated viewer container |
| Bleeds & crop marks | ✓ | Partial |
| EPUB / vertical writing | – | ✓ |