背景
多数のdiv要素をカレンダー様表示(1行当たり7カラム表示)にしたい。
しかし、グリッドレイアウトの基本数字である12カラムと7カラムは相性が悪いため、bootstrap以外の方法が必要。
目的
方法
- カラム表示にflexboxを使い、レスポンシブのためにメディアクエリを追加する。
注意
-
flexboxが対応するブラウザの割合については以下のページ参照のこと。
1行3カラムレイアウトを作る
いつもの方法(bootstrap)
- bootstrapで3カラムならばdivのclassに
col-xx-4
と書く。(今回はcol-sm-4) - 本質的にCSSは不要。だたし、枠が合った方がカラム数が明確になるためCSSによりborderを指定した。
コード
bootstrap_test.html
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- 文字コード指定 -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<!-- bootstrap読み込み -->
<link rel="stylesheet" type="text/css" href="custom_bs.css">
<!-- css読み込み -->
<div class="row">
<div class="col-sm-4">
<p>
1日目のメニュー
</p>
</div>
<div class="col-sm-4">
<p>
2日目のメニュー
</p>
</div>
<div class="col-sm-4">
<p>
3日目のメニュー
</p>
</div>
<div class="col-sm-4">
<p>
4日目のメニュー
</p>
</div>
<div class="col-sm-4">
<p>
5日目のメニュー
</p>
</div>
<div class="col-sm-4">
<p>
6日目のメニュー
</p>
</div>
<div class="col-sm-4">
<p>
7日目のメニュー
</p>
</div>
<div class="col-sm-4">
<p>
8日目のメニュー
</p>
</div>
<div class="col-sm-4">
<p>
9日目のメニュー
</p>
</div>
</div>
custom_bs.css
div.row > div {
border: 1px solid black;
/* 飾り */
}
結果
cssの機能を用いた方法(flexbox)
- 解説は後で。
コード
flexbox_test.html
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- 文字コード指定 -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<!-- bootstrap読み込み。bootstrapと見た目を一緒にするために加えている。flexboxはこれが無くても動作する -->
<link rel="stylesheet" type="text/css" href="custom_fb.css">
<!-- css読み込み -->
<div class="cont">
<!-- flexboxのコンテナ -->
<div class="item">
<!-- flexboxのアイテム-->
<p>
1日目のメニュー
</p>
</div>
<div class="item">
<!-- flexboxのアイテム-->
<p>
2日目のメニュー
</p>
</div>
<div class="item">
<!-- flexboxのアイテム-->
<p>
3日目のメニュー
</p>
</div>
<div class="item">
<!-- flexboxのアイテム-->
<p>
4日目のメニュー
</p>
</div>
<div class="item">
<!-- flexboxのアイテム-->
<p>
5日目のメニュー
</p>
</div>
<div class="item">
<!-- flexboxのアイテム-->
<p>
6日目のメニュー
</p>
</div>
<div class="item">
<!-- flexboxのアイテム-->
<p>
7日目のメニュー
</p>
</div>
<div class="item">
<!-- flexboxのアイテム-->
<p>
8日目のメニュー
</p>
</div>
<div class="item">
<!-- flexboxのアイテム-->
<p>
9日目のメニュー
</p>
</div>
</div>
custom_fb.css
* {
box-sizing: border-box;
/* widthにpaddingとborderを含めて計算を簡単にするため */
}
div.cont {
display: flex;
/* flexboxレイアウトを使うための命令 */
flex-wrap: wrap;
/* 上記で囲われたflexアイテムを折り返すように設定する */
}
div.item {
width: 33.3%;
/* 100%を1行当たりのカラム数(今回は3)で割った数値 */
border: 1px solid black;
/* 飾り */
margin: 0;
/* widthの計算簡単にするため(marginも使うための拡張は後で) */
}
@media (max-width: 767px) {
/*レスポンシブ用*/
div.cont {
display: block;
}
div.item {
width: 100%;
}
}
結果
本題:1行7カラムレイアウトを作る
bootstrapでやる方法はわからなかったので、flexboxの例のみ。
flexbox
コード
- flexbox_test.htmlは上記と同じ。
- custom_fb.cssの変更は 1行だけ 。div.itemのwidthを33.3%から14.28%に書き換える。それだけ。
- 100 / 7 = 14.28
custom_fb.css
* {
box-sizing: border-box;
/* widthにpaddingとborderを含めて計算を簡単にするため */
}
div.cont {
display: flex;
/* flexboxレイアウトを使うための命令 */
flex-wrap: wrap;
/* 上記で囲われたflexアイテムを折り返すように設定する */
}
div.item {
width: 14.28%;
/* 100%を1行当たりのカラム数(今回は7)で割った数値 */
border: 1px solid black;
/* 飾り */
margin: 0;
/* widthの計算簡単にするため(marginも使うための拡張は後で) */
}
@media (max-width: 767px) {
/*レスポンシブ用*/
div.cont {
display: block;
}
div.item {
width: 100%;
}
}
結果
解説
-
flexboxの基本は配置したい要素(今回の例ではdiv.item)をdiplay: flex;が指定された要素(div.cont)で囲うこと。
xxx.html
<div class="cont">
<div class="item">
</div>
<div class="item">
</div>
</div>
yyy.css
div.cont {
display: flex;
}
- このままだとdiv.itemが横に並ぶだけなので折り返すためにflex-wrap: wrap;を追加する
yyy.css
div.cont {
display: flex;
flex-wrap: wrap;
}
- 任意のカラム数で折り返してもらうためdiv.itemのwidthを指定する。このときwidthは%で指定し、100%を目的とするカラム数で割った値に設定する。7カラムであれば14.28%。
yyy.css
div.cont {
display: flex;
flex-wrap: wrap;
}
div.item {
width: 14.28%
}
- レスポンシブになるように、幅が狭い場合(本例では767px以下)ではflexboxを使わない様にする
yyy.css
div.cont {
display: flex;
flex-wrap: wrap;
}
div.item {
width: 14.28%
}
@media (max-width: 767px) {
div.cont {
display: block;
}
}
応用(marginも設定したい場合)
- 単純にdiv.itemにmarginを指定すると1行当たりに表示したいカラム数が減ってしまいます。
- div.itemのwidthはmarginの合計を差し引いた値をカラム数で割った値にします。
- widthの計算の単位を揃えるため、div.itemにmarginも設定したい場合は、%単位で指定してください。
- (100% - margin (%) * (カラム数 - 1) * 2 + margin (%) * 2}) / カラム数}
- 例えば、margin: 1%;でカラム数7の場合は以下のかんじです。
yyy.css
div.item {
width: 12.28% /* = 100 - 1 * (7 - 1) * 2 + 1 * 2 */
margin: 1%
}
- scssだったら変数を使うと一般化できます
zzz.scss
$n: 7; //1行当たりのカラム数
$m: 1%; //カラム左右のマージン
// 省略
div.item {
width: calc((100% - #{$m * ($n - 1) * 2 + $m * 2}) / #{$n});
margin: $m;
}
// 省略
結果
その他
-
paddingを使う時は、widthの計算を簡単にするため、
* {box-sizing: border-box;}
を使うと楽 -
今回の例では効果がわからないけど、flexboxでレイアウトしたitemの高さはデフォルトで 揃います 。floatでこれをやるとすごい面倒。
http://shanabrian.com/web/html-css-js-technics/css-equal-height.php
-
コードは省略するけど、こんな感じに高さが揃った表示もflexboxだとすごい簡単だった。
最後に
- bootstrapだとhtmlに見た目も書くことになって気持ち悪かったのが、flexboxだと楽々すっきり。