今更学ぶ CSS Multi-column Layout の使い所

## はじめに

横並びのレイアウトは近年では Flexbox や CSS Grid 、少し前でしたら float によるレイアウトなどの手法があります。
自分はまず反射的に Flexbox を使用することが頭に浮かびますが、場合によっては CSS Multi-column Layout を使うことで、文書構造に沿った HTML のまま段組レイアウトを実装することができます。

[MDN web docs 段組みレイアウト](https://developer.mozilla.org/ja/docs/Learn/CSS/CSS_layout/Multiple-column_Layout)

## ブラウザ対応状況

マルチカラムレイアウトは `column-count` プロパティによって段組レイアウトが行われます。
比較的長く使われているプロパティで、対応ブラウザの幅も広いようです。

<img width="1360" alt="スクリーンショット 2020-08-02 17.50.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390806/b515618b-852a-a08e-9052-15e2636053dd.png">

## CSS Multi-column Layout でできること

よくサンプルとして上げられるのは、雑誌などに見られる段組テキストのレイアウトです。
`column-count` プロパティを設定することで、各カラムが同程度の高さに調整されたマルチカラムレイアウトを実現することができます。

```html:index.html
<p class="text">吾輩は猫である。名前はまだ無い。どこで生れたかとんと見当がつかぬ。何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。吾輩はここで始めて人間というものを見た。しかもあとで聞くとそれは書生という人間中で一番獰悪な種族であったそうだ。この書生というのは時々我々を捕えて煮て食うという話である。しかしその当時は何という考もなかったから別段恐しいとも思わなかった。ただ彼の掌に載せられてスーと持ち上げられた時何だかフワフワした感じがあったばかりである。掌の上で少し落ちついて書生の顔を見たのがいわゆる人間というものの見始であろう。この時妙なものだと思った感じが今でも残っている。第一毛をもって装飾されべきはずの顔がつるつるしてまるで薬缶だ。その後猫にもだいぶ逢ったがこんな片輪には一度も出会わした事がない。のみならず顔の真中があまりに突起している。そうしてその穴の中から時々ぷうぷうと煙を吹く。どうも咽せぽくて実に弱った。これが人間の飲む煙草というものである事はようやくこの頃知った。</p>
```

```scss:main.css
.text {
  column-count: 2;
}
```

<img width="988" alt="スクリーンショット 2020-08-02 19.25.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390806/4ef82c90-48ee-0061-06a5-547dae1307cb.png">


3 カラム以上のレイアウトも同様に実装可能です。

```scss:main.css
.text {
  column-count: 3;
}
```

<img width="993" alt="スクリーンショット 2020-08-02 19.35.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390806/fa31a377-dee7-a616-4d87-c5f4c48789c3.png">

また[`column-width`](https://developer.mozilla.org/ja/docs/Web/CSS/column-width) プロパティや [`column-gap`](https://developer.mozilla.org/ja/docs/Web/CSS/column-gap) プロパティを使用することによって段組幅やギャップ（列間隔）の調整を行うことも可能です。

## 表の段組レイアウトで使用する

横方向へ見ていく表であれば Flexbox が良さそうですが、縦方向の表となるとすこし厄介です。

<img width="686" alt="スクリーンショット 2020-08-02 23.35.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390806/9bdd748f-d9b1-57dc-8d60-02bf03bdcc9d.png">

Flexbox でのレイアウトを行おうとすると、本来不要な位置でマークアップを分割する必要が出てしまいますが、マルチカラムレイアウトを使用することでマークアップを分割することなく調整が可能です。
また子要素数の増減も HTML への要素の追加・削除のみで簡単に行うことができます。

<details><summary>マークアップ</summary><div>

```html:index.html
<div class="nutrition">
  <dl class="nutrition_list">
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">エネルギー</dt>
      <dd class="nutrition_listAmount">240kcal</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">タンパク質</dt>
      <dd class="nutrition_listAmount">4.4g</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">脂質</dt>
      <dd class="nutrition_listAmount">10.2g</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">炭水化物</dt>
      <dd class="nutrition_listAmount">18.7g</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">糖質</dt>
      <dd class="nutrition_listAmount">19.7g</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">食物繊維</dt>
      <dd class="nutrition_listAmount">2g</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">食塩相当量</dt>
      <dd class="nutrition_listAmount">0.64g</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">カルシウム</dt>
      <dd class="nutrition_listAmount">120mg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">鉄</dt>
      <dd class="nutrition_listAmount">1mg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">マグネシウム</dt>
      <dd class="nutrition_listAmount">230mg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">リン</dt>
      <dd class="nutrition_listAmount">47mg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">ビタミンA</dt>
      <dd class="nutrition_listAmount">205μg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">ビタミンB1</dt>
      <dd class="nutrition_listAmount">0.2mg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">ビタミンB2</dt>
      <dd class="nutrition_listAmount">0.3mg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">ビタミンB6</dt>
      <dd class="nutrition_listAmount">0.3mg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">ビタミンB12</dt>
      <dd class="nutrition_listAmount">0.7μg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">ナイアシン</dt>
      <dd class="nutrition_listAmount">3mg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">パントテン酸</dt>
      <dd class="nutrition_listAmount">1mg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">葉酸</dt>
      <dd class="nutrition_listAmount">50μg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">ビタミンC</dt>
      <dd class="nutrition_listAmount">20mg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">ビタミンD</dt>
      <dd class="nutrition_listAmount">1.3μg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">ビタミンE</dt>
      <dd class="nutrition_listAmount">1.4mg</dd>
    </div>
    <div class="nutrition_listInner">
      <dt class="nutrition_listHeading">(備考)<br>カリウム</dt>
      <dd class="nutrition_listAmount">40mg</dd>
    </div>
  </dl>
</div>
```

</div></details>

```scss:main.css
.nutrition_list {
  column-count: 2;
  column-gap: 24px;
}

.nutrition_listInner {
  break-inside: avoid;
  display: flex;
  margin-bottom: 4px;
}

_::-webkit-full-page-media, _:future, :root .nutrition_listInner {
  // Safari 調整用
  margin-top: 4px;
  margin-bottom: 0;
}

.nutrition_listHeading {
  flex-basis: 45%;
  padding: 8px 16px;
  background-color: hsl(100, 60, 84);
  font-size: 14px;
  font-weight: bold;
}

.nutrition_listAmount {
  display: flex;
  align-items: center;
  flex-grow: 1;
  padding: 8px 16px;
  background-color: hsl(210, 6, 94);
}
```

### break-inside: avoid; を指定する

上記のような表のレイアウト時には [`break-inside: avoid;`](https://developer.mozilla.org/ja/docs/Web/CSS/break-inside) プロパティを指定しておくことで、子要素の途中での改ページ/改カラムを防ぐことができます。
（似たもので [`page-break-inside`](https://developer.mozilla.org/ja/docs/Web/CSS/page-break-inside) プロパティがありますが、`break-inside: avoid;` によって置き換えられたプロパティのようです。）

<img width="1395" alt="スクリーンショット 2020-08-02 21.43.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390806/723320a8-49ab-eb1d-70f2-0510c428a964.png">

### 参考: Safari での若干の挙動の違い

上記のようなプロパティの指定を行なったマルチカラムレイアウトによる表の段組では、 Safari で若干挙動の違いが見られました。
下キャプチャのように、改カラム位置での `margin-bottom` が次カラムに影響を及ぼし、ズレが発生するようことがあるようです。

- Chrome
<img width="685" alt="スクリーンショット 2020-08-02 23.34.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390806/77d51bbd-1e32-dac5-06ba-3df0c385a4e8.png">

- Safari
<img width="690" alt="スクリーンショット 2020-08-02 23.34.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390806/55868049-b5e8-3448-bb9b-2b45939a7752.png">


Safari 対応用の CSS ハックによってレイアウトを調整しておきます。

```scss
_::-webkit-full-page-media, _:future, :root .nutrition_list {
  // Safari 調整用
  margin-top: -4px;
}

_::-webkit-full-page-media, _:future, :root .nutrition_listInner {
  // Safari 調整用
  margin-top: 4px;
  margin-bottom: 0;
}
```

## まとめ

あまり使用頻度の高いプロパティではないので自分は使ったことがなかったですが、必要に応じて使うことができるとよいプロパティだと思います。
Safari での挙動の違い以外にも、レイアウトがブラウザに一任されますのでブラウザごとで若干の挙動の違いがありそうです。
（挙動の差を許容・対応できるかどうか、がマルチカラムレイアウトを使用するかどうかの分かれ目になりそうですね。）
ポリフィルなどによる IE 対応を考えずに使用できるのは嬉しいところです。