CSSで段組みと内容の流し込みをするcolumnsプロパティの使い方

PCでAppleのサイトを表示した時のフッターメニュー (フッターサイトマップ) のように段組みして、なおかつ、画面サイズに応じて段の数を調整しつつ、内容の流し込みをする、columnsプロパティという非常に便利なCSSプロパティがあります。

しかし、実際に使ってみると、各ブラウザで意図したとおりに表示されない場合があって四苦八苦したので、意図したとおり表示される場合とされない場合を合わせてご紹介します。

各種プロパティの基礎知識

columnsプロパティ

columnsプロパティは段組みを設定するプロパティで、段の数を設定するcolumn-countプロパティと、段の基準幅を設定するcolumn-widthプロパティを一括設定できるショートハンドプロパティです。

column-countプロパティとcolumn-widthプロパティを同時に設定すると、column-countプロパティは段の最大数を意味するようになり、段組みを設定した要素 (段組み要素) の幅に応じて段の数が自動調整されます。そのため、レスポンシブデザインと非常に相性が良いです。

次のコードの _exmaple-1 と _example-2 には、段の最大数が3で、段の基準幅が20文字分の段組みを設定しています。_example-1 は一括設定した場合、_example-2 は個別に設定した場合です。

._example-1 {
  columns: 3 20em;
}
._example-2 {
  column-count: 3;
  column-width: 20em;
}

column-gapプロパティとcolumn-ruleプロパティ

columnsプロパティとは別に、段の間の幅を設定するcolumn-gapプロパティと、段の間の中央に罫線を設定するcolumn-ruleプロパティがあります。

column-ruleプロパティは、罫線の線種を設定するcolumn-rule-styleプロパティ、罫線の幅を設定するcolumn-rule-widthプロパティ、罫線の色を設定するcolumn-rule-colorプロパティを一括設定できるショートハンドプロパティです。

次のコードの _exmaple-1 と _example-2 には、段の間に2文字分の余白、その中央に幅4ピクセルで灰色の点線を設定しています。_example-1 は一括設定した場合、_example-2 は個別に設定した場合です。

._example-1 {
  columns: 3 20em;
  column-gap: 2em;
  column-rule: dotted 4px gray;
}
._example-2 {
  column-count: 3;
  column-width: 20em;
  column-gap: 2em;
  column-rule-style: dotted;
  column-rule-width: 4px;
  column-rule-color: gray;
}

break-beforeプロパティとbreak-afterプロパティとbreak-insideプロパティ

columnsプロパティによる段組みで内容が流し込みされる際、区切られたくない位置で段によって区切られてしまう場合があります。

break-beforeプロパティは設定した要素の前、break-afterプロパティは設定した要素の後、break-insideプロパティは設定した要素の内側での区切りをそれぞれ制御します。

ちなみに、これらのプロパティは元々、page-break-before、page-break-after、page-break-insideという印刷用 (@media print) の改ページを制御するためのプロパティでした。

Appleのフッターメニューをcolumnsプロパティで作り直してみる

AppleのUS版サイト (2019年9月現在) のフッターメニューは、簡略化すると次のようなコードになっています。

<nav>
  <div><!-- 1段目 -->
    <div>
      <h3>Shop and Learn</h3>
      <ul> … </ul>
    </div>
  </div>
  <div><!-- 2段目 -->
    <div>
      <h3>Services</h3>
      <ul> … </ul>
    </div>
    <div>
      <h3>Account</h3>
      <ul> … </ul>
    </div>
  </div>
  …
  <div><!-- 5段目 -->
    <div>
      <h3>Apple Values</h3>
      <ul> … </ul>
    </div>
    <div>
      <h3>About Apple</h3>
      <ul> … </ul>
    </div>
  </div>
</nav>

このように、段ごとにdiv要素でグループ化して、そのdiv要素を横一列に並べることで段組みを行っています。

この方法の欠点は、項目数が変化したときにグループ化し直す等の調整が必要になることです。WordPressに代表されるCMSを使用したサイトの場合、HTMLコードを出力するテンプレートやプログラムに手を入れる必要が出てきます。

