Letter, word & glyph spacing
Three controls tune the horizontal rhythm of text. letter-spacing and word-spacing add real space
that the layout counts (tracking that affects wrapping). glyph-x-scale stretches or condenses the
rendered glyphs without touching the layout. And <tbreak/> forces a line break where you author it.
letter-spacing and word-spacing
CSS/SVG tracking: uniform extra space between grapheme clusters (letter-spacing) and at each
inter-word gap (word-spacing), on every text element (spec §6.8). Both are unprefixed — they are
existing SVG/CSS names.
Attributes
| Attribute | Values | Initial | Effect |
|---|---|---|---|
letter-spacing | normal | length | normal (= 0) | extra advance added per inter-grapheme gap |
word-spacing | normal | length | normal (= 0) | extra advance added per inter-word space |
Model
Both are absolute lengths in user units — they do not scale with font-size, so under
shrink-to-fit the spacing stays put while the glyphs shrink, matching CSS/SVG.
They are additive on top of kerning, not a replacement: the font's pair kerning stays in the glyph
advances and the spacing layers over it. For a run of n grapheme clusters containing s inter-word
spaces, the rendered advance is:
advance = kerned_advance(run) + (n − 1) × letter-spacing + s × word-spacing
Layout-aware. This spaced advance — not the raw glyph advance — drives wrapping, shrink-to-fit,
ellipsis truncation and alignment, so tracked text breaks and fits correctly. The attributes are then
emitted on the output <text> so the renderer reproduces the exact width the layout assumed. normal
and 0 emit nothing. Counts use code points in v0.
glyph-x-scale — visual width scaling
A purely visual horizontal scale on the rendered glyphs (spec §6.7): condensed or extended type
without a condensed or extended font. It applies to all three front-ends — unprefixed glyph-x-scale
on <x:textbox>, and the x:-prefixed x:glyph-x-scale on the reused SVG <text inline-size> and
<textArea> (a new attribute on a reused SVG element is namespaced).
| Attribute | Values | Initial | Effect |
|---|---|---|---|
glyph-x-scale | number | 1 | multiply each line's advance width by this factor |
Layout is unchanged. Wrapping, fitting and overflow all run at the natural width; only the final
rendered glyphs are scaled. Per line, the compiler measures the natural advance w and emits
textLength="w · scale" lengthAdjust="spacingAndGlyphs" on the <tspan>, so the renderer stretches
both the glyphs and their spacing to hit that length. A value of 1 (the initial) emits nothing. When
combined with letter-spacing, the textLength target is computed from the letter-spaced advance, so
the two compose.
<tbreak/>
A forced line break, per SVG Tiny 1.2. Each <tbreak/> child of a <textArea> (or <x:textbox>)
ends the current line and starts a new one; wrapping resumes independently on each side, and
consecutive breaks produce blank lines. It is the only child element <textArea> interprets in v0.
Justification and fitting treat the text on each side of a <tbreak/> as its own paragraph — see
Justification.
<textArea x="32" y="72" width="226" font-size="16">
Ada Lovelace<tbreak/>12 Analytical Engine Way<tbreak/>London
</textArea>
How it lowers
letter-spacing and word-spacing are emitted as the same-named attributes on the output <text>
(or forwarded on a passed-through <text inline-size>). glyph-x-scale becomes per-line
textLength + lengthAdjust="spacingAndGlyphs". <tbreak/> is resolved at compile time into the
positioned per-line <tspan>s.
See also
- Wrapping — where line breaking and
<tbreak/>fit in. - Justification — how
justifyinteracts with spacing and per-paragraph breaks. - Shrink to fit — spacing is absolute, so it holds under fitting.
- Styled runs — runs share the paragraph's
letter-spacingandword-spacing.