CSSで、文章を縦書きにする方法

​​CSS​HTML,Playwright

CSS で文章を縦書きにするには、文章を囲む要素に writing-mode: vertical-rl を指定します。文字は上から下へ並び、行は右から左へ進みます。あわせて height で1行の長さを決めておくと、行の長さが画面の高さに左右されません。

補足

検証環境は Ubuntu 24.04、Node.js 22.23.4、Playwright 1.63.0、Chromium 153 です。フォントは Noto Serif CJK JP を使いました。HTML と CSS のページを Playwright で開き、要素の位置と大きさ、getComputedStyle() の値、スクロールの位置を調べました。Firefox と Safari、スマートフォンの実機、ほかのフォントでの見え方は試していません。

writing-mode: vertical-rl で縦書きにする

CSS は次のとおりです。

css
/* 文章を縦書きにする */
.tategaki {
  writing-mode: vertical-rl;
  height: 16em;
}
html
<div class="tategaki">
  <p>吾輩は猫の手である。名前はまだない。</p>
  <p>どこで生まれたか、とんと見当がつかぬ。</p>
</div>

writing-mode は、横書きにするか縦書きにするかと、行が進む向きを決めるプロパティです。vertical-rl は、文字を上から下へ並べ、次の行を前の行の左に置きます。

検証では、文字の大きさを20px、行の高さを1.8にしました。縦書きの箱は高さが320px(16em)で、幅は144pxでした。1つの段落が2行に折り返し、1行が36px、2行で72pxの幅になります。1つ目の段落は箱の右半分(段落の左端が、箱の左端から72pxの位置)に、2つ目の段落はその左(箱の左端の位置)に置かれました。

縦書きでは、height が1行の長さになり、行が増えると幅が広がります。getComputedStyle() で論理的な大きさを調べると、inline-size(行の長さ)が 320px、block-size(行が積み重なる方向の長さ)が 144px でした。横書きのときとは、幅と高さの役目が入れ替わります。

句読点の「、」「。」は、縦書きのときの位置(文字の右上)に置かれました。次の節の画像で確かめられます。

vertical-lr との違いは、行が進む向き

writing-mode には vertical-lr もあります。文字が上から下へ並ぶのは同じですが、次の行は前の行の右に置かれます。

上下2段の比較。上の「writing-mode: vertical-rl」では、太字で色を付けた1つ目の段落「吾輩は猫の手である。名前はまだない。」が右側にあり、その左に2つ目の段落「どこで生まれたか、とんと見当がつかぬ。」が続いている。下の「writing-mode: vertical-lr」では、1つ目の段落が左側にあり、2つ目の段落がその右に続いている
vertical-rl は行が右から左へ、vertical-lr は左から右へ進む(色付きが1つ目の段落)

位置を測ると、vertical-lr では1つ目の段落の左端が箱の左端に、2つ目の段落の左端が箱の左端から72pxの位置にあり、vertical-rl とちょうど逆でした。

height を指定しないと、行の長さが画面の高さで変わる

height を指定せずに writing-mode: vertical-rl だけを書くと、1行の長さはブラウザの画面の高さで決まりました。同じ文章(73文字)を、画面の高さだけを変えて開いた結果です。

画面の高さ 縦書きの箱の高さ 行数(箱の幅)
400px 400px 4行(144px)
800px 800px 2行(72px)

箱の高さが画面の高さと同じになるため、body の上下の余白(20pxずつ)を足したページ全体の高さは、画面より40px高くなりました。画面の高さが変わると行の折り返しも変わるので、縦書きにするときは height で行の長さを決めておくと、表示が安定します。

英字を立てて並べる text-orientation: upright

縦書きの中の英字は、初期設定では右に90度倒れて並びます。1文字ずつ立てて並べたいときは、text-orientation に upright を指定します。

css
/* 英字を横に倒さず、1文字ずつ立てて並べる */
.upright {
  text-orientation: upright;
}

初期値の mixed は、英字のような横書きの文字を右に90度回し、漢字やかなはそのまま立てて置きます。検証では、「CSS」の3文字が占める縦の長さは、mixed で36.3px、upright で60pxでした。upright では1文字ごとに20px(1em)ずつ場所を使うので、英字の並びが長くなります。

2桁の数字を横に並べる text-combine-upright: all

日付の「11月」のような2桁の数字は、縦書きの中で横に並べて1文字分に収めることがあります(縦中横)。CSS では、数字を span で囲み、text-combine-upright に all を指定します。

css
/* 縦書きの中の2桁の数字を、横に並べて1文字分に収める */
.tcy {
  text-combine-upright: all;
}
html
<p>今日は<span class="tcy">11</span>月。</p>
白い4つの縦長の枠を横に並べた比較。左から「指定なし」は「CSSを」のあとの「CSS」(ピンク)が横に倒れている。「upright」(text-orientation: upright)は同じ「CSS」が1文字ずつ立って並んでいる。「指定なし」の「今日は11月」は「11」(ピンク)が横に倒れている。「縦中横(all)」(text-combine-upright: all)は「11」が横書きのまま1文字分に収まっている
英字と数字の並び方の比較(ピンクが比べている部分)

all は、囲んだ文字をすべて横に並べ、縦書きの行の中で1文字分の場所に収めます。検証では、「11」が占める縦の長さは20px(1文字分)でした。指定しないときは、横に倒れて18.8pxです。

4桁の「2026」に all を指定しても、縦の長さは同じく20pxでした。4文字が1文字分の幅に収まるように縮められます。指定しないときの「2026」は、横に倒れて44.6pxでした。

行がはみ出すと、横スクロールは右端から始まる

縦書きの箱に width と overflow-x: auto を指定すると、行が入りきらないときに横スクロールが出ます。

css
.tategaki-scroll {
  writing-mode: vertical-rl;
  height: 16em;
  width: 300px;
  overflow-x: auto;
}

15行(540px)の文章を幅300pxの箱に入れたところ、開いた直後は右端が見えていて、1行目から8行目までが表示されました。読み始めの位置が最初から見えているので、スクロールの位置を動かす必要はありません。

一方、JavaScript で読むスクロールの位置(scrollLeft)は、開いた直後が 0 で、左(文章の終わり)へ進むほど負の数になりました。いちばん左までスクロールしたときは -240 です。スクロールの位置を JavaScript で扱うときは、0から負の数の範囲になることに気をつけてください。

対応しているブラウザ

MDN の互換性データ(@mdn/browser-compat-data 8.1.8)で、この記事で使っている機能を調べました。最新の対応状況は、MDN の各プロパティのページ(例:MDN の writing-mode のページ)の下にある表で確かめられます。

機能 Chrome Firefox Safari
writing-mode 48 41 10.1
text-orientation 48 41 14
text-combine-upright: all 48 48 15.4

互換性データでは、Safari は 5.1 から、-webkit- を付けた -webkit-writing-mode と -webkit-text-orientation にも対応しています。

​Posted by 86