コンサルティング
クリエイティブ・UX
テクノロジー
データドリブン
マーケティング
サービスについて
サービスについて
オピニオン
オピニオン
トライベック広報
トライベック広報
会社概要
会社概要
社長メッセージ
社長メッセージ
経営理念
経営理念
社名・ロゴの由来
社名・ロゴの由来
トライベック・ニューノーマル
トライベック・ニューノーマル
役員紹介
役員紹介
地図・アクセス
地図・アクセス
採用情報
採用サイト
採用募集についてのお問い合わせ
採用募集についてのお問い合わせ

COLUMN

コラム

classのシンプルなグリッドシステム

2020年6月22日
プロダクション

今や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} );
            }
        }
    }
}

この記事を書いた人

G・I

記事一覧

トライベック・プロフェッショナルサービス株式会社

お問い合わせ

Web戦略策定からサイト構築、オペレーションまで、最適なワンストップのソリューションを提供します。
お気軽にお問い合わせください。

関連コンテンツ