install
source · Clone the upstream repo
git clone https://github.com/openclaw/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/bartok9/pdf-generation" ~/.claude/skills/openclaw-skills-pdf-generation && rm -rf "$T"
OpenClaw · Install into ~/.openclaw/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.openclaw/skills && cp -r "$T/skills/bartok9/pdf-generation" ~/.openclaw/skills/openclaw-skills-pdf-generation && rm -rf "$T"
manifest:
skills/bartok9/pdf-generation/SKILL.mdsource content
PDF Generation Skill
Purpose: Generate professional PDFs from HTML/CSS without whitespace gaps or layout issues.
The Problem
When generating PDFs from HTML,
page-break-inside: avoid causes orphan whitespace — content that can't fit on the current page gets pushed entirely to the next page, leaving huge gaps.
The Solution
1. Use Flow-Based Layout (NOT Fixed Page Containers)
❌ WRONG:
<div class="page" style="min-height: 297mm;"> <!-- Content --> </div>
✅ RIGHT:
<body> <!-- Content flows naturally --> </body>
Use
@page CSS rules instead of fixed page containers:
@page { size: A4; margin: 18mm 15mm; }
2. Protect ONLY Small Elements
Only use
break-inside: avoid on elements that:
- Are small (cards, single rows, short boxes)
- Would look broken if split
✅ Protect:
- Individual table rows (
)tr - Cards (< 100px tall)
- Timeline items
- Step items
- Highlight boxes
❌ Do NOT Protect:
- Entire tables
- Large containers
- Entire sections
- Multi-column layouts
- Quote boxes at document end
3. Use Modern + Legacy Properties
.small-element { break-inside: avoid; /* Modern spec */ page-break-inside: avoid; /* Legacy support */ }
4. Keep Headers With Content
h2, h3, h4, .section-header { break-after: avoid; page-break-after: avoid; }
5. Prevent Orphan Lines
body { orphans: 3; /* Min lines at bottom of page */ widows: 3; /* Min lines at top of page */ }
6. Allow Tables to Break (But Keep Rows Together)
table { /* NO break-inside: avoid */ } tr { break-inside: avoid; page-break-inside: avoid; }
Template
@page { size: A4; margin: 18mm 15mm; } body { font-size: 10pt; line-height: 1.5; orphans: 3; widows: 3; } /* Headers stay with content */ h2, h3, h4 { break-after: avoid; page-break-after: avoid; } /* Small elements don't break */ .card, .highlight-box, .step, .timeline-item { break-inside: avoid; page-break-inside: avoid; } /* Table rows stay together, table can break */ tr { break-inside: avoid; page-break-inside: avoid; } /* Large containers flow naturally */ table, .section, .two-col { /* NO break-inside: avoid */ } @media print { body { -webkit-print-color-adjust: exact; print-color-adjust: exact; } }
Tools
| Tool | Use Case | Install |
|---|---|---|
| WeasyPrint | HTML/CSS → PDF (best CSS support) | or |
| Pandoc | Markdown → PDF via LaTeX | |
| wkhtmltopdf | Complex layouts | Download from wkhtmltopdf.org |
| Puppeteer | JS-rendered content | |
WeasyPrint Command
weasyprint input.html output.pdf
Pre-Flight Checklist
Before sending ANY PDF:
- Open in PDF viewer, scroll through ALL pages
- Check for large whitespace gaps between content
- Ensure no single-line orphans at page tops
- Verify tables don't have awkward mid-row breaks
- Confirm headers are followed by content (not at page bottom alone)
Common Mistakes
| Mistake | Fix |
|---|---|
on large containers | Remove it, let content flow |
| Fixed-height page divs | Use rules instead |
| Quote box at document end with break protection | Remove break protection |
| Entire table protected from breaking | Only protect , not |
No / set | Add |
Resources
- WeasyPrint docs: https://doc.courtbouillon.org/weasyprint/
- CSS Paged Media: https://www.w3.org/TR/css-page-3/
- Print CSS Guide: https://www.smashingmagazine.com/2018/05/print-stylesheets-in-2018/
Skill created by Bartok — March 6, 2026