Lesstep
Japanese vertical text · 縦書き · Checked October 30, 2026

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-rluprighton its side
vertical-rl and rotate(180deg)upside downon its side, read upward
sideways-lron its side, read upwardon its side, read upward
vertical-rl and text-orientation: uprightuprightupright, 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

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