columnsプロパティを使った場合は次のようなコードになります。

<style>
nav {
  columns: 5 180px;
  column-gap: 20px;
}
nav > div {
  break-inside: avoid;
}
…
</style>
…
<nav>
  <div>
    <h3>Shop and Learn</h3>
    <ul> … </ul>
  </div>
  <div>
    <h3>Services</h3>
    <ul> … </ul>
  </div>
  <div>
    <h3>Account</h3>
    <ul> … </ul>
  </div>
  …
  <div>
    <h3>Apple Values</h3>
    <ul> … </ul>
  </div>
  <div>
    <h3>About Apple</h3>
    <ul> … </ul>
  </div>
</nav>

HTMLについては、段ごとにグループ化する必要はなくなります。CSSについては、段組み要素 (このコードではnav要素) にcolumnsプロパティとcolumn-gapプロパティで段組みと余白の設定をし、段組み要素の子要素 (このコードではdiv要素) では、途中で区切られないようbreak-insideプロパティを設定しています。

Appleのサイトでは、画面サイズが一定の幅以下になると、横5段から縦1列に変化しますが、columnsプロパティを使った場合はグループ化されていないので、4段、3段、2段と柔軟に変化します。また、項目数が変化しても自動で内容の流し込みがされるので、メンテナンスフリーで非常に便利です。

メディアクエリ (Media Queries) を使用すれば、より柔軟にレイアウトが変更できます。

各ブラウザにおけるcolumnsプロパティの不具合

ここまで、良いこと尽くめのcolumnsプロパティですが、各ブラウザで意図しない表示結果になることがあります。

IE11とEdge (ms)

段組み要素の子要素に break-inside: avoid; を設定しているのにもかかわらず、要素内で区切られてしまう場合があります。

段組み要素の子要素に display: inline-block; width: 100%; を追加すると要素内で区切られなくなります。

Firefox (moz)

ブラウザをリサイズしているとき、段組みされた内容の流し込みがコロコロ変わる現象が起こる場合があります。

MDN Web Docs の CSSリファレンスでもcolumnsプロパティが使用されており、ブラウザをリサイズしていくと数ピクセル単位で流し込みが変化する箇所があります (2019年9月現在)。

ブラウザのリサイズは頻繁に行われる操作ではないため、無視してもいいかもしれません。

IE11、Edgeと同様に、段組み要素の子要素に display: inline-block; width: 100%; を追加すると流し込みが安定します。

Chrome (webkit)

Chromeの不具合はIE11、Edge、Firefoxと逆で、段組み要素の子要素に display: inline-block; width: 100%; があると、空の段ができてしまう場合があります。

不具合の対処法

IE11、Edge、Firefoxにだけ段組み要素の子要素に display: inline-block; width: 100%; を設定すると良さそうです。具体的には次のようなCSSコードになります。

nav > div {
  break-inside: avoid;
}
:-ms-lang(ie11, edge),
nav > div {
  display: inline-block;
  width: 100%;
}
_:-moz-focusring,
nav > div {
  display: inline-block;
  width: 100%;
}

段組み要素の子要素が display: block; なら、CSSハックで display: inline-block; を設定しますが、例えば display: flex; なら、CSSハックで display: inline-flex; を設定してください。

nav > div {
  break-inside: avoid;
  display: flex;
}
:-ms-lang(ie11, edge),
nav > div {
  display: inline-flex;
  width: 100%;
}
_:-moz-focusring,
nav > div {
  display: inline-flex;
  width: 100%;
}

「CodePen」によるcolumnsプロパティで再現したAppleのフッターメニュー

See the Pen CSS Multi-column Layout Test by nov (@numerofive) on CodePen.

ブラウザ毎に多少の不具合があるcolumnsプロパティですが、問題がある箇所をきちんと踏まえて使用すれば、普通に使えるくらいのレベルになっています。

これまでのメンテナンスを要する段組みから、columnsプロパティを使用した段組みに移行してみてはいかがでしょうか?

関連記事