カレンダー
flexbox

flexboxで1行7カラムのカレンダー表示


背景

多数のdiv要素をカレンダー様表示(1行当たり7カラム表示)にしたい。

しかし、グリッドレイアウトの基本数字である12カラムと7カラムは相性が悪いため、bootstrap以外の方法が必要。


目的


  • cssにある基本機能を使い、div要素をカレンダーのように横7カラム表示する

    スクリーンショット 2016-06-29 10.40.25.png


  • レスポンシブも対応する



方法


  • カラム表示に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;
/* 飾り */
}


結果


  • デスクトップ表示

    スクリーンショット 2016-06-29 10.33.47.png


  • スマホ表示(イメージ)

    スクリーンショット 2016-06-29 11.56.50.png



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%;
}
}


結果


  • デスクトップ表示

    スクリーンショット 2016-06-29 10.34.58.png


  • スマホ表示(イメージ)

    スクリーンショット 2016-06-29 11.57.38.png



本題: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%;
}
}


結果


  • デスクトップ表示

    スクリーンショット 2016-06-29 10.40.25.png


  • スマホ表示(イメージ)

    省略



解説


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;
}
// 省略


結果

スクリーンショット 2016-06-29 11.14.22.png


その他



  • paddingを使う時は、widthの計算を簡単にするため、* {box-sizing: border-box;}を使うと楽

    http://phiary.me/css3-box-sizing/




  • 今回の例では効果がわからないけど、flexboxでレイアウトしたitemの高さはデフォルトで 揃います 。floatでこれをやるとすごい面倒。

    http://shanabrian.com/web/html-css-js-technics/css-equal-height.php




  • コードは省略するけど、こんな感じに高さが揃った表示もflexboxだとすごい簡単だった。

    スクリーンショット 2016-06-29 11.27.11.png




最後に


  • bootstrapだとhtmlに見た目も書くことになって気持ち悪かったのが、flexboxだと楽々すっきり。