模写中級 #002 | 茶屋サイトで学ぶ縦書きと日本語組版


模写中級 #002 は、和風の茶屋サイトを題材に、縦書きの見出し・単位なしの行間・日本語の折り返しという3つを自分の手で組む課題です。横並びや中央寄せといったレイアウトの技術ではなく、日本語の文字そのものをどう置くかで見た目が決まる題材を選んでいます。

#001(ポートフォリオ)はグリッド、#003(ジム)は写真主体のセクション構成が主題です。この #002 だけは日本語タイポグラフィと縦のリズムが主題なので、順番に進めても内容が重複しません。

項目内容
難易度中級
所要時間目安4〜6時間(見本の実装量から見積もった目安で、計測値ではありません)
使う技術HTML/CSS(Flexbox・writing-mode・メディアクエリ)/スライドショーを付けるなら素のJavaScript
完成見本TABISAKI茶屋(別タブで開きます)
ゴール見本と同じ縦のリズム(行間・字間・折り返し)を、自分で判定できる状態で再現する

差分チェックツールで効率UPお手本コードと自分のコードを比較して、違いを一目で確認できます。練習前にブックマークしておくと便利です。
Diff Checkerを開く →

この課題で作るものと、作る順番

作るのは1枚もののトップページで、上から順にヘッダー・ヒーロー・お知らせ・当茶屋について・道案内・フッターの6ブロックです。この記事に完成コードは載せません。骨格だけを書き出すと次のようになります。

<header class="header">    ロゴ + 3項目のナビ(ヒーローに重ねる)
<main>
  <section class="hero">     背景写真 + 縦書きの h1
  <section class="news">     日付と本文が横に並ぶお知らせ
  <section class="about">    リード文 + 写真2枚を左右に並べる
  <section class="access">   地図エリア + 営業時間の表
</main>
<footer class="site-footer"> ロゴ + ナビ + コピーライト

作る順番

上から順に作るのがいちばん早いです。縦書きの見出しはページ全体の文字設定が決まってからでないと詰まり具合を判断できないため、body の基本設定を書いた直後にヒーローへ入ってください。

順番/セクション作るものこの段階で決まること
1. body の基本設定明朝系のフォントと、単位なしの行間ページ全体の縦のリズム
2. ヘッダーロゴとナビを両端に置き、ヒーローに重ねる重なりの前後関係
3. ヒーロー画面の高さいっぱいの背景写真と縦書きの見出し字間と行間の見え方
4. お知らせ日付と本文が横に並ぶ行を積む狭い幅で縦積みに切り替える判断
5. 当茶屋について写真2枚を左右half幅で並べる画像の切り抜き方
6. 道案内地図エリアと、曜日ぶんの列を持つ営業時間の表狭い幅で表をどう逃がすか
7. フッター中央寄せのロゴ・ナビ・コピーライト折り返したときの間隔

ヘッダーはページ最上部に絶対配置され、ヒーローの写真に白文字で乗ります。ヘッダーを先に置いてからヒーローを敷くと、重ね順の調整が1回で済みます。写真は見本と同じものでなくてかまいません。


和風レイアウトの土台になる日本語タイポグラフィ

和風に見えるかどうかは、色や背景テクスチャよりも行間・字間・文字の向きで決まります。以下の数値はすべて、完成見本を Chrome 150(ヘッドレス)で実測したものです(実測日: 2026-08-02)。

行間は単位なしの数値で指定する

見本は body に line-height: 1.8 と単位なしで書いています。文字サイズ16pxのとき計算後の行間は28.8pxでした。ここを 1.8em に書き換えると、見た目は同じでも子孫要素の挙動が変わります。MDN は「多くの場合、これが line-height を設定する望ましい方法で、継承による予期しない結果を避けられる」と単位なしを推奨しています。親を font-size: 20px として測ると次のとおりです。

親の指定親の計算後の行間子(40px)の計算後の行間
line-height: 1.8(単位なし)36px72px(子の文字サイズ×1.8)
line-height: 1.8em36px36px(親から絶対値のまま継承)

単位を付けると計算結果の長さがそのまま子へ渡ります。見出しだけ文字を大きくしたときに行が重なるのはこれが原因です。出典は MDN: line-height(2026-08-02取得)です。

縦書きは writing-mode と text-orientation の組み合わせで決まる

ヒーローの見出しは縦書きで、見本の計算後の値は writing-mode: vertical-rltext-orientation: upright でした。

writing-mode は行が流れる向きと次の行を置く側を決めます(vertical-rl は上から下へ流れ、次の行は左)。text-orientation は横書き用の文字を寝かせるか立てるかを決めます。text-orientation の初期値 mixed は横書き用の文字を時計回りに90度回します。日本語だけなら差が出ませんが、店名にローマ字や数字を入れた瞬間に寝るので、和風サイトでは upright を明示するのが定石です。出典は MDN: writing-modeMDN: text-orientation(いずれも2026-08-02取得)です。

字間は最後の1文字の後ろにも入る

