Japanese vertical text that comes out sideways or upside down
Japanese novels, e-book readers and some menus and labels are set vertically: 縦書き (tategaki), with lines that run top to bottom and follow each other from right to left. CSS does it with writing-mode. Apps get it wrong in three places: they rotate a box to make a vertical label, which turns the kanji upside down; they set English vertically too; and they page through a vertical book as if it ran left to right. Set it like this:
/* vertical, only for Japanese */
:lang(ja) .novel {
writing-mode: vertical-rl;
}
/* a vertical label: no rotate() */
.lane-title {
writing-mode: vertical-rl;
}
/* two or three digits, upright */
.tcy {
text-combine-upright: all;
}
What each way of turning text did to 未着手 (“to do”) and the English “To do” in Chromium 152:
| CSS | 未着手 | To do |
|---|---|---|
vertical-rl | upright | on its side |
vertical-rl and rotate(180deg) | upside down | on its side, read upward |
sideways-lr | on its side, read upward | on its side, read upward |
vertical-rl and text-orientation: upright | upright | upright, a letter at a time |
Rotating a vertical box by 180 degrees is a common way to make a label that reads upward, such as the title of a collapsed column. It looks right in English, because English already lies on its side in vertical text, and it turns every kanji upside down. For Japanese, vertical-rl alone reads top to bottom with every character upright. If the label has to read upward, use writing-mode: sideways-lr, which Chromium 152 supports: Japanese then lies on its side as English does, and nothing is upside down.
Numbers and English in a vertical line
In vertical text, digits lie on their side like English, so the 22 in 10月22日 (October 22) is turned 90 degrees. text-combine-upright: all sets a short run side by side in the space of one character: in 28px text, the 22 took one 28px slot. CSS Writing Modes Level 4 also defines digits 2 to do this for you, but Chromium 152 doesn't accept it (CSS.supports() returned false), so wrap the digits in a span:
<p class="novel"> 10月<span class="tcy">22</span>日まで </p>
Keep it to two or three digits. A four-digit 2026 was squeezed into the same one-character slot; leave longer numbers on their side. For a short code such as PDF, text-orientation: upright stands each letter up; leave whole words on their side.
Set English horizontally. A layout that puts writing-mode: vertical-rl on the whole page turns English menus, product names and headings on their side, and English isn't written that way. Limit it to Japanese content with :lang(ja), which follows the lang attribute of the page or of any element: with the rule above, a .novel inside lang="ja" was vertical and one inside lang="en" stayed horizontal.
Paging right to left
A vertical book starts at the right and moves left, so the next page is on the left. In a vertical-rl box that scrolls sideways, scrollLeft is 0 at the start and goes negative: in Chromium 152, a box 198 pixels wide holding 792 pixels of text ran from 0 to −594. Code written for pages that run left to right breaks two ways. Scrolling by a positive amount does nothing (scrollLeft stayed 0), and a last-page test that adds scrollLeft to the width never comes true. Count leftward, and use the absolute value:
function nextPage(el) {
const w = el.clientWidth;
el.scrollBy({ left: -w });
}
function atEnd(el) {
const left = Math.abs(el.scrollLeft);
return left + el.clientWidth >=
el.scrollWidth - 1;
}
In that box, nextPage() went to −198, −396 and −594, and atEnd() was true on the last. Work out the number of pages from scrollWidth when you need it, after document.fonts.ready, not once when the chapter opens: the width changes when the font loads or the reader changes its size. An e-book says it pages right to left with page-progression-direction="rtl" in its package file, and a reader that ignores it pages the wrong way.
What went wrong in real apps
- obsidian-kanban #1217: a collapsed column's title used a vertical
writing-modeandrotate(180deg), so Japanese, Chinese and Korean titles were drawn upside down, while Latin titles didn't show it. - shippress-themes #84: a theme set
writing-mode: vertical-rlon English text in 13 places, from the menu to product names. A user asked not to set English vertically, and the fix kept vertical writing only for pages in Japanese, Chinese or Korean. - vectorcraft #260: in vertical text, 月 was drawn over the 22 of 10月22日まで (“until October 22”). The fix set two- and three-digit numbers upright side by side.
- Novel_reader_app #164: in vertical mode, an episode of 11 pages stopped at page 10, until a change of font size made the reader count the pages again.
- bookorbit-ios-support #63: e-books set with
vertical-rland right-to-left page progression stopped turning pages after the first, until version 1.6.0.
The rest of a Japanese check
A novel that reads upside down, or stops a page short, loses its reader. The same pass catches Enter while typing Japanese (the fix), yen charged 100 times over (the fix), kanji drawn in their Chinese shapes (the fix), headings that break in the middle of a word (the fix), postal codes rejected when typed in Japanese (the fix), dates saved one day early in Japan (the fix), address forms in the American order (the fix), phone numbers sent to +81 with the 0 still in (the fix), PDFs with the Japanese missing (the fix), search that finds nothing in Japanese (the fix), previews cut down to “...” in Japanese (the fix), lists sorted in the wrong order (the fix), email subjects that arrive garbled (the fix), CSV files that open garbled in Excel (the fix), Japanese titles that give an empty URL slug (the fix), file names garbled on upload and download (the fix), dates in the Japanese era that come out wrong (the fix), full-width spaces that get past your checks (the fix), and public holidays your app gets wrong (the fix).
Lesstep translates web apps into Japanese and delivers them as one pull request. In Complete (US$249), we check every screen in Japanese, and read vertical text the way it's set: upright, top to bottom, and paged right to left. The first step is a free sample.
Chromium is a trademark of Google LLC. This page is not affiliated with or endorsed by Google.
More: Enter sends the message while typing Japanese · Stripe charges 100 times too much in yen · Kanji in their Chinese shapes · Japanese headings that break in the middle of a word · Forms that reject numbers typed in Japanese · Dates that come out wrong for Japanese users · Address forms in the Japanese order · Japanese phone numbers in forms · Japanese text missing from your PDFs · Search that finds nothing in Japanese · Length limits that break in Japanese · Japanese lists sorted in the wrong order · Japanese email subjects that arrive garbled · Japanese CSV files that open garbled in Excel · Japanese titles that give an empty URL slug · Japanese file names garbled on upload and download · Japanese era dates that come out wrong · Full-width spaces that get past your checks · Japanese public holidays your app gets wrong · Japanese localization checklist · Japanese localization for your web app