読みやすい＝理解しやすい　Webの組版を整理してより良い文章を届けよう

この記事は[Qiita Advent Calendar 2021](https://qiita.com/advent-calendar/2021/qiita)の12日目の記事で、Qiita株式会社 CX向上グループの綿貫（@xrxoxcxox）が担当します！

https://qiita.com/advent-calendar/2021/qiita

## この記事の概要

Webの組版を現実的な手法で綺麗に整えるためのやり方をまとめました。

同じ内容の文章でも組版次第で読みやすさは変わります。
実は、意識していないとWebサイトの文章は余白がガタガタとかになりやすいんですね。

DTPに比べるとどうしても劣ってしまいますが、HTMLとCSSだけでできるだけ綺麗になるようにした & ステップバイステップで説明していますので良ければ真似てみてください！

ちなみに今回載せているコードは全てこちらのリポジトリにあります。

https://github.com/xrxoxcxox/qiita-css-typesetting

## 解決したいこと（≒よくあるWebの組版）

- 余白がガタガタ
- 見出しや本文のジャンプ率が適切でなく目が滑る
- 禁則処理がほぼ何も無い

あまり意識したことは無いかもしれませんが、こういったものを整えるだけでも随分印象が変わります！

## 実際にやっていく

### まずはテキストを用意する

まずは最低限だけUser agent stylesheetをリセットしてテキストを貼り付けてみます。

| 幅1366pxの画面 |
| --- |
| ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/7e36e05b-74e8-40e1-6899-e7e2db27b8a3.png) |

完全に怪文書ですが、ダミーテキスト生成サイトで用意した文章をベースに作成しました。

https://lipsum.sugutsukaeru.jp/index.cgi

今のコードはこんな感じ

```html:index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="./style.css">
    <title>Qiita CSS Typesetting</title>
  </head>
  <body>
    <div class="body-text">
      <h1>へんも蚊のおねがい人らを鳥にちがい扉ましだ。</h1>
      <p>ではどう生意気たたて写真たまし。外いただけこのねどこ拍子手へおまえ一枚のままへコップを過ぎようまいことじは、みんながもまた愉快だろてかい。</p>
      <h2>何まで大物を追い払っしのだた。</h2>
      <!-- 以下略 -->
    </div>
  </body>
</html>
```

```css:style.css
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

::before, ::after {
  box-sizing: border-box;
}
```

### テキストの横幅を制御する

先ほどの画像を見て分かるとおり、1行あたりの文字数があまりにも多すぎるため非常に読みづらいです。
よくある説として1行30~40文字が読みやすいとあるのでそれを採用し、35文字としてみました。

https://www.shoubaisekkei.co.jp/column/number-of-characters

https://yuyakinoshita.com/blog/2019/01/31/readability-and-typography/

https://www.jimdo.com/jp/checklist-for-clear-readable-website-text/

| 横幅の制限なし | 1行35文字に制限 |
| --- | --- |
| ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/7e36e05b-74e8-40e1-6899-e7e2db27b8a3.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/88fc3a07-44fe-764c-c5d9-a74e220a89ee.png) |

ページが縦には長くなりましたが、こちらの方が少しは読みやすいですね。
現在のコードはこんな感じ。（HTMLは変更無し）

```css:style.css
.body-text {
  display: grid;
  grid-template-columns: min(100%, 35em);
  justify-content: center;
  padding: 2rem 1rem;
}
```

`px`ではなく`em`で横幅を指定したのは、和文の文字は仮想ボディと呼ばれる正方形の枠に収まっているからです。
そのため`35em`とはニアリーイコールで35文字分の幅を取ります。[^1]

[^1]: もちろん途中で英単語が挟まったりカーニング設定を施したりすれば話は別です。そのためニアリーイコールと記載しました。

### それぞれのテキストのサイズにモジュラースケールを適用してバーティカルリズムも揃える

テキストのサイズを決めるときには一般的にはモジュラースケールを使います。
何かのサイズを基準にして、決まった比率を掛けていくことで均整のとれたスケールが出来上がるんですね。

今回は以下の式で計算してみます。

```math
f_n = 16 \times 2^{\frac{n}{5}}
```

CSSではルートの計算が上手くできないので、実際に計算した値を四捨五入して以下のスケールとします

- 14
- 16
- 18
- 21
- 24
- 28
- 32

なお計算が面倒と思われる方もいると思いますがこちらのサイトで簡単にシミュレーションしてくれます。

http://simplescale.online/

適用するとこのようになりました。

| デフォルトのフォントサイズ | モジュラースケールの適用 |
| --- | --- |
| ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/88fc3a07-44fe-764c-c5d9-a74e220a89ee.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/cdfaa3d8-89a7-3955-2525-68c6ddac850b.png) |

コードはこちら。

```css:style.css
.body-text h1 {
  font-size: 2rem;
  line-height: calc(0.25rem * 13);
}

.body-text h2 {
  font-size: 1.75rem;
  line-height: calc(0.25rem * 12);
}

.body-text h3 {
  font-size: 1.5rem;
  line-height: calc(0.25rem * 10);
}

.body-text h4 {
  font-size: 1.3125rem;
  line-height: calc(0.25rem * 9);
}

.body-text h5 {
  font-size: 1.125rem;
  line-height: calc(0.25rem * 8);
}

.body-text h6 {
  font-size: 0.875rem;
  line-height: calc(0.25rem * 6);
}

.body-text p {
  font-size: 1rem;
  line-height: calc(0.25rem * 7);
}
```

:::note warn
CSSカスタムプロパティあたりを使って上手く共通化できそうな内容ですし、その方がコードとしては綺麗だと思いますが、今回は実施しません。
:::

しれっと`line-height`の変更もしていますが、これはバーティカルリズムを整えるためです。
常に0.25remの整数倍（実質4pxの整数倍）になるようにしているので、テキストのブロックが整然と並んで見えるのではないでしょうか。
バーティカルリズムについては以下の記事が詳しいです。

https://postd.cc/why-vertical-rhythms/

また、モジュラースケールの考え方は他にもいくつかバリエーションがあります。
以下は参考記事です。

https://qiita.com/degudegu2510/items/f6a6d924fb430c6f3e38

https://qiita.com/nm7279/items/3c737fa735cc45a78e10

### 段落間の余白をあける

今のままでは段落間がぎゅうぎゅうなので、余白を設定します。
これもバーティカルリズムが綺麗になるよう、0.25remの整数倍のマージンを指定します。

| 余白無し | 余白有り |
| --- | --- |
| ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/cdfaa3d8-89a7-3955-2525-68c6ddac850b.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/53112ee8-d5c4-cbe3-5c20-ffed87fb10ce.png) |

```css:style.css
.body-text * + h2 {
  margin-top: calc(0.25rem * 11);
}

.body-text * + h3 {
  margin-top: calc(0.25rem * 10);
}

.body-text * + h4 {
  margin-top: calc(0.25rem * 8);
}

.body-text * + h5 {
  margin-top: calc(0.25rem * 7);
}

.body-text * + h6 {
  margin-top: calc(0.25rem * 6);
}

.body-text * + p {
  margin-top: calc(0.25rem * 5);
}
```

ここは特別言及するようなことも無いと思います。

### font-familyを変更する

以下の2つの理由のためにWebフォントを使います。

- 和欧混植
- 約物の調整

:::note warn
最近は心配が少なめになってきたとは言え、Webフォントを使うとスピードが下がります。この章は基本的にはWebフォントを使わないと実現できないのですが、実際のプロジェクトの具合にあわせて採用するかを決めてください。
:::

| デフォルトのフォント | Yaku Han JP + Noto Sans + Noto Sans JP |
| --- | --- |
| ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/53112ee8-d5c4-cbe3-5c20-ffed87fb10ce.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/32e94b9b-42a7-8f01-1726-5afca9d2b04f.png) |

コードはこのようになっています。

```diff_html:index.html
    <head>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+     <link rel="preconnect" href="https://fonts.googleapis.com">
+     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+     <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&family=Noto+Sans:wght@400;700&display=swap" rel="stylesheet">
+     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/yakuhanjp@3.4.1/dist/css/yakuhanjp_s-noto.min.css">
      <link rel="stylesheet" href="./style.css" />
      <title>Qiita CSS Typesetting</title>
    </head>
```

```css:style.css
body {
  font-family: 'YakuHanJPs_Noto', 'Noto Sans', 'Noto Sans JP', sans-serif;
}
```

`Noto Sans`を`Noto Sans JP`より前に指定することで、英数字は`Noto Sans`、日本語は`Noto Sans JP`で表示されます。
実は`Noto Sans`と`Noto Sans JP`は別のフォントで、同じ文字でもタイプフェイスが違います。
個人的には英数字は`Noto Sans`の方が好きなので変更しました。

また、`Yaku Han JP`を使うことで間延びしがちな約物類をぎゅっとまとめています。
句読点まで半角にすると詰まりすぎに思ったので`Small`の方を選択しました。

https://fonts.google.com/noto/specimen/Noto+Sans

https://fonts.google.com/noto/specimen/Noto+Sans+JP

https://yakuhanjp.qranoko.jp/

ちなみに有料ですがFONTPLUSというサービス経由でフォントを配信すると、約物まわりは更に綺麗になります。

https://fontplus.jp/usage/services/chws-vchw

### 見出しはツメる

私は本文はベタ組み（っぽく見える調整）が好きなのですが、見出しは文字サイズが大きいのもありますからツメ組みの方が良さそうです。

| 見出しそのまま | 見出しにfont-feature-settings: "palt"; |
| --- | --- |
| ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/32e94b9b-42a7-8f01-1726-5afca9d2b04f.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/07468475-045d-ec5a-f8c8-4337f9d4687a.png) |

```diff_css:style.css
  .body-text h1 {
+   font-feature-settings: "palt";
    font-size: 2rem;
    line-height: calc(0.25rem * 13);
  }

  .body-text h2 {
+   font-feature-settings: "palt";
    font-size: 1.75rem;
    line-height: calc(0.25rem * 12);
  }

  .body-text h3 {
+   font-feature-settings: "palt";
    font-size: 1.5rem;
    line-height: calc(0.25rem * 10);
  }

  .body-text h4 {
+   font-feature-settings: "palt";
    font-size: 1.3125rem;
    line-height: calc(0.25rem * 9);
  }

  .body-text h5 {
+   font-feature-settings: "palt";
    font-size: 1.125rem;
    line-height: calc(0.25rem * 8);
  }

  .body-text h6 {
+   font-feature-settings: "palt";
    font-size: 0.875rem;
    line-height: calc(0.25rem * 6);
  }
```

若干間延びしていた印象のある見出しですが、割とすっきりしたと思います。
font-feature-settingsについてはAdobeのこのページが分かりやすいので紹介します。

https://helpx.adobe.com/jp/fonts/using/open-type-syntax.html

### 禁則処理を追加する

かなり細かいので、1番分かりやすい箇所を示します。

| ハイフネーション無し | ハイフネーション有り |
| --- | --- |
| ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/76255fd3-0951-4d86-363a-b85c78429dee.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/0d9c6162-3125-9712-5736-fe71dc43f8c6.png) |

`pneumonoultramicroscopicsilicovolcanoconiosis`というやたら長い単語がを表示するために無理矢理改行されてしまっていたのを、音節をハイフンでつないで「1つの単語である」と分かるようにして表示できるようになりました。
もちろん余白の見え方も良くなっています。

```diff_css:style.css
  body {
    font-family: 'YakuHanJPs_Noto', 'Noto Sans', 'Noto Sans JP', sans-serif;
+   hyphens: auto;
+   line-break: strict;
+   overflow-wrap: break-word;
+   word-break: break-word;
  }
```

改行の際にどのような挙動をするか、なのでQiitaの記事上で示すのがなかなか難しいのですが、細かく説明してくださっているサイトがありました。

https://onebitious.net/prohibition/

図らずもというか、今回私が書いている内容とほぼ同じものになっています。
（word-wrapは、まあ良いかな……と思って省略しました笑）

## まとめ

| 最初の状態 | 最後の状態 |
| --- | --- |
| ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/7e36e05b-74e8-40e1-6899-e7e2db27b8a3.png) | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/a7667cd6-a4de-eb05-13a0-a48f4a5da5b2.png) |

- テキストの横幅を制御する
    - 読みやすい文字数は1行30-40文字
- モジュラースケールやバーティカルリズムを整える
    - 規則的に変化させたり配置したりすることで読みやすくなる
- font-familyを変更する
    - 和欧混植
    - 約物の調整
- 見出しはツメる
    - 間延びして見えがちなのでCSSの機能でツメる
- 禁則処理を追加する
    - 変な箇所で改行されたり、ボックスから文字が溢れてしまうのを防ぐ

Qiita Advent Calendar 2021 の 13 日目は、 @gilly が担当します、お楽しみに:christmas_tree: