classのシンプルなグリッドシステム
- プロダクション
今やWebページのレイアウトメソッドとしてすっかり定着したグリッドデザイン。近年では、flex-boxやCSS gridの登場でますます使い勝手が良くなっていますね。一方で、マルチカラムレイアウトのためだけにBootstrapなどの大がかりなフレームワークを導入したり、複雑なCSSを書き起こしたりするのはちょっとめんどう。

12カラムグリッドシステムのイメージ
そこで今回は、簡単なclassだけで手軽に3パート・レスポンシブのマルチカラムレイアウトを実現するシンプルなグリッドシステムを作ってみます。
いつも悩ましい多重class
広く利用されているコンポーネントフレームワークBootstrapにも、一般的な12分割タイプのグリッドシステムが搭載されています。たとえば「スマホは2カラム、タブレットは3カラム、PCは4カラムで」といったレイアウトをする場合、下のようにclassを記述します。
<div class="row"> <div class="col-6 col-md-4 col-xl-3"></div> <div class="col-6 col-md-4 col-xl-3"></div> <div class="col-6 col-md-4 col-xl-3"></div> <div class="col-6 col-md-4 col-xl-3"></div> </div>
Bootstrapのグリッドシステムは「12を分母とする分数の分子」で列幅を指定するのが特徴で、指定方法こそ慣れれば問題ないものの、classがいくつも並ぶのはもう少しすっきりさせたい気がします。また、12分数で表現できない5カラムや8カラムといった列数が実現できないのも少し物足りないですね。
1クラスで書けたら簡単だけど……
シンプルにひとつのclassだけでメディア別に異なるカラム数を設定したい。たとえば上記の「スマホは2カラム、タブレットは3カラム、PCは4カラム」というレイアウトならば、
<div class="row"> <div class="col2-3-4"></div> <div class="col2-3-4"></div> <div class="col2-3-4"></div> <div class="col2-3-4"></div> </div>
こんな風に1クラスで書けたら、直感的だし楽チンでよいのではないでしょうか(ハイフンで区切られた3つの数字には1~12の何を入れてもよい)。ついでに5カラム、7カラム、8カラムといった、12分割ルールでは割り切れなかった段組みにも対応できたらもっとすてきです。
パターンは5,184通り
ですが、1クラスであらゆるレイアウトパターンを網羅しようとすると、
12×12×12×3=5184
OMG、5,184通りものスタイルを定義しなければいけません。
.col1-1-1 { width: 100%;}
.col2-1-1 { width: 50%;}
.col3-1-1 { width: 33.3333%;}
:
:
.col12-12-10 { width: calc( 100% / 10 );}
.col12-12-11 { width: calc( 100% / 11 );}
.col12-12-12 { width: calc( 100% / 12 );}
5,184通りを列挙することじたいはExcelなどを使えばたやすいですが、このシステムだけのために5000行以上あるCSSをページに読み込ませるのは人道にもとる行為とのそしりをまぬがれません。もっと合理的な方法を考えましょう。
属性セレクタを使う
属性セレクタには、属性名、属性値の完全一致、前方一致、後方一致、部分一致など多様なマッチングオプションがあります。これをうまく活用すれば5,184種類のスタイルを賢く合理化できそうです。
ハイフンで区切られた3つの数字のうち、最初の数字は前方一致、真ん中の数字は部分一致、最後の数字は後方一致でマッチングさせます。
/* 前方一致・スマホ用 */
[class^="col1-"] { width: 100%;}
[class^="col2-"] { width: 50%;}
:
:
/* 部分一致・タブレット用 */
[class*="-1-"] { width: 100%;}
[class*="-2-"] { width: 50%;}
:
:
/* 後方一致・PC用 */
[class$="-1"] { width: 100%;}
[class$="-2"] { width: 50%;}
:
:
これなら、それぞれのメディアクエリについて12種類ずつ、計36パターンのスタイルを定義するだけで5,184通りのレイアウトに対応できます。
できました!
CSS
.row {
display: flex;
flex-wrap: wrap;
}
.row > * {
flex-grow: 0;
flex-shrink: 0;
}
.row [class^="col1-"] { width: calc( 100% / 1 );}
.row [class^="col2-"] { width: calc( 100% / 2 );}
.row [class^="col3-"] { width: calc( 100% / 3 );}
.row [class^="col4-"] { width: calc( 100% / 4 );}
.row [class^="col5-"] { width: calc( 100% / 5 );}
.row [class^="col6-"] { width: calc( 100% / 6 );}
.row [class^="col7-"] { width: calc( 100% / 7 );}
.row [class^="col8-"] { width: calc( 100% / 8 );}
.row [class^="col9-"] { width: calc( 100% / 9 );}
.row [class^="col10-"] { width: calc( 100% / 10 );}
.row [class^="col11-"] { width: calc( 100% / 11 );}
.row [class^="col12-"] { width: calc( 100% / 12 );}
@media (min-width: 668px) {
.row [class*="-1-"] { width: calc( 100% / 1 );}
.row [class*="-2-"] { width: calc( 100% / 2 );}
.row [class*="-3-"] { width: calc( 100% / 3 );}
.row [class*="-4-"] { width: calc( 100% / 4 );}
.row [class*="-5-"] { width: calc( 100% / 5 );}
.row [class*="-6-"] { width: calc( 100% / 6 );}
.row [class*="-7-"] { width: calc( 100% / 7 );}
.row [class*="-8-"] { width: calc( 100% / 8 );}
.row [class*="-9-"] { width: calc( 100% / 9 );}
.row [class*="-10-"] { width: calc( 100% / 10 );}
.row [class*="-11-"] { width: calc( 100% / 11 );}
.row [class*="-12-"] { width: calc( 100% / 12 );}
}
@media (min-width: 1025px) {
.row [class$="-1"] { width: calc( 100% / 1 );}
.row [class$="-2"] { width: calc( 100% / 2 );}
.row [class$="-3"] { width: calc( 100% / 3 );}
.row [class$="-4"] { width: calc( 100% / 4 );}
.row [class$="-5"] { width: calc( 100% / 5 );}
.row [class$="-6"] { width: calc( 100% / 6 );}
.row [class$="-7"] { width: calc( 100% / 7 );}
.row [class$="-8"] { width: calc( 100% / 8 );}
.row [class$="-9"] { width: calc( 100% / 9 );}
.row [class$="-10"] { width: calc( 100% / 10 );}
.row [class$="-11"] { width: calc( 100% / 11 );}
.row [class$="-12"] { width: calc( 100% / 12 );}
}
Sass
.row {
display: flex;
flex-wrap: wrap;
> * {
flex-grow: 0;
flex-shrink: 0;
}
@for $i from 1 through 12 {
[class^="col#{$i}-"] {
width:calc( 100% / #{$i} );
}
}
@media ( min-width: 668px ) {
@for $i from 1 through 12 {
[class*="-#{$i}-"] {
width:calc( 100% / #{$i} );
}
}
}
@media ( min-width: 1025px ) {
@for $i from 1 through 12 {
[class$="-#{$i}"] {
width:calc( 100% / #{$i} );
}
}
}
}
この記事に関するご相談やご質問など、お気軽にお問い合わせください。
関連する記事
-
JavaScriptをマルチスレッドで動かす方法
プロダクション
-
CSSグラデーションにアンチエイリアスを
プロダクション
-
CSS千本ノック~国旗を作ろう~
プロダクション
