新しい CSS レイアウトモジュール
スタイルシートの新バージョン CSS3 では、角丸、グラデーション、透過、アニメーションなどの視覚効果やレイアウトなどまったく新しい機能が使えるようになりました。レイアウト面では、今まで float、position プロパティぐらいでしたが、 マルチスクリーン、レスポンシブ Web も簡単にできるレイアウトモジュールが使えるようになりました。ここでは3種類の新しい CSS レイアウトモジュールをご紹介します。(2017年 4月)
Contents
マルチカラムレイアウト(段組みレイアウト)
新聞や雑誌の記事のようにコンテンツを複数のカラムに分けて、テキストがカラム幅に応じて隣の列に折り返し整列していく段組みレイアウトです。
下記の例は、画面幅を 300px で分割してカラムコンテンツを折り返し表示するように指定しています。カラム列の境目の間隔は 30px で線幅 2px の破線で区切られます。
#columns {
max-width: 1000px; /* 画面幅は%か、最大幅を指定*/
column-width: 300px;/* カラム幅(%値は不可)*/
column-gap: 30px; /* カラムの間隔*/
column-rule: 2px dotted #333;
} /* カラム間の区切線(border と同じ書式)*/
【HTML】
<article id="columns">
<p>カラム・・・・</p>
</article>
下図のように column-width:
は、カラム幅、column-gap:
は、隣接カラムとの間隔で、省略するとブラウザの初期値(約 1em)に設定されます。column-rule:
はその間隔の中央に入る区切り線のスタイルで、border
と同じ書式になります。寸法値はすべて実数値単位(em、px、pt、cm など)を使用します。
%指定は不可です。
カラム数 column-count
と、カラム幅 column-width
プロパティ
マルチカラム(段組み)レイアウトにするには、「カラム数」か、「カラム幅」を指定します。そのどちらかを指定したとき他方は、auto
になります。
カラム数指定 column-count
の場合は、利用可能領域を指定した数のカラム数に分割し整形表示します。画面幅に応じて指定したカラム数を維持しカラム幅が変化します。
カラム幅指定 column-width
の場合は、利用可能領域を指定した幅で分割整形表示されます。画面幅に応じて指定した幅を下まわらないようにカラム数が変化します。「幅」の指定は、%値以外の実数値指定です。
上のサンプルは、カラム幅 column-width
指定したサンプルです。画面幅に応じて指定したカラム幅 300px を下まわらないようにカラム数が変化します。
カラム数とカラム幅のショートハンド指定
カラム数 column-count
と、カラム幅 column-width
を設定するための略式プロパティです。 省略するとその初期値 auto
に設定されます。
columns: <‘column-width’> || <‘column-count’>
カラム数とカラム幅の両方を指定した場合、利用可能幅に応じて、指定する「数」は分割数の最大限の数になり、「幅」は分割幅の最小限の幅になるようにカラム数と幅が計算され配置されます。
カラム幅かカラム数のどちらか一方だけ指定した場合は、他方は auto
になり、auto
は省略できるので、数を自動にする columns: 300px;
か、幅を自動にする columns: 3;
になります。
従って、「数」か「幅」の優先したいほうを指定する下記の4種になります。
columns: 300px; column-width: 300px; /* 数が自動配置 */
columns: 3; column-count: 3 /* 幅が自動配置 */
「カラム幅」と「カラム数」の両者とも設定することが有意義になる場合
通常、必要な「カラム幅」を設定するだけでレスポンシブに対応できるので、「カラム数」も同時に設定することは稀です。ショートハンド columns:
でカラム幅とカラム数の両者を設定することがどんな場合に有意義になるのか?
設定するカラム数は、最大限の数になるので表示されるカラム数を制限する形になります。例えば、カラム要素幅(画面サイズ)が大きい場合にカラム数が多くなり過ぎるようなとき、カラム数を制限するように設定することで分割数を抑えてバランスがとれることがあります。
サンプル表示(2) (1,000px 以上の画面サイズで有効)
カラム要素がテーブルセルやフロートの場合
カラム要素の幅が決定されていないテーブルセルやフロートの場合は、「カラム数」を決められないためにマルチカラムレイアウトはできません。テーブルセルやフロートがカラム要素の場合は、幅を明確にしておく必要があります。width
指定は必須です。「カラム数」を決めてから「カラム幅」を確定させるアルゴリズムのようです。
カラム数とカラム幅の関係式
下記は、仕様 3.4 項の疑似アルゴリズムによるカラム幅指定したときのカラム数とカラム幅の関係式です。それほど難しい式ではないのでカラム幅の設定に参考になります。
width := column-width の設定値 gap := column-gap の設定値 U := 複カラム要素 の使用幅 C := column-count の使用値 W := column-width の使用値 C := max(1, floor((U + gap) ÷ (width + gap))) W := max(0, ((U + gap) ÷ C )−gap) ここで floor(X) は X を超えない最大の整数を返す関数 max(X, Y) は 最大値を返す関数
【 計算例 】
Excel によりカラム幅 260px、ギヤップ 10px、に設定したマルチカラムレイアウトを 画面幅 430px 〜1300px の範囲で 30px ステップでの実際のカラム幅(W)、カラム数(C)を計算してみた例です。画面幅に対するカラム幅とカラム数の推移を確認できます。
【 2行目セルの数式 】 (W :小数点以下切り捨て) C = MAX(1,FLOOR((A2+C2)/(B2+C2),1)) W = FLOOR(MAX(0,((A2+C2)/E2)-C2),1)
【 実例 】
表示幅が狭い場合の対応
ディスプレイの表示幅が狭い場合、最小表示幅を想定して支障のない幅を指定します。例のように column-width: 300px;
か、columns: 300px;
が適しています。ディスプレイ幅が狭くても指示された幅を維持するように動きます。
また、コンテンツ全体の幅指定は、「%」にするか、max-width: 1000px;
のように、max-
を入れて幅を固定サイズにしないリキッドタイプにします。(レスポンシブの場合は必須です)
列スパン(段抜き)指定column-span: all;
未対応だった Firefox は、v71 からカラム内容の詰め方プロパティが初期値の balance
では動作するようになりました。高さを指定して使用する auto
では、スパン行の前のカラムが分割されなかったり、他の後続ボックスが先に表示されるなど崩れます。(2019年 12月)
h2 {
column-span: all;
} /* カラムスパン有りは all、カラムスパン無しは none(初期値)*/
カラム要素を分割して column-span: all;
を使ってみる
カラムスパン「段抜き」は、将来的には具体的なカラム数を指定する機能拡張があるかもしれませんが、カラム要素をテーブルや後述のフレキシブルボックスレイアウトで分割して column-span: all;
を使用した例です。
新聞や雑誌のような固定レイアウトと違って Web レイアウトの場合は、画面サイズによりスパンカラム数も変化しなければならないので、コンテンツを分割すれば all
だけでも対応できるものがありそうです。
テーブルで2分割した例
2個のテーブルセルにコンテンツを分割してマルチカラムレイアウトした例です。
#columns {
display: table;
table-layout: fixed;/* 初期値 auto が適している */
width: 100%; /* 幅指定は必須 */
border-collapse: separate; /* ボーダーを分離(省略可)*/
border-spacing: 10px 0; /* 左右 10px、上下 0px */
}
.column-cell {
display: table-cell;
vertical-align: top;
border-left: 2px dotted #333;/* カラムセルの左ボーダー*/
padding-left: 10px;
}
.column-cell:first-child { /* 左カラムセルに適用させる */
border: none; /* セル左側のボーダーを除く */
padding-left: 0; /* カラムギャップと重なるので */
}
.multi-column {
columns: 180px;
column-gap: 20px;
column-rule: 2px dotted #333;
font-size: small;
}
h2 {
column-span: all; /* カラムスパンあり */
background: #eee;
padding: 5px;
}
/* 1カラムになるブレークポイント幅と同じか小さくする */
@media all and (max-width: 390px) {
.column-cell {
display: block;
border: none;
padding-left: 0;
}
}
【HTML】
<article id="columns">
<section class="column-cell">
<div class="multi-column">
<p>裏から・・</p>
<h2>不忍の池</h2>
<p>「御邪魔なら・・・</p>
</div>
</section>
<section class="column-cell">
<div class="multi-column">
<p>三四郎はちょっと・・・</p>
<h2>偉大なる暗闇</h2>
<p>「用事は決して・・・</p>
</div>
</section>
</article>
table-layout
プロパティは、全体を読み込んでからセルの幅を決める auto
が適していますが、ブラウザで表示が異なるので、fixed
にしています。
【 折り返した右セルと左セルのつなぎ目 】
画面サイズが狭くなると最終的には2カラムになります。最終カラムを1カラムにする場合は、メディアクエリでテーブルレイアウトを外して1カラムにします。このときのメディアクエリ設定幅は、マルチカラムレイアウトのブレークポイントよりも大きいと2カラム状態で折り返すため、下図のようにブレークポイント付近の右セルと左セルとのつなぎ目で「両流れ」状態になるので、マルチカラムのブレークポイント値と同じ値か小さくします。
フレキシブルボックスレイアウトで2分割した例
#columns {
display: flex; /* flex コンテナー */
flex-wrap: wrap; /* 折り返し複ライン*/
}
.column-cell {
flex: 160px;/*ブレークポイントをマルチカラムと同じか小さくする*/
border-left: 2px dotted #333; /* カラムセルの左ボーダー */
padding: 0 10px; /* 左右カラムセル間のギャップ20px */
}
.column-cell:first-child; { /* 左カラムセルに適用させて */
border: none; /* セル左側のボーダーを除く */
}
/* 1カラムになるブレークポイント幅と同じか小さくする */
@media all and (max-width: 390px) {
.column-cell {
border: none;
}
}
CSS は前記の「テーブルで2分割した例」と異なる部分です。flex-wrap: wrap;
プロパティで折り返し複ラインにしているので、テーブルレイアウトのメディアクエリ部分も兼ね備えた動作になります。
折り返したときの右セルのボーダーを除くところだけ メディアクエリで行っています。ボーダーがなければ不要です。
右セルが折り返して左セルとのつなぎ目で「両流れ」状態になる条件は、テーブルレイアウトと同じです。flex
基底値がブレークポイントを決めているのでマルチカラムレイアウトのブレークポイントと同じにしています。
テーブルレイアウトではメディアクエリで強制的に行いましたが、flex
を使用したこの例でもマルチカラムのブレークポイント値と同じか小さくします。小さくするとその差の区間はボーダーが残ります。
【 マルチカラムとフレキシブルボックスレイアウトのブレークポイントを合わせる 】
flex
アイテムのセレクタ column-cell
は、「flex: 160px; padding: 0 10px;
」にしているので flex
基底値は180px と同じで、マルチカラムレイアウトの幅指定180px と同じになります。
マルチカラムレイアウトとフレキシブルボックスレイアウトは、収容可能エリアに margin、padding
を含めて入りきれないときに折り返す論理は共通で同じことが分かります。
マルチカラム要素の内側と外側におけるオーバーフロー
カラムボックス内に収まりきらないコンテンツがある場合は、初期値のoverflow: visible
の状態でカラムボックスの内側と外側ともに切り取られないでオーバーフローするはずですが、ブラウザにより異なります。
画像挿入時の注意点
カラム幅を超えるサイズの画像を挿入する場合は、下図のように分割されたマルチカラム内側のカラムボックスに対して Firefox 以外はカラム幅で切り取られ、Firefox はカラムボックスからはみ出ます。
仕様 8.1項 「マルチカラム要素内側におけるオーバーフロー」が変更されて、「大きい画像などはカラム幅からはみ出しカラムボックスで切り取られない 」となりました。
マルチカラムの外側ボックスでは、どのブラウザもはみ出ますが、内側カラムボックスに対しては、 Firefox 以外のモダンブラウザではカラム幅で切り取られます。Firefox は仕様どおりのレンダリングのようですがよく分かりません。
CSSで、img { width: 100% }
を追加すると、どのブラウザもギャップを除いたカラム幅で切り取られるようになります。(2016年 7月)
この記事は 2016年 当時のものです。Chrome は v71 から、Opera も v57 から Firefox と同じように内側ボックスの横方向は切り取られなくなりましたが、新たな問題が判明しました。
Chrome、Opera は、下図のように画像を傾斜させた場合に折り返し部分の画像の縦方向にはみ出したエッジ部分が切り取られます。縦方向のオーバーフローの初期値 overflow: visible
が効いていないようです。
Firefox は、オーバーフローするとカラム領域(赤色のoutline
ボックス)が指定領域を越えて広がります。画像をアニメ加工しても同じように動きながら広がります。
IE、MS Edge は、カラムボックス内側のoverflow: visible
は未対応で切り取られますが、カラム領域の外側に対しては縦横ともに Firefox と同じようにはみ出します。
z-index 値による重なり順序付けについては、Chrome、Opera を除いてカラムボックスに position: relative
指定で重なりを制御できるようです。
以上の件は、IE11、MS Edge、Chrome、Opera、Firefox で確認しました。あまり問題にはならないかもしれませんが、傾斜した画像の「散らかしタイプのフォトギャラリー」を検討していて気づきましたのでご参考まで。(2018年 12月)
入りきらない画像の場合は、下記の CSS を追加しておくとマルチカラムレイアウトに限らず均等に伸縮表示してカラム内に収まります。
img { max-width: 100%; height: auto; }
カラム要素に高さ制限がある場合
通常、表示デバイスの縦方向は、height: auto
状態なので、コンテンツ内容に応じて設定されたカラム数や幅で縦方向に拡がり表示されますが、height
や max-height
でカラム高さが拘束されている場合は、
横方向の利用可能なスペースの外に設定カラム数を超えてカラムボックスがつくられオーバーフローになりスクロールバーが表示されます。
下記はカラム数 4、高さ制限 400px のサンプルです。
#column {
max-width: 800px;
height: 400px; /* 高さ制限あり */
columns: 4;
column-gap: 20px;
column-rule: 2px dotted #333;
font-size: small;
}
h2 {
column-span: all; /* カラムスパンあり */
background: #eee;
padding: 5px;
}
縦書き日本語マルチカラムレイアウト例
縦書きの場合は、縦書き用プロパティwriting-mode: vertical-rl;
を追加します。横書きの「カラム幅」指定は 90 度回転してカラム行の高さになります。
縦書きの場合の column-span: all;
は、縦方向の「段抜き」になります。横書きと同じように見出しタグ h
や、区切り線 hr
タグで分割することができます。
下記はスパンなしの縦書きカラムレイアウトの例です。
body {
font-family: Arial, sans-serif;
max-width: 900px;
margin: 20px auto 0;
}
#columns {
columns: 15em; /* カラム幅指定 */
column-gap: 20px;
column-rule: 2px dotted #333;
column-fill: auto; /* カラム内を詰める */
font-size: small;
width: 100%;
min-height: 700px;
overflow-y: scroll; /* Firefox以外の後続ボックス重なり対策 */
writing-mode: tb-rl;/*IE 縦書き独自仕様 */
writing-mode: vertical-rl;
}
p {
text-indent: 1em;
line-height: 1.5;
margin: 0;
}
/* Firefox CSSハックでスクロールバーを外す */
@-moz-document url-prefix() {
#columns {
overflow: visible;
}
}
【HTML】
<article id="columns">
<p>カラム・・・・</p>
</article>
縦書き日本語マルチカラムのレスポンシブ対応
冒頭の例のように、横書きのレスポンシブ対応では「カラム幅」を指定すると、その幅を下回らないように画面の下方向に拡がります。縦書きの場合は横スクロールもできますが、ここでは横書きと同じように画面幅が狭くなると表示画面の下方向に拡がるようにします。
縦書きでは、必要な「カラム数」だけ指定してもレスポンシブになります。縦書きでの「カラム幅」は、カラム内の行ボックスの長さを意味し、どちらの場合もカラム領域内で自動調整するために、使用できるカラム領域の大きさの幅と高さを意識しておく必要があります。
縦書きマルチカラムの後続ボックスが重なる
画面幅が狭くなると表示画面の下方向にカラムボックス下端が伸張する縦書きマルチカラムレイアウトでは、他の後続ボックスがカラムボックスの下方への変化を認識できず、下図のように初期配置された状態のまま重なる現象が起こります。
カラム詰め方プロパティは、カラム要素の高さが確定しないと正確に機能しません。、Firefox も同じように重なります。column-fill: auto;
の場合、Firefox だけは、カラムボックスの高さを指定しないか、min-height
指定すると後続ボックスの重なりは起こりません。height
指定や、カラム詰め方プロパティ初期値のbalance
のときは
横書きの場合は、高さ指定がない場合や、min-height
指定の高さが確定しないときは、Flrefox 以外のブラウザは、auto
にはならず初期値のbalance
表示になります。
重なりの回避策として上記の例では、overflow-y: scroll;
でスクロールバーを発生させ、正常な Firefox だけ CSS ハックを利用してスクロールバーを外しています。横書きの場合は、どのブラウザも後続ボックスは押し下げられるので必要ありません。(2018年 6月)
Firefox は、2019年 12月 v71 から列スパン(段抜き)指定 column-span: all;
が一部対応されました。同時に、上記の後続ボックスが重なる件が Firefox 以外のブラウザと同じように重なるようになりました。理由はよく分かりません。そのため前記の削除部分を訂正しました。従って、上記サンプルは Firefox も重なります。(2019年 12月)
カラム内容の詰め方プロパティcolumn-fill
各カラム内コンテンツの詰め方を指定するプロパティです。マルチカラム要素に高さが指定されていたり、画像表示などで高さを持っている場合に有効です。
プロパティ値 auto
の場合は height
指定が必須
カラム要素の高さを指定しない場合、初期値の balance
は、どのブラウザもコンテンツ内容から判断して均等に詰められます。
横書きでプロパティ値 auto
の場合、Firefox 以外(IE、MS Edge、Chrome、Opera)は、高さが確定しない min-height
のときは、初期値の balance
で表示されます。Chrome、Opera は、max-height
指定でも balance
で表示されます。縦書きでは、前記の例のように auto
になるようです。
仕様に忠実な Firefox だけは、カラム高さを指定しないときや min-height
指定のときは、高さが確定しないため最初のカラム列だけに詰められます。(2018年 12月)
column-fill: auto | balance | balance-all
プロパティ値 | 説 明 |
---|---|
auto |
各カラム内は順に詰められ必要な分だけ領域を占有する。 |
balance |
各カラム内が均等になるよう詰められる。(初期値) |
balance-all |
各カラム内の断片化されたコンテンツも詰められる。 |
使用例
body {
font-family: Arial, sans-serif;
}
.columns {
max-width: 1000px;
margin: 1em auto;
columns: 250px;
column-gap: 30px;
column-rule: 2px dotted #333;
font-size: small;
padding: 5px;
height: 200px; /* column-fill:auto の場合は高さ指定必須 */
outline: 1px solid red;
overflow-x: scroll;
}
.col-fill-auto {
column-fill: auto;
}
h2 {
background: #eee;
padding: 5px;
}
p {
text-indent: 1em;
line-height: 1.5;
margin: 0;
}
【HTML】
<h2>column-fill: balance</h2>
<article class="columns">
<p>裏から回って婆さんに聞くと、婆さんが小さな声で・・(省略)</p>
</article>
<h2>column-fill: auto</h2>
<article class="columns col-fill-auto">
<p>裏から回って婆さんに聞くと、婆さんが小さな声で・・(省略)</p>
</article>