Skip to content

jaywoo0830a/htmlasitis

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

htmlasitis

A4 print-safe CSS library for HTML books.

Guarantee: one .hai-page section becomes exactly one printed A4 page. No overflow. No empty pages. No widow page numbers.

Tested against the Chromium print engine (Chrome, Edge, Brave, Opera).

Why this library exists

Browsers were not built for books. They were built for documents that scroll forever. When you try to print HTML to A4 sheets, the browser makes its own decisions about how to break content across pages, and those decisions are usually wrong:

  • Headings get orphaned at the bottom of pages
  • Tables split across page boundaries
  • Page numbers jump to the next page alone
  • Content overflows silently and creates extra pages

This library enforces a simple rule that solves all of these problems: each .hai-page section is exactly one printed page. If your content does not fit, it gets clipped, and you find out immediately when you run the validation script.

This trades flexibility for predictability. That is the right trade for books.

Quick start

# 1. Set up the environment (run once)
./run/init.sh

# 2. Edit example.html or copy template.html to start a new book

# 3. Preview in a browser
./run/dev.sh
# Open http://localhost:8000/example.html

# 4. Validate that page counts match
./run/test.sh example.html

If the test passes, your book prints exactly. If it fails, the script tells you how many extra pages were created and where to look.

How to use the library

Minimum HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="htmlasitis.css">
</head>
<body>

  <section class="hai-page">
    <h1>Your Chapter Title</h1>
    <p>Your content...</p>
    <div class="hai-page-number">— 1 —</div>
  </section>

</body>
</html>

That is it. Wrap each printed page in <section class="hai-page">. The library handles the rest.

Components

All components are documented with a content budget — roughly how much text fits when you use that component on a page.

.hai-page (required)

The fundamental unit. Each one is exactly 210mm × 297mm with 18mm horizontal and 20mm vertical padding. Content area: 174mm × 257mm.

Content budget: about 1800 characters of body text alone, less when you add other components.

.hai-cover

Combine with .hai-page to make a book cover. Centers content vertically with flexbox.

<section class="hai-page hai-cover">
  <div class="hai-cover-volume">Volume 1</div>
  <h1>Book Title</h1>
  <div class="hai-cover-subtitle">Subtitle here</div>
  <div class="hai-cover-author">Author · Year</div>
</section>

.hai-divider

A part divider page. Like cover, but for sections within a book.

<section class="hai-page hai-divider">
  <h1>Part Two</h1>
  <div class="hai-divider-subtitle">The subtitle of this part</div>
</section>

.hai-page-number

A page number pinned to the bottom of the page. Uses absolute positioning, so it always sits 12mm from the bottom regardless of content above it.

<div class="hai-page-number">— 42 —</div>

.hai-callout

A bordered box for emphasizing one key insight per page.

<div class="hai-callout">
  The most useful constraint is the one that tells you when you
  have written too much.
</div>

Content budget cost: about 200 characters less of body text.

.hai-example, .hai-example-good, .hai-example-bad

Boxes for showing examples, optionally framed as good or bad.

<div class="hai-example hai-example-bad">
  <div class="hai-example-label">BEFORE</div>
  An example of what not to do.
</div>

<div class="hai-example hai-example-good">
  <div class="hai-example-label">AFTER</div>
  An example of what to do instead.
</div>

Content budget cost: about 150 characters per example.

.hai-annotation

A side note. Like a callout but with a left border instead of a full border. Less prominent.

<div class="hai-annotation">
  <div class="hai-annotation-label">NOTE</div>
  An aside that supplements the main text.
</div>

Content guidelines

The library enforces page boundaries. It cannot enforce content density. That is your job. Here are the budgets:

Page composition Body text budget
H1 + body text only ~1500 characters
H1 + H2 (×2) + body text ~1300 characters
H1 + 1 callout + body text ~1300 characters
H1 + 1 small table + body text ~1000 characters
H1 + 1 code block + body text ~1100 characters
H1 + 2 example boxes + body text ~1200 characters
Pure body text (no H1) ~1800 characters

These are at the default font size (11pt) and line height (1.55). If you change those, the budgets change.

How to write to budget:

  1. Draft your chapter in plain text first
  2. Count characters: wc -m chapter.txt (or use word count in your editor)
  3. Divide by your budget to estimate page count
  4. Split your text into sections of roughly that size
  5. Each section becomes one .hai-page

When in doubt, run the test. If the validation passes, you are within budget.

How to write a book that prints cleanly

These are practical rules that emerge from working within the library's constraints:

1. One topic per page

A .hai-page is a unit of attention. Treat it as one idea, one argument, one example. If you find yourself wanting to put two unrelated topics on one page, split them.

2. End on a complete thought

Because pages cannot overflow, your last paragraph must finish within the page. Plan your final sentence as you write — do not let it become a half-thought because you ran out of space.

3. Use page numbers consistently

Every content page should have a .hai-page-number. Cover and divider pages do not. Number from page 2 onward (the page after the cover).

4. Test early, test often

Run ./run/test.sh whenever you finish a draft of a chapter. The test runs in seconds and catches overflow problems before they compound.

5. Treat overflow as a writing prompt

When the validation fails, do not just delete words to fit. Ask what the overflow is telling you about the chapter. Often it means you have two ideas crammed into one page, and they want to be two pages.

6. Keep typography stable

Avoid changing font sizes mid-book. Each typography change shifts your content budget for that page. The CSS variables let you theme the whole book once at the top — use that, do not override in individual pages.

Theming with CSS variables

All visual properties are CSS variables defined in :root. Override them at the top of your HTML to theme your whole book at once:

<style>
  :root {
    --hai-font-body: "Your Font", sans-serif;
    --hai-font-mono: "Your Mono Font", monospace;
    --hai-font-size-body: 12pt;
    --hai-line-height-body: 1.6;
  }
</style>

See htmlasitis.css for the full list of variables.

Note that changing font size or line height changes your content budget per page. Re-run validation after any theming change.

How the library works under the hood

A short tour of the engineering:

@page { margin: 0 }

Browsers add their own margins to printed pages by default (about 9.5mm in Chromium). We disable that and use .hai-page padding to create margins. This gives us per-page control and defeats browser defaults that would shift our layout.

Fixed .hai-page dimensions

Each page is exactly 210mm × 297mm with padding: 20mm 18mm. This is not responsive — it is intentionally rigid. The content area is precisely 174mm × 257mm, every time.

overflow: hidden on .hai-page

This is the core trick. It clips content that exceeds the page. Without this, the browser would helpfully flow content to a new page and create an empty page after each overflow. With this, overflow becomes visible (clipped content) and detectable (failed test).

break-after: page for page boundaries

Each .hai-page ends with a forced page break. The legacy page-break-after: always is included alongside for compatibility.

print-color-adjust: exact

By default, browsers do not print background colors to save ink. We force exact color rendering for callouts, code blocks, and table headers, so the printed book looks like the screen book. Users no longer need to enable "Background graphics" in the print dialog.

Heading cohesion via break-after: avoid

Headings cannot end up alone at the bottom of a page. The browser will pull them onto the next page with their following content if needed. (This rarely matters within a .hai-page because it cannot break, but it matters if you nest content in unusual ways.)

Validation script details

./run/test.sh does three things:

  1. Renders the HTML file to PDF using headless Chromium
  2. Counts <section class="hai-page"> in the source
  3. Compares to the page count of the generated PDF

If the counts match, your book prints predictably. If they do not, some content overflowed and created extra pages.

The script accepts any HTML file as an argument:

./run/test.sh my-book.html
./run/test.sh chapters/chapter-3.html

Browser support

Browser Engine Status
Chrome Chromium Tested, works
Edge Chromium Tested, works
Brave Chromium Tested, works
Opera Chromium Should work
Firefox Gecko Most features work, some edge cases differ
Safari WebKit print-color-adjust works, otherwise less tested

The library is primarily targeted at Chromium because of its strong print CSS support and predictable behavior. Validation requires Playwright with Chromium.

Browser print dialog settings

The library is designed to print correctly with default print dialog settings:

  • Paper size: A4 (matches CSS @page size: A4)
  • Margins: any setting works, because we use @page margin: 0 and create margins via .hai-page padding
  • Background graphics: any setting works, because we force background printing with print-color-adjust: exact
  • Headers and footers: should be off — turn this off in the print dialog so the browser does not add its own page numbers on top of yours

The only setting that matters: turn Headers and footers off.

Files in this library

htmlasitis/
├── README.md              This file
├── htmlasitis.css         The CSS library
├── template.html          Minimal starting point for new books
├── example.html           Demonstrates all components
├── overflow-test.html     Verifies clipping behavior
└── run/
    ├── init.sh            Install Playwright + Chromium
    ├── test.sh            Validate page counts
    └── dev.sh             Run local server for preview

License

Use it however you want. Ship books.

About

htmlasitis

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors