← dompdf.js Studio

Text Alignment and Indentation in dompdf.js

Alignment and indentation are the most basic visual language of paragraph layout. Centered headings, justified body text, two-character first-line indents, and the indentation hierarchy of lists and blockquotes tell the reader, before a single sentence is read, that the document was composed with care. PDF export raises the stakes: a slightly off alignment scrolls past unnoticed on a web page, but a PDF is a deliverable, and every misaligned line is frozen into the file and judged at print size. dompdf.js supports all four text-align values and text-indent through the real CSS layout engine, so alignment verified in the browser survives export as-is, and both the Chinese convention of first-line indentation and the English convention of justified body text are under precise control. This guide covers the behavior of each alignment value and when it belongs, the forms of indentation and how em-based indents scale with font size, the details and traps of justified text including inter-character justification for CJK, the conventions of formal Chinese layout, and how alignment interacts with tables, lists, columns, and RTL. The closing section answers the questions that actually come up in production. By the end, paragraph layout in your templates should be deliberate, consistent, and finished — the kind of output that reads as professionally typeset at first glance. The sections build on each other: the four alignment values and their conventions, indentation in all its forms, the justification details that separate polished output from passable output, the CJK conventions your Chinese documents should follow, and the way alignment interacts with tables, lists, columns, and RTL mirrors. Practical code appears throughout, and the final section collects the questions that actually come up in production.

The Four Alignment Values and Their Use Cases

text-align accepts four values with distinct behaviors. Left alignment is the workhorse for Chinese body text, giving a stable reading rhythm; right alignment suits footers, sign-offs, and numeric table columns; center alignment belongs to headings, covers, and captions; and justify squares both margins, the conventional choice for formal English body copy and the standard of newspapers and magazines.

Language characteristics should drive the choice. Chinese breaks between characters, so left and justified alignment look similar, but justification squares off the page. English words vary in length, so left alignment leaves a ragged right edge while justification evens it by adjusting word spacing. The reliable combination for formal documents is justified body text, centered headings, and right-aligned data — a pattern that reads as professional without any further thought.

Alignment inherits and overrides: text-align is an inherited property, so children follow their parent unless they set their own value, and block-level alignment applies to the text inside while inline elements need parent-level handling. Design templates by setting a default alignment on the root and overriding on specific elements; the hierarchy stays legible, changes concentrate in one place, and stray alignment styles stop fighting each other across the template.

One habit worth building: never rely on default alignment for anything that matters. Defaults differ by context — RTL flips the default, table cells inherit from the table — so stating alignment explicitly on every element that carries visible text makes the template's intent readable by the next developer and immune to context changes.

Alignment interacts with the text itself in one more way: it is applied per line, so a paragraph with mixed font sizes shows each line aligned by the engine's rules. When a line contains a large inline element such as an image, the alignment still holds, but the vertical position of that element is governed by vertical-align, not text-align — the two properties work together, and knowing which one controls what saves a lot of trial and error.

Code Example: Alignment and First-Line Indentation

text-indent: 2em implements the classic two-character first-line indent of Chinese typesetting. The em unit tracks the font size, so the indent scales when the size changes, which is exactly what the convention requires and what fixed pixels cannot deliver. text-indent affects only the first line of a block, never subsequent lines; write it once on the shared paragraph style and every paragraph inherits it, so a single edit reindents the whole document.

Hanging indents — text-indent: -2em combined with padding-left: 2em — push the first line out while indenting the rest, the standard shape for bibliographies and list items. dompdf.js supports the combination and renders it exactly as the browser does. The two declarations must travel together: a negative indent alone makes the first line overflow the container's left edge, so treat the pair as one unit and the pattern becomes reliable.

Alignment belongs in the template's style block; there is no extra configuration. If the template comes from a rich text editor, the editor's inline styles can override global rules, so normalize inline styles before export or use more specific selectors to win the cascade. Alignment that is controlled is alignment that survives data changes — unexpected right-aligned paragraphs are almost always an inline-style leak rather than a library limitation.

For tables of numbers, per-cell alignment beats per-column guesswork: right-align numeric cells and left-align text cells at the cell level, and the column reads correctly even when data changes the content mix, because alignment follows the cell's role rather than its position.

<style>
  body { font-family: 'Source Han Sans SC', sans-serif; }
  .center { text-align: center; }
  .left { text-align: left; }
  .right { text-align: right; }
  .justify { text-align: justify; text-justify: inter-ideograph; }
  .indent-2em { text-indent: 2em; }
  .hanging { text-indent: -2em; padding-left: 2em; }
</style>
<h1 class="center">Project Acceptance Report</h1>
<p class="indent-2em">First paragraph with a two-character first-line indent, following the Chinese layout convention.</p>
<p class="justify">Justified English text stretches word spacing so both margins are flush, which is the standard for formal documents.</p>
<p class="hanging">• Hanging indents suit lists and bibliographies: the first line protrudes, following lines indent.</p>
<p class="right">Signed: Quality Department, 2026-08-18</p>

Justified Text: Details and Traps

text-align: justify stretches word spacing to square both margins, with a few behaviors that surprise people: the last line is never stretched, staying left-aligned by specification, and for Chinese text the inter-character spacing needs text-justify: inter-ideograph to look right, because without it the engine has no instruction for distributing space between Han characters and the result reads as uneven gaps.

Justification is hostile to narrow columns. When a column is narrow, the engine stretches word spacing dramatically and the paragraph develops rivers — visible white channels running through the text — that are harder to read than a ragged edge. Table cells, sidebars, and any container under a few inches wide should use left alignment; reserve justification for wide body columns where the spacing stays subtle, and judge the choice by the actual column width rather than by the property's reputation.