この課題でいちばん引っかかるのがここです。letter-spacing は「文字と文字のあいだ」ではなく、各文字の後ろに空きを足すように働きます。11文字の日本語(font-size: 20px)で幅を測ると、指定なしで220px、0.3em(=6px)で286pxでした。差の66pxは6px×11文字ぶんです。文字間だけなら10ぶん=60pxのはずなので、行の最後の文字の後ろにも1つぶん残っています。

横書きなら右端に空きが残るだけですが、縦書きではこの空きが下端に出ます。見本のヒーロー見出し(幅1200px時・font-size 24px・letter-spacing 7.2px)で内容の高さを測ると、指定を0にしたとき168px、0.3emのとき218.41pxでした。差の50.4pxは7.2px×7文字ぶんで、いちばん長い行の文字数と一致します。中央寄せするとこの空きも含めて中央に置かれるため、文字は見た目で3.6px(0.15em)上にずれます。直し方は、見出しの文字を1枚包んで末尾ぶんを相殺することです。

/* 修正前: 末尾の 0.3em ぶんだけ文字が上にずれて見える */
.hero h1 { letter-spacing: 0.3em; }

/* 修正後: 内側の要素で末尾ぶんを打ち消す */
.hero h1 > span { margin-bottom: -0.3em; }

この修正を当てて測り直すと、見出しの内容が3.6px下に動き、上下の余白が揃いました。0.15emぶんきっかり動くかどうかが、直せたかどうかの判定になります。定義は MDN: letter-spacing(2026-08-02取得)を参照してください。同じページには「letter-spacing が0以外のとき、標準合字などの任意の合字は適用されない」という注記もあります。


日本語の折り返しと禁則処理

先に結論を書きます。日本語だけの文章なら、禁則処理のためにCSSを足す必要はありません。ブラウザが既定で処理します。手当てが要るのは、英数字が連続したときです。

幅200pxの枠に「ふと立ち止まり、味わう和のひととき。日本の心、茶の香りと共に。」を入れ、line-break を auto/strict/anywhere と変えて各行の末尾文字を調べたところ、結果はいずれも同じで、行末に読点や句点は来ませんでした。word-break: break-all でも変わりません。一方、同じ枠に長いURLを含む文を入れると、既定では内寸200pxに対して中身が405pxになり、はみ出しました。指定を変えた結果は次のとおりです。

指定実測(枠200px)使いどころ
指定なし中身405px・はみ出す日本語だけの本文ならこれで十分
overflow-wrap: anywhere中身200px・収まる収まらないときだけ切る。本文向き
word-break: break-all中身200px・収まる常にどこでも切る。日本語の途中でも切れる
word-break: keep-all中身405px・はみ出したままこの用途では効かない(CJKの改行を止める指定)

お知らせや住所欄にはURLや英語の店名が入りやすいので、overflow-wrap: anywhere を本文の段落に当てておくのが無難です。MDN は break-all について「本来なら1語まるごと次の行に送れば済む場合でも、あふれるちょうどその位置で切る」と説明しており、見た目が荒れやすい点に注意が要ります。出典は MDN: overflow-wrapMDN: word-breakMDN: line-break(いずれも2026-08-02取得)です。


完成条件(自分で判定する基準)

「和風に見える」は判定になりません。次の5つが満たせていれば合格です。開発者ツールのコンソールに次を貼ると、1〜4をまとめて確認できます。完成見本のページで実行すると fontSize: "16px" / lineHeight: "28.8px" / writingMode: "vertical-rl" / textOrientation: "upright" / pageScrollW: 305 / windowW: 320 / tableScrolls: false が返りました(幅320px・2026-08-02実測)。

const cs = el => getComputedStyle(el);
const h1 = document.querySelector('.hero h1');
const w  = document.querySelector('.hours-wrapper');
console.table({
  fontSize:   cs(document.body).fontSize,
  lineHeight: cs(document.body).lineHeight,
  writingMode: cs(h1).writingMode,
  textOrientation: cs(h1).textOrientation,
  pageScrollW: document.documentElement.scrollWidth,
  windowW: innerWidth,
  tableScrolls: w.scrollWidth > w.clientWidth
});
  1. 行間が文字サイズの1.8倍。lineHeight が fontSize の1.8倍(16pxなら28.8px)。外れたら line-height に px や em を付けていないかを疑う。
  2. 見出しが縦方向に流れ、英数字も正立する。writingMode が vertical-rl、textOrientation が upright。外れたら text-orientation が初期値の mixed のままかを疑う。
  3. 幅320pxで横スクロールバーが出ない。pageScrollW が windowW 以下(見本は320px幅で305px)。外れたらヒーローの左右パディングか営業時間の表を疑う。
  4. 営業時間の表だけが横に流れる。tableScrolls が true で、かつ3も満たす。ここは見本そのものが false を返す箇所で、表に最小幅が無いためスクロールせずセルが潰れます。見本どおりでも課題は通りますが、true にできれば一段上です。
  5. 縦書き見出しの上下の余白が同じに見える。下だけ広く見えるなら、letter-spacing の末尾ぶんが残っている。

