Marked 3 print/PDF — large vertical gaps ("vertical justification") on under-full pages

Viewed 29

Long-time Marked user and fan here — it's been part of my daily writing workflow for years. After moving to Marked 3 I ran into a print/PDF template behaviour I wanted to document, in case others hit it too.

Environment: Marked 3.1.12, macOS, direct (non-MAS) build. Custom preview style based on Lopash. MultiMarkdown processor (though the behaviour below is the same across all four processors).

Main issue — content stretched vertically to fill under-full pages.
When a page doesn't fill completely, the paginator seems to distribute the content vertically to fill it: large gaps open up between blocks, and a heading can end up floated to the middle or bottom of an otherwise near-empty page — instead of the leftover whitespace simply falling at the bottom of the page.

  • It's most pronounced right before a heading that's followed by a large table.
  • Marked 2 doesn't do this (same document renders with normal bottom-of-page whitespace).
  • Adding manual <!--BREAK-->s makes it worse, not better — each break creates another partially-filled page for the effect to act on. (Measured on one ~9-page document: one targeted break helped, but a break before every top-level section took it to 13 pages with gaps up to ~580pt.)

Two smaller things noticed while tuning the custom print style:

  1. PDF export of a custom style appears to render in screen media — so @media print, page-break-*, orphans and widows rules in the stylesheet are ignored, and pagination can't be steered from CSS. (.mkprinting class rules do apply, which is how I styled everything else.)
  2. SVG diagrams exported from D2 / OmniGraffle (which use <foreignObject> and external font url()s) render blank when embedded via <img>; the PNG equivalents display fine.

None of this is urgent, and I remain a big fan — just wanted to pass it along in case it's useful. Happy to share a sample document or example exports. Thanks for making such a wonderful tool!

All the best,
Johan

1 Answers

Thanks Brett — great to hear it's on your radar, and your explanation matches what I measured (the gaps always appear around a table or image that got bumped to the next page). Thanks also for confirming .mkprinting + screen rules is the intended mechanism.

I've attached a zip with my stylesheet, example documents and diagrams (README inside has the details and settings). Two separate repros in it:

1. The pagination gapsexample-document.md: prose sections where a heading is immediately followed by a table sized to fit a page but not the leftover space. Exporting a paginated PDF reliably produces gaps on the pages where a table was moved (typical: a ~130 pt gap right after a stranded heading, and a page with ~440 pt of empty tail). One detail that may help: near-page-height tables just split between rows and do not trigger it — the trigger zone is tables that fit a fresh page whole.

2. Something bigger we found while building the repro: the paginated export can run before the document has finished loading, and silently produces corrupted PDFs. If the export is triggered a few seconds after opening a document (easiest to hit while other image-heavy documents are also still loading), we get — with no error shown:

  • silently truncated exports (a 6-page document comes out as ~2 pages),
  • missing images (SVG and PNG absent from the PDF while the preview shows them),
  • and on one real document of mine, 6-out-of-6 reproducible: link text URL-encoded into a table cell (%20…%C2%A7… soup), a whole section swallowed, page count 6 → 4. That document is internal so it's not in the zip, but I'm happy to share it privately if useful, and race-document.md in the zip is a width-preserving anonymized clone of it (same layout, gibberish words) with the timing recipe in the README.

The isolating observation: at the same moment the paginated export corrupts, a continuous PDF export of the same document is complete and correct — so this looks specific to the paginated pipeline snapshotting the document before it has settled.

I suspect this race also explains my earlier "SVG renders blank via <img>" report: SVGs (with foreignObject + embedded fonts) load slower than PNGs, so an early export catches the SVG missing while the PNG made it. That would explain why it seemed machine-dependent — it's load-speed-dependent.

Happy to test builds or run more measurements — I've got a PyMuPDF script that detects the gaps and the truncation programmatically.

— Johancompact-print-repro.zip