本文へスキップ
ブログに戻る

Thai typography on the web: line breaking, leading, and reading time

約5分1回閲覧

Why Thai text is harder than it looks#

The web is built on the assumption that words are separated by spaces — line breaking, word counting, and the default leading all rest on it. When the primary content is Thai, that assumption disappears completely, and the consequences show up one at a time with no error message attached.

  • Thai does not put spaces between words. The spaces you do see mark phrase or sentence boundaries, not word boundaries.
  • Glyphs stack: a consonant can carry a vowel above it and a tone mark above that, plus a vowel below. Leading that feels right in English is cramped in Thai.
  • Fonts chosen for a Latin design usually have no Thai coverage, so the browser falls back to a system font at a different optical size and the page stops looking like one design.
  • Any tool that counts words by splitting on whitespace will see an entire Thai paragraph as a single word.

Line breaking#

The good news is that modern browsers already break Thai using a dictionary. The catch is that they only do it when they know the text is Thai, which makes a correct lang attribute far more visually load-bearing than most people expect — and screen readers need it regardless.

javascript
:lang(th) {
  /* let the browser use its dictionary; do not fight it */
  line-break: auto;
  word-break: normal;

  /* only to stop long Latin words and URLs from overflowing */
  overflow-wrap: break-word;

  /* headroom for a tone mark sitting on top of a vowel */
  line-height: 1.85;
}

/* never do this to Thai: it breaks inside a syllable cluster */
.dont-do-this { word-break: break-all; }
  1. Declare the language properly with lang="th", on the document or on the content block, and the browser handles word breaking for you.
  2. Do not reach for word-break: break-all on Thai text — it splits syllables and strands a vowel at the start of the next line.
  3. The hyphens property does nothing useful here, because Thai does not hyphenate across a break.
  4. For mixed content or long links, overflow-wrap prevents overflow without disturbing Thai word breaking.
  5. Avoid justify for Thai in narrow columns: there are no inter-word spaces to stretch, so the extra space lands in the wrong places.

Leading and spacing#

ElementTypical English valueBetter for ThaiReason
Body text1.51.75 – 1.9Vowels and tone marks stack up to two levels above the line
Large headings1.11.25 – 1.35The bigger the type, the more visible the collision
Letter spacingAdjust freelyLeave it at normalExtra tracking visually detaches marks from their consonant
MeasureAround 65 charactersAround 40 – 45 charactersThai carries more meaning per character of width
Badly set Thai never throws an error. It just makes the page quietly more tiring to read, in a way readers cannot name.
Why typography should be reviewed with real Thai content

Word-based reading time does not work#

javascript
// splitting on whitespace treats a whole Thai paragraph as one word,
// so count Thai characters instead and add the remaining Latin words
const thaiChars = (text.match(/[\u0E00-\u0E7F]/g) ?? []).length
const latinWords = text.replace(/[\u0E00-\u0E7F]/g, ' ').split(/\s+/).filter(Boolean).length

// roughly 400 Thai characters per minute, 230 English words per minute
const minutes = thaiChars / 400 + latinWords / 230
return Math.max(1, Math.round(minutes))
  • Set lang correctly on the document and on any block that switches language
  • Pick a font with real Thai coverage and declare an explicit fallback
  • Give Thai body text its own leading rather than inheriting the Latin default
  • Compute reading time from character counts when the content is Thai
  • Test wrapping on narrow screens with real Thai copy, not lorem ipsum