Another misconception: justify does not break words. A long unbroken word in a justified paragraph still overflows or produces a huge gap on its line. Justification and wrapping strategy must be combined — justify for the paragraph plus overflow-wrap: break-word for the pathological strings — so long URLs and long words cannot destroy the alignment of the whole paragraph. The two properties are one solution, not two alternatives.

Hyphenation changes the equation for English: with proper hyphenation, justification has more break points and produces less dramatic spacing. If your English documents justify poorly, consider whether the template should hyphenate at all — a simple style decision that measurably changes the visual quality of justified columns. If you do hyphenate, keep the hyphenation dictionary consistent across the document, because a mix of hyphenated and unhyphenated lines in adjacent paragraphs is visually jarring.

Chinese Layout Conventions: Indentation and Spacing

Formal Chinese documents follow a specific convention: body paragraphs indent two characters (2em) at the first line, paragraphs are not separated by blank lines, and heading hierarchy is expressed through size and weight. English layout is the opposite: no first-line indent, with blank lines or paragraph spacing between blocks. Decide the convention before designing the template, because mixing the two systems produces documents that look wrong to readers of either language.

The 2em indent scales automatically with font size, which is why it beats fixed-pixel indentation for CJK. Inside nested structures — lists, blockquotes — the indent stacks with the parent's padding, producing the progressive indentation that expresses hierarchy. When exact control matters, keep margin and padding roles separate: margins for paragraph spacing, padding and text-indent for indentation, and the template stays semantically clear and easy to adjust.

Paragraph spacing belongs to margin, not to blank lines. Inserting empty paragraphs to create vertical space is a common bad habit: the empty line's height is uncontrolled and changes with font and line-height, and it disturbs pagination because the layout engine counts it as content. A margin-bottom on paragraphs gives stable, adjustable spacing, and the pagination engine can then compute page content height accurately, so multi-page documents break at sensible points instead of leaving awkward half-lines at page bottoms.

A practical number: Chinese body text at 10.5pt with a 2em indent and 6-8pt paragraph spacing reads as the standard formal layout. These are conventions, not laws, but starting from them means your templates look familiar to the audience before a single paragraph is read. When in doubt, match the convention of the document's primary language and keep it uniform across every exported file, so a batch of reports looks like one system produced them.

Alignment Across Tables, Lists, and Columns

Alignment shapes more than paragraphs. Numeric table columns right-align by convention so amounts and quantities line up digit by digit for vertical comparison; list text left-aligns with markers positioned consistently. dompdf.js applies text-align inside table cells exactly as in the browser, so data tables get the full range of alignment treatment without any drawing-level code.

In multi-column layouts, each column aligns independently, and justification in narrow columns magnifies the spacing problem, so column width design must leave room for the text it carries. dompdf.js supports CSS multi-column and flex layouts, with column gaps controlled by gap rather than manual coordinates — changing a column width is one property, and the alignment reflows automatically without recalculating positions.

RTL flips alignment semantics: text-align: left keeps its meaning in an RTL container, but visually it corresponds to the LTR right side. The cleaner approach is logical properties: text-align: start and end follow the document direction automatically. A template serving both LTR and RTL locales can use start/end exclusively and render correctly in both with one set of declarations — the lowest-maintenance way to handle alignment in multilingual documents.

When a template must serve both directions and the layout itself differs — a sidebar that flips sides, a signature block that moves — pair logical alignment with direction-aware flex ordering so the whole structure mirrors, not just the text. Testing one RTL locale end to end then validates the pattern for all of them.

For RTL tables, the column order mirrors as well: the first column in the markup appears at the right edge in an RTL context, so headers and data must be authored in logical order and let the direction system flip them. If a bilingual table needs different column orders per language, that is a layout decision to make in the template per locale, not a data transformation.

Common Problems and Best Practices

Q: Justified Chinese text shows strange character spacing. A: Add text-justify: inter-ideograph so the engine distributes space according to Chinese typographic conventions. If the result is still unsatisfying, left-align the Chinese body and reserve justification for English — a pragmatic split that matches reading habits and produces predictable results.

Q: text-indent has no effect. A: Confirm the element is block-level or a list item, since inline elements ignore the property; then check whether a more specific selector or an inline style overrides it. Inline styles from rich text editors win the cascade, so normalize them or use !important deliberately, and the indent returns.

Q: Alignment looks right in the preview but wrong in the PDF. A: The engine is the same, so compare the template's exact styles against the preview context. Differences usually come from a missing style rule or a different container width — reproduce the template in the browser and the discrepancy becomes visible and fixable.

Best-practice summary: choose alignment by language and column width; indent with em units; space paragraphs with margin; avoid justification in narrow containers; use logical start/end for multilingual templates. This standard covers the overwhelming majority of document scenarios, produces professional, disciplined output, and raises the first-pass acceptance rate of every deliverable built on it.

Q: Justified paragraphs in a table cell look terrible. A: Narrow cells are the worst environment for justification — spacing stretches so far that readability collapses. Left-align text cells, right-align numeric cells, and reserve justification for wide body columns. This split is not a compromise; it is the standard practice of professional tables, where alignment follows the data type rather than a document-wide default. Reserve justification for genuinely narrative prose, and use it consistently once chosen, because mixing justified and left-aligned body paragraphs in one document reads as sloppy.

⚡ 现场演示(点击生成 PDF)

下面的按钮用 dompdf.js 在浏览器端实时生成 PDF,无需后端:

Hello from dompdf.js!

这是由 dompdf.js 渲染的示例 PDF 内容。