見本と1px単位で一致させる必要はありません。判定するのは比率と挙動です。行間が1.8倍で、縦書きが縦のまま流れ、狭い幅でページが溢れないなら、余白が数px違っていても通っています。写真も見本と同じものである必要はありません。


つまずきポイント

以下は完成見本を実際に測って再現できたものだけです。

症状原因直し方
縦書きの見出しが少しだけ上寄りに見えるletter-spacing の空きが行末(下端)に残り、それも含めて中央寄せされている文字を span で包み、margin-bottom に letter-spacing と同じ値の負数を入れる
幅320pxで営業時間の表の見出しが折り返し、行の高さが膨らむoverflow-x: auto を書いても、表に最小幅が無いと表のほうが縮んで収まってしまう表に min-width を与える。見本相当の内容では620pxで折り返しが消え、表だけが横に流れた
スマホ用に表の文字を小さくしたのに、見出し行だけ変わらないメディアクエリは詳細度を上げない。thead を含むセレクタが強く、後から書いても負ける詳細度を揃える。なお本文と表のセルは16pxを下回らない範囲で調整する
見出しを大きくしたら行が重なったline-height を em や px で指定し、計算後の長さが子へそのまま渡っている単位なしの数値に戻す
長いURLや英語の店名を入れた段落だけ枠からはみ出す日本語の折り返し規則は、英数字が続く部分には効かないその段落に overflow-wrap: anywhere を当てる
/* 修正前: 表が縮むだけでスクロールしない */
.hours-wrapper { overflow-x: auto; }

/* 修正後: 表に最小幅を与えて、はみ出しをラッパーに逃がす */
.hours-wrapper { overflow-x: auto; }
.hours-table   { min-width: 620px; }

次の課題と関連記事

1つ前は 模写中級 #001(CSS Gridで作るポートフォリオ) です。グリッドで面を割る練習なので、この課題の縦のリズムとは別の筋肉を使います。次は 模写中級 #003(ジムのサンプルサイト) で、写真主体のセクションを積む構成に進みます。

レベルを選び直したいときは 模写コーディング一覧 から他の課題を見てください。フォントの選び方に迷ったら Webデザインのフォント選び完全ガイド が明朝とゴシックの使い分けをまとめています。CSSの書き方そのものを引きたいときは CSS実装テクニック集 が索引になります。


よくある質問(FAQ)

Q. 縦書きにしたのに英数字が寝てしまいます。どこが違いますか?

text-orientation の初期値 mixed が効いています。mixed は横書き用の文字を時計回りに90度回す指定なので、縦書きの中で英数字を正立させたいときは text-orientation: upright を明示してください。なお upright は direction の使用値を ltr に固定するとMDNに明記されています。

Q. line-height に単位を付けると何が変わりますか?

単位なしの数値は「その数値」が子へ継承され、子は自分の文字サイズに掛けて行間を決めます。em や px を付けると計算後の長さがそのまま渡るため、文字サイズが違う子要素で行が重なります。実測では親20px・1.8 のとき40pxの子は72px、1.8em では子も36pxのままでした。

Q. 営業時間の表がスマホで潰れます。列を減らすべきですか?

列は減らさず、表に min-width を与えて横スクロールに逃がすのが定石です。くるむ要素に overflow-x: auto を書いただけでは表のほうが縮んで収まるため、スクロールバーは出ません。実測では幅320pxのとき、min-width なしだと表の内寸が275pxに縮んで見出し行が72.8pxに膨らみ、620pxを足すと46.9pxに戻って表だけが流れました。

Q. 明朝体のWebフォントを読み込む場合、font-display はどれを選べばよいですか?

見本はWebフォントを読み込まず端末の明朝体を指定しているため、font-display の出番はありません。@font-face で和文フォントを足す場合は、MDNの説明どおり block(短いあいだ文字を隠して待つ)と swap(すぐ代替フォントで出して後から差し替える)で見え方が変わります。和文はファイルが大きいので、まず swap で差し替わり方を目で確認してから選んでください(MDN: font-display・2026-08-02取得)。

Q. 日本語の禁則処理は自分でCSSを書く必要がありますか?

日本語だけの文章なら不要です。幅200pxの枠で line-break を auto/strict/anywhere と変えて各行の末尾文字を調べたところ、いずれも行末に読点や句点は来ませんでした。手当てが要るのは英数字が連続したときで、長いURLを含む段落は既定ではみ出します(枠200pxに対し中身405px)。その場合は overflow-wrap: anywhere を当ててください。

Q. 和文の字形を細かく調整したいときは font-feature-settings を使えばよいですか?

まず font-variant 系を検討してください。MDNは font-feature-settings について「可能な限り font-variant の一括指定か font-variant-east-asian などの個別プロパティを使うべきで、他に手段がない特殊なケースのための低レベルな機能である」と明記しています。この課題では、字形より先に行間と字間を合わせるほうが効き目が大きいです(MDN: font-feature-settings・2026-08-02取得)。