While reading the Daangn SEED documentation, I noticed a few awkward line breaks and submitted a minimal PR (opens in a new window). A few days later I was asked for a review, and another related PR (opens in a new window) was merged. Looking through that change, I noticed the property [word-break:auto-phrase].

PR summary

“Oh, does that property exist?” I opened the MDN documentation (opens in a new window). auto-phrase was marked experimental, and the Chrome note in the compatibility table said it only applied when lang="ja" and had no effect in other locales. The page also explains that auto-phrase behaves like word-break: normal, except that language-specific analysis improves wrapping by avoiding breaks in the middle of natural phrases. Korean uses ko, so it should receive no effect and fall back to word-break: normal. The result should therefore have remained unchanged.

You said ja only!!!

But when I opened the actual document, the line break had been fixed. With normal, the first line split the Korean word for “engineers” after its first syllable. With auto-phrase, it broke cleanly before the whole word. You said only Japanese was supported! Why did Korean wrap differently?

Image 1 / 2
Comparing Korean wrapping with normal and auto-phrase

I decided to find the actual Chrome release. (This might also be a perfect chance to contribute to MDN, hehe.) I started with Chrome 119, the version named by MDN. Chrome introduced auto-phrase there as a feature for wrapping Japanese text at natural phrase boundaries (opens in a new window).

That page also says, “Currently, Chrome supports this feature only for Japanese, using the BudouX C++ port that uses AdaBoost ML technology,” and, “We plan to support Korean and Chinese in future versions of Chrome.” So it still says only Japanese... but Korean clearly works in practice!!! I went to read the code.

PhraseBreaking is supported in ja and ko; MlBreakEngine only supports ja

Chromium calculates line breaks with ICU (International Components for Unicode). In the code that creates a LineBreakIterator (opens in a new window), ICU explicitly says that lw=phrase is supported only for Japanese and Korean.

lw=phrase is only supported in Japanese and Korean

Meanwhile, the code that selects the actual analysis engine (opens in a new window) says phrase breaking supports Japanese and Korean, but the ML engine supports only Japanese. My first thought was: perhaps they describe Korean as unsupported because its ML engine is unsupported.

But consider the languages themselves. Korean has spaces, and those spaces effectively identify word-group boundaries. Japanese and Chinese do not normally use spaces at all, so finding those boundaries may require a separate ML engine. Chrome uses BudouX (opens in a new window) for this purpose; it divides Japanese into units called bunsetsu. They may not be linguistically identical, but they seem to play a very similar practical role. (As someone approaching a thousand days of Japanese on Duolingo, the resulting divisions feel similar to me.)

Japanese needs an ML engine to recover natural boundaries from an unspaced sentence—almost like reverse engineering. Korean does not need one in the first place, because its spaces already provide natural boundaries. BudouX itself has a section titled Korean support? (opens in a new window), which essentially says that Korean can usually use keep-all.

That led me to conclude that Korean is, in practice, already supported by auto-phrase. I opened an issue (opens in a new window) and a PR (opens in a new window) on MDN. It would be a shame if people avoided the property because MDN said it only supported Japanese when Korean effectively works too... But then, how exactly does it differ from keep-all?

The PR was merged! Now I only have to wait for the release, hahaha

keep-all always breaks only between word groups. auto-phrase starts at those boundaries, but if overflow remains, it falls back to normal and recalculates the line. In other words, it behaves like keep-all while retaining the ability to split a word that is simply too long. The effect is close to combining keep-all with overflow-wrap: anywhere.

One difference is that auto-phrase removes the normal opportunities for hyphenation and effectively behaves like hyphens: none. A long English word that wraps would usually be connected with a hyphen, but that hyphen is not added.

My conclusion is this: if a product handles Korean (and Japanese) together with English, might this be the most practical setup?

.title {
  word-break: normal;
  overflow-wrap: anywhere;
  text-wrap: balance;
}

.title:lang(ko),
.title:lang(ja) {
  word-break: auto-phrase;
}

.title:lang(en) {
  hyphens: auto;
}

Use overflow-wrap: anywhere to defend against extremely long strings and URLs, and text-wrap: balance to place lines well. Let Korean and Japanese wrap at phrase boundaries with word-break: auto-phrase, while English adds hyphens when a long word must wrap.

No separate min-width required!

A few more reasons anywhere helps: dictionary words behave well when hyphenation is available, but unknown words can still overflow. It also prevents flex or grid layouts from breaking without adding min-w-0 separately to every text element.

When I first saw auto-phrase, I thought it meant semantic line breaking. Korean already has keep-all to wrap at word groups, so I assumed auto-phrase would only be meaningful if it added semantic grouping on top. Something roughly like this:

- To build a good product, improve each
- small inconvenience one by one
+ To build a good product,
+ improve each small inconvenience one by one

So I decided to build it myself with BudouX. The result proved useful, at least within some limits, and I went ahead and published it as npm packages. Here they are: GitHub (opens in a new window) and npm (opens in a new window). In the next article, I will share how I built it. Hahaha.

A logo I asked GPT to make
GitHubfix(docs): improve Korean title wrapping in updates by woohyun-park · Pull Request #2070 · daangn/seed-designSEED Design System. Contribute to daangn/seed-design development by creating an account on GitHub. (opens in a new window)GitHubfix(docs): improve updates title wrapping by junghyeonsu · Pull Request #2112 · daangn/seed-designhttps://github.com/daangn/seed-design/pull/2112/changes (opens in a new window)MDN Web Docsword-break CSS property - CSS | MDNThe word-break CSS property sets whether line breaks appear wherever the text would otherwise overflow its content box. (opens in a new window)Chrome for DevelopersIntroducing four new international features in CSS | Blog | Chrome for DevelopersChrome is adding four new international CSS features. (opens in a new window)chromium.googlesource.comsource/common/brkiter.cpp - chromium/deps/icu - Git at Googlehttps://chromium.googlesource.com/chromium/deps/icu/+/8cc91d9b6ab9991802fd208ee03a69714fd0251c/source/common/brkiter.cpp#444 (opens in a new window)chromium.googlesource.comsource/common/dictbe.cpp - chromium/deps/icu - Git at Googlehttps://chromium.googlesource.com/chromium/deps/icu/+/8cc91d9b6ab9991802fd208ee03a69714fd0251c/source/common/dictbe.cpp#1266 (opens in a new window)GitHubGitHub - google/budouxContribute to google/budoux development by creating an account on GitHub. (opens in a new window)GitHubGitHub - google/budouxContribute to google/budoux development by creating an account on GitHub. (opens in a new window)GitHub`word-break: auto-phrase` - Chrome note incorrectly excludes Korean · Issue #30359 · mdn/browser-compat-dataWhat type of issue is this? Incorrect support data. What information was incorrect, unhelpful, or incomplete? The Chrome support note for css.properties.word-break.auto-phrase currently says: This value is only applicable if lang="ja" is... (opens in a new window)GitHubCorrect Chrome locale note for `word-break: auto-phrase` by woohyun-park · Pull Request #30360 · mdn/browser-compat-datahttps://github.com/mdn/browser-compat-data/pull/30360/changes (opens in a new window)GitHubGitHub - woohyun-park/semantic-wrap: Model-driven line breaking for JavaScript and ReactModel-driven line breaking for JavaScript and React - woohyun-park/semantic-wrap (opens in a new window)npmjs.comnpmhttps://www.npmjs.com/org/semantic-wrap (opens in a new window)