Skip to main content

Best Practices

Quick Reference​

CategoryRecommendedUse with CautionAvoid
HTMLSemantic HTMLGeneric <div>Deep nested <div> structures
LayoutBlock layoutSimple FlexboxComplex Grid or deeply nested Flexbox
TablesNative <table>Small Flex layoutsRecreating tables using <div>
Header/FooterRunning elementsMargin box generated contentDuplicated HTML on every page
Paginationbreak-before, break-after, break-insideManual page breaksSpacer elements for page positioning
PositioningNormal document flowSmall position: relative adjustmentsposition: absolute for page layout
HeightsAuto / min-heightFixed height for known contentFixed height with dynamic content
ImagesSVGHigh-resolution PNGLow-resolution images
FontsEmbedded fontsSystem fontsAssuming fonts exist on the server
EffectsBorders, background colorsBorder radiusfilter, clip-path, backdrop-filter

1. HTML Structure​

<body>
<header class="report-header"></header>

<main>
<section>...</section>
</main>

<footer class="report-footer"></footer>
</body>

Guidelines​

  • Use semantic elements.

  • Group content into logical sections.

  • Keep nesting shallow.

Prefer

body
├── header
├── main
│ ├── section
│ └── section
└── footer

Avoid

div
└── div
└── div
└── div
└── div

2. Layout Guidelines​

Layout Decision Order​

When implementing a layout, choose the first option that satisfies the design.

Need a layout?

│
├── Normal document?
│ │
│ └── Block Layout
│
├── Horizontal alignment?
│ │
│ └── Simple Flexbox
│
├── Tabular data?
│ │
│ └── HTML Table
│
├── Dashboard/Grid?
│ │
│ └── Grid (only after testing)
│
└── Complex overlapping layout?
│
└── Redesign the layout

3. Layout​

Block Layout​

Preferred Most documents can be built using normal block flow.

Example

Heading

Paragraph

Paragraph

Table

Summary

Advantages

  • Predictable pagination
  • Easier maintenance
  • Better rendering consistency

Flexbox​

Use with caution Flexbox support has improved significantly in recent versions of WeasyPrint, but layouts involving pagination or nested flex containers should always be tested.

Recommended

Logo Company

Label Value

Customer Invoice

Good use cases

  • Header
  • Footer
  • Two-column rows
  • Label-value pairs
  • Navigation-like horizontal alignment

Avoid multi-level nested flexbox

Flex
└── Flex
└── Flex
└── Flex

Grid​

Avoid complex grid, use only when necessary Grid support continues to improve, but it is still less mature than block layout.

Grid is acceptable when

  • Layout is static.
  • No pagination occurs inside grid items.
  • The layout has been thoroughly tested.

Avoid Grid for

  • Dashboard pages
  • Complex reports
  • Nested grids
  • Responsive-style layouts

If Flexbox or block layout can achieve the same result, prefer those approaches.


4. Page Layout​

Always define page settings.

@page {
size: A4;

margin: 20mm;
}

Never rely on browser defaults.

More details about @page layout can be found here.


5. Headers & Footers​

Recommended

.report-header {
position: running(header);
}

.report-footer {
position: running(footer);
}
@page {
@top-center {
content: element(header);
}

@bottom-center {
content: element(footer);
}
}

Benefits

  • Single source of truth
  • Easier maintenance
  • No duplicated HTML

More details about configuring header and footer can be found here.


6. Margin Boxes​

Suitable for lightweight generated content.

@page {
@top-left {
content: 'Monthly Report';
}
}

Typical uses

  • Document title
  • Page number
  • Company name

Avoid placing complex layouts inside margin boxes.

More details about configuring margin boxes can be found here.


7. Named Strings​

Named strings are recommended for dynamic running headers.

/* 1. Extract the text from the heading and save it into a variable named "chapter" */
h1 {
string-set: chapter content();
}

/* 2. Retrieve that text and display it in the top-right corner of every printed page */
@page {
@top-right {
content: string(chapter);
}
}

Result

Page 1

Customer

-----------------

Page 2

Inventory

-----------------

Page 3

Financial Summary

8. Counters​

Use counters for automatic numbering.

content: counter(page);

Page X of Y

content: counter(page) ' / ' counter(pages);

Section numbering

h2 {
counter-increment: chapter;
}

h2::before {
content: counter(chapter) '. ';
}

More details about counter can be found here.


9. Pagination​

Recommended

.section {
break-before: page;
}
.card {
break-inside: avoid;
}

Keep together

  • Heading + paragraph
  • Table header + first row
  • Card content
  • Images with captions

More details about pagination can be found here.


10. Tables​

Always use HTML tables.

<table>
<thead></thead>

<tbody></tbody>
</table>

Repeat headers

thead {
display: table-header-group;
}

Avoid splitting rows

tr {
break-inside: avoid;
}

Avoid fixed row heights.


11. Images​

Preferred

  • SVG
  • Vector logos

Acceptable

  • PNG (300 DPI)

Avoid

  • Low-resolution images
  • Images larger than necessary

Always define

img {
max-width: 100%;
}

12. Typography​

Embed fonts.

@font-face {

...

}

Always test

  • Bold
  • Italic
  • Currency
  • Unicode
  • Symbols

Avoid relying on fonts installed on the rendering server.


13. Common Mistakes​

  • Using CSS Grid everywhere

  • Fixed heights

  • Absolute positioning for layout

  • Empty <div> for spacing

  • Browser-only CSS features

  • Very deep HTML hierarchy

  • Duplicating headers manually

  • Using <div> instead of <table>

  • Testing only with small datasets


14. Checklist​

Layout​

  • Page size defined
  • Margins configured
  • Flexbox used where appropriate
  • No unnecessary absolute positioning

Pagination​

  • Sections break correctly
  • Cards are not split
  • Tables paginate correctly
  • Table headers repeat
  • Running elements used
  • Page numbers correct
  • Header/Footer rendered on every page

Assets​

  • Fonts embedded
  • SVG preferred
  • Images scaled correctly

Final Verification​

  • Rendered with realistic data
  • No overflow
  • No unexpected page breaks
  • Matches the design specification

Rules​

  1. Design for printed pages, not browsers.
  2. Prefer block layout whenever possible.
  3. Use semantic HTML.
  4. Keep CSS simple and maintainable.
  5. Use Flexbox only for simple alignment.
  6. Use Grid only when necessary and after testing.
  7. Use native HTML tables for tabular data.
  8. Configure page settings with @page.
  9. Use running elements for headers and footers.
  10. Design pagination intentionally using page-break properties.
  11. Always test with realistic production data.