CSS|Flexbox
Flexboxとは柔軟なレイアウトを実現できるCSS3のレイアウトモジュールです。複雑なレイアウトを少ないコードで実装することができます。例えば、サイトナビゲーションメニューを横に並べる場合、float プロパティを使うよりも Flexbox を使う方が簡単にそれを実現できます。
仕様の変更、ブラウザの未対応など、これまで不安要素があったのですが、2018年現在では Firefox、Chrome、Safar、いずれもベンダープレフィックス無しで、大半のプロパティーを正しく認識するようになっています。
Flexboxの仕様
Flexbox の考え方を一言でまとめると、以下のようになります。
親要素(Flexコンテナ) に display: flex; を設定すると 子要素(Flexアイテム) の 並び(縦・横)や順序(上下・左右)について、 様々なプロパティを設定しつつ自由にレイアウトできる
以下、メニューを横に並べる・・という簡単な事例です。
- HTML
<ul> <li><a href="#">about</a></li> <li><a href="#">gallery</a></li> <li><a href="#">links</a></li> </ul>
- CSS
ul { display: flex; flex-direction: row; } li { width: 120px; margin-right: 20px; }
要するに親要素に対して、display: flex; と書けば、子要素は横や縦に並ぶように制御することができます。
一般的には、以下のようにコンテナとアイテムを Classで定義します。
- HTML
<div class="flex-container"> <div class="flex-item"> 〜 </div> <div class="flex-item"> 〜 </div> <div class="flex-item"> 〜 </div> <div class="flex-item"> 〜 </div> : </div>
- CSS
.flex-container { display: flex; flex-direction: row; } .flex-item { ・・略・・ }
モバイルサイズではメニューを flex-direction: column; 、PCサイズの場合は flex-direction: row; といった使い方で、レスポンシブデザインも簡単です。
Flexコンテナのプロパティー
コンテナとなるボックスに指定するプロパティ
- flex-direction:Flexアイテムの向き・方向
row(左から右へ) / row-reverse(右から左へ) /
column(上から下へ) / column-reverse(下から上へ) - flex-wrap:幅が不足した場合にFlexアイテムの折り返しを認めるか否か
nowrap(なし)/ wrap(下へ折り返し) / wrap-reverse(上へ折り返し) - flex-flow:flex-directionとflex-wrapをまとめて設定するショートハンド
- justify-content:Flexアイテム同士の余白の調整
flex-start(左) / flex-end(右) / center(中央) / space-between(均等)
space-around 均等配置(先端・終端にも余白) - align-items:Flexアイテムの垂直揃え
flex-start(横配置の場合は上、縦配置の場合は左) /
flex-end (横配置の場合は下、縦配置の場合は右) /
center(中央) / baseline(ベースライン) / stretch(等幅) - align-content:複数行のFlexアイテムの揃え方
stretch(全体幅) / flex-start(横配置の場合は上、縦配置の場合は左) / flex-end(横配置の場合は下、縦配置の場合は右) / center(中央) / space-between( 均等) / space-around(均等、先端・終端にも余白)
Flexアイテムのプロパティー
- flex-grow:コンテナに空きがある場合のアイテムの伸長率
- flex-shrink:コンテナ幅が不足する場合のアイテムの萎縮する割合を調整
- flex-basis:Flexアイテムの基準幅(最小幅)
auto (自動) / 単位を含めた数値 - align-self:個々のFlexアイテムの垂直揃え
auto (自動) / flex-start(横配置の場合は上、縦配置の場合は左) /
flex-end(横配置の場合は下、縦配置の場合は右) /
center(中央) / baseline(ベースライン) / stretch(全体を等幅) - order:Flexアイテム個々の並び順
Flexアイテムの個々の順番を設定(デフォルト値は0) - flex:flex-grow、flex-shrink、flex-basisのショートハンド
デフォルト値は 0 1 auto
Flexアイテムの幅について
以下の例では、BOXが2つ横に2:1の比率で並びます。
<div class="flex-container"> <div class="flex-a"> <p>BOX-A</p> </div> <div class="flex-b"> <p>BOX-B</p> </div> </div>
.flex-container{ display: flex; width:960px; } .flex-a { flex-grow: 2; } .flex-b { flex-grow: 1; }
flex-basisが定義されている場合、2つのブロック幅は以下のようになります。
Aの幅 = Aのbasis値 + ( 2 × ( 960px – ABのbasis合計) ÷ ( 2+1 ) ) Bの幅 = Bのbasis値 + ( 1 x ( 960px – ABのbasis合計) ÷ ( 2+1 ) )
flex-basisが0であれば話はシンプルで、以下のように単純に2:1になります。
Aの幅 = 0 + ( 2 × ( 960px – 0 ) ÷ ( 2+1 ) ) = 640px Bの幅 = 0 + ( 1 × ( 960px – 0 ) ÷ ( 2+1 ) ) = 320px
ちなみに flex というショートバンドで、{ flex: 2; } と書いた場合、flex-grow は 2 に、flex-basis は 0 となります。よって、以下のように書くだけでも、2つのアイテム幅は2:1になります。
.flex-container { display: flex; } .flex-a { flex: 2; } .flex-b { flex: 1; }
Flexアイテムがはみ出す問題について
Flexアイテムには、width: 70%; などと指定しても、大きな画像や、英文がはみ出す・・という問題があります。
width:700px; という明示的な幅指定があれば、内容がはみだすことはありあせんが、width: 70%; と書くと、サイズが明示的ではないので、内容にそれより大きな画像があるとはみ出す・・ということになるようです。
フレキシブルにしたいということは、明示的なサイズは書きたくないわけで、ではどうすれば?・・ということになるのですが、答えは以下。
Flex アイテムが水平方向に並ぶ場合の最小幅は、アイテムの内容の最小幅または Flex アイテムに width プロパティで明示的に指定された幅などのうち、最も小さい値が選択される。つまり、Flex アイテムの幅はそこまでは縮むことができる・・ということです。よって、実質的にレイアウトに影響のない、min-widthの方に以下のような明示的な指定を行って、そこまでは縮んでもいい・・ということにすれば解決します。
min-width: 100px;
逆説的でややこしいのですが、現状そうなるようです。
Flexbox サンプル1 → DEMO
header、nav ul、main の3箇所がFlexコンテナになっています。
- HTML
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="style.css"> <title>Sample Site</title> </head> <body> <div id="container"> <header> <h1>header</h1> <nav> <ul> <li><a href="#">about</a></li> <li><a href="#">gallery</a></li> <li><a href="#">links</a></li> </ul> </nav> </header> <main> <article> article </article> <aside> aside </aside> </main> <footer> © http://www.example.com </footer> </div> </body> </html>
- CSS
*{ margin: 0; padding: 0; list-style: none; text-decoration: none; } #container { width: 84%; max-width: 1280px; min-width: 512px; margin: 0 auto; } header { display: flex; padding: 40px; background: #333; } header h1{ margin-right: auto; color: white; } header nav ul{ display: flex; flex-direction: row; } header nav ul li{ margin-right: 24px; } main{ display: flex; } article{ flex: 3; height: 400px; padding: 40px; background: #EEE; } aside{ flex: 1; padding: 40px; background: #DDD; } footer { padding: 40px; text-align: center; background: #333; color: white; }
サンプル2 → DEMO
メディアクエリーを使わずに Flexbox のみでスマホに対応させる事例です。以下、フレキシブルに横と縦を切り替える <article> 部分のみを掲載します。全体像はDEMOページから辿ってご覧下さい。
- HTML
<article> <div class="imageBox"> <img src="images/sample.jpg"> </div> <div class="textBox"> <h2>Dummy Text</h2> <p>A wonderful serenity </p> </div> </article>
- CSS
article { display: flex; flex-wrap: wrap; } .imageBox{ flex: 1; text-align: center; flex-basis:200px; } .imageBox img{ width: 80%; } .textBox{ flex: 3; flex-basis:400px; } .textBox h2 { width: 80%; margin: auto; } .textBox p{ width: 80%; margin: auto; text-align: justify; }
- article がFlexコンテナで、その中の2つの div が Flexアイテムです。
- flex-wrap: wrap; とあることで、横幅が不足した場合に折返しとなります。
- 左のBoxで flex: 1; 右のBoxで flex: 3; とすることで、横並びレイアウトにおいては、1:3の比率に保たれます。
- 各Boxのサイズは flex-basis に記載された幅を保持します。この記載がないと、どこまでも細長くなって、折り返しが生じません。