Flexboxレイアウトを知る
レスポンシブデザインのWebサイトをコーディングする際、よくあるのが「スマホの時は縦並び、タブレットもしくはPC幅で横並び」というレイアウト変更です。下図のようにPCだとサイドバーでカテゴリーや新着記事が表示されていて、タブレットやスマホで見るとメインコンテンツの下に配置されているようなWebサイトを見たことがある方も多いのではないでしょうか。

こうしたサイトをコーディングする際、よく使うのがCSSのFlexboxというレイアウトモジュール。 簡単に言ってしまえば、FlexboxはWebページ内の要素を並べるためのキットのようなものです。
次回から進めていく動物園サイトのコーディングでも、このFlexboxを中心にレスポンシブコーディングを進めていきます。 今回の実習で簡単に基礎を押さえておきましょう。
◆実習①Flexboxの仕組みを知ろう
CSSのFlexboxレイアウトを使うのは、とっても簡単。
基本はFlexboxで配置を作りたい要素を囲い、囲った要素(親要素)にdisplay: flex; と指定するだけです。 display: flex; を指定している要素をflexコンテナ、その中に入っている要素をFlexアイテムと呼びます。

実際にtest1.htmlで<div class="viewport-test"></div>の下に、Flexboxを作って試してみましょう。
test1.html
<body>
  <div class="viewport-test">
    test
  </div>
  <div class="flexbox">
    <div>
      item1
    </div>
    <div>
      item2
    </div>
  </div>
</body>
一旦、CSSを書く前にブラウザで見てみましょう。 item1と1tem2の文字は、縦並びになっていますね。

では、CSSで「flexbox」クラスに対してdisplay: flex; を指定してみましょう。
メディアクエリの外側、@media (min-width: 600px) { }よりも上に書いてみてください。
test1.css
.viewport-test{
  width: 100%;
  background: #FFFFD6; /* 黄色 */
}
.flexbox{
  display: flex;
} 
/* -------------------------------------------- */
/*  ▼ タブレット以上の場合に適用するCSS ▼
/* -------------------------------------------- */
@media (min-width: 600px) {
  ...以下略

アイテムの並べ方を決めるflex-direction
display: flex;を指定したflexコンテナ内の子要素(flexアイテム)は、デフォルトで横並びになります。 flex-directionというCSSプロパティを使うと、並び順の変更が可能。flex-directionプロパティも、同じくflexコンテナに対して指定します。
| 値 | 結果(どうなるか) | 
|---|---|
| row(初期値) | 左から右に横並べ | 
| row-reverse | 右から左に横並べ | 
| column | 上から下へ縦並べ | 
| column-reverse | 下から上に縦並べ | 
先程書いた<div class="flexbox">とは、別のクラスで作ってみます。
test1.html
<div class="flexbox2">
    <div>
        アイテム1
    </div>
    <div>
        アイテム2
    </div>
</div>
test1.css
.flexbox2{
  display: flex;
  flex-direction: column;
}
flex-direction: column;が指定されている、flexbox2クラス内の「アイテム1」「アイテム2」は縦方向に配置されます。

flexアイテムの配置・並べ方のバリエーション
表示領域の大きさによって、Flexアイテムの配置を変えたい場面も出てきます。 よくあるパターンを見ていきましょう。
1. メディアクエリと組み合わせる
よくあるのが、スマホ幅ではitem1とitem2を縦並び、タブレット幅以上で横並びにしたい…というパターン。

flex-directionプロパティと組み合わせても出来ますが、この場合は.flexbox { display: flex; }を@media (min-width: 600px) { }の中に書くだけでも対応できます。タブレット以上の幅になってはじめてFlexboxレイアウトを使う、という形です。
以下のように書くと、スマホ幅ではitem1とitem2を縦並び、タブレット幅以上で横並びになります。
test1.css(必要箇所のみ抜粋)
.viewport-test{
  width: 100%;
  background: #FFFFD6; /* 黄色 */
}
@media (min-width: 600px) {
  .flexbox{
    display: flex;
  } 
}
2. flexアイテムの幅を指定し、折り返す
次に、スマホやタブレットの場合はFlexアイテムを2つ横並び、PC幅になったら4つ横並びにしたい場合の方法を見てみましょう。

まず、htmlに書き足して、flexアイテムのdivを4つにします。
test1.html(flexレイアウト部分のみ抜粋)
<div class="flexbox">
  <div>
    item1
  </div>
  <div>
    item2
  </div>
  <div>
    item3
  </div>
  <div>
    item4
  </div>
</div>
CSSで「flexboxクラスの中にある(子要素の)div」をセレクタに幅を指定してみましょう。 CSSセレクタは半角スペースで区切って書くと、左側の要素の“中にある(子要素の)”という意味になります。
メディアクエリで囲っていない部分はwidth:50%、PC幅では4つ並ぶようwidth:25%を指定します。
test1.css (必要箇所のみ抜粋)
.flexbox{
  display: flex;
}
.flexbox div{
  width: 50%;
}
@media (min-width: 1024px) {
  .flexbox div{
    width: 50%;
  }
}
ブラウザで見てみると、下図のようになります。

PC幅は4つ横並びが出来ていますが、スマホ幅の表示がおかしいです。 flexアイテムに対してwidth: 50%; は指定されているのに、効いていませんね。

これは、flexコンテナ内で、アイテムを1列に並べようという力が働いているため。 デフォルト状態だと、flexアイテムは親要素に合わせて伸縮する性質があるので、50%より小さくなっているわけです。
ですので、flex-wrap: wrap;というCSSを書いて「一列に並べず、折り返しても良いです」と指示します。
flex-wrapプロパティを指定するのはFlexコンテナの方なので、以下のように書きます。
test1.css (必要箇所のみ抜粋)
.flexbox{
  display: flex;
  flex-wrap: wrap;
}
.flexbox div{
  width: 50%;
}
これでスマホ幅では2つ横並びになりました。

【flex-wrapプロパティの値】
| 値 | 結果(どうなるか) | 
|---|---|
| nowrap (初期値) | 折り返さない フレックスコンテナに合うよう子要素のサイズを変える/はみ出しても一列に並べる  | 
            
| wrap | 複数行(列)に改行して表示 書字方向と同じ向きで折り返す  | 
            
| wrap-reverse | 複数行(列)に改行して表示 書字方向と逆向きに折り返す  | 
            
◆実習②大きさの異なるflexアイテムを配置する
下図のようにスマホ、タブレット、PCで表示されるFlexboxレイアウトを一緒に作ってみましょう。

『2. flexアイテムの幅を指定し、折り返す』のコードがベースとして使えます。 まずは各アイテム同じ大きさで、スマホやタブレットの場合は2つずつ横並び、PC幅になったら4つ横並びになるようにコードを書きます。
test1.html(flexレイアウト部分のみ抜粋)
<div class="flexbox">
  <div>
    item1
  </div>
  <div>
    item2
  </div>
  <div>
    item3
  </div>
  <div>
    item4
  </div>
</div>
test1.css (必要箇所のみ抜粋)
.flexbox{
  display: flex;
  flex-wrap: wrap;
}
.flexbox div{
  width: 50%;
}
@media (min-width: 600px) {
}
@media (min-width: 1024px) {
  .flexbox div{
    width: 50%;
  }
}
次に今回の実習のポイントとなる、赤字でかかれたitem3,item4の幅指定です。
- タブレット幅以上の時、item3が入っているdivを幅120pxにする
 - タブレット幅以上の時、item4が入っているdivをの幅を、残りの幅全てにする
 
それぞれ、個別に指定出来るようにdivタグにクラスをつけましょう。
test1.html(flexレイアウト部分のみ抜粋)
<div class="flexbox">
  <div>
    item1
  </div>
  <div>
    item2
  </div>
  <div class="item3">
    item3
  </div>
  <div class="item4">
    item4
  </div>
</div>
item3クラスの方は、シンプルに @media (min-width: 600px) { } のなかでwidthを指定すればOKです。
test1.css (必要箇所のみ抜粋)
@media (min-width: 600px) {
  .flexbox .item3{
    width: 120px;
  }
}
タブレット幅以上の表示を確認すると、item3クラスのdivは指定通り、幅が狭くなっていることがわかります。 問題は上のtestの背景色と同じところまで伸ばしたい、item4のdiv。

検証ツールで<div class="item4"> の横幅を見ると、今は途中までで終わっていますね。
こうした場合には、Flexboxレイアウト用のCSSプロパティ「flex」が役立ちます。 以下のように、.item4に対して「flex: 1; 」と指定してみてください。
test1.css (必要箇所のみ抜粋)
@media (min-width: 600px) {
  .flexbox .item3{
    width: 120px;
  }
  .flexbox .item4{
    flex: 1;
  } 
}
「flex: 1; 」の一行を指定しただけで、item4の幅が端まで伸びました。 ブラウザ幅を大きくしたり小さくたり変更しても、柔軟に横幅を確保してくれます。

これで完成です。
flexプロパティとは何か?
CSSのflexプロパティは、flexアイテムに関する下記3つのプロパティを一括指定できるプロパティです。
- flex-grow (伸長率):Flexコンテナの領域に収めるために伸長するか
 - flex-shrink(縮小率):Flexコンテナの領域に収めるために縮小するか
 - flex-basis (初期幅):そのFlexアイテムの幅の初期設定
 
https://developer.mozilla.org/ja/docs/Web/CSS/flex
それぞれプロパティの値を3つ書くことも、省略して書くこともできます。 Flexアイテムを横並びする際、片方にwidthもしくはflex-basisでを使って指定し、もう片方に「flex: 1:」と書いた場合は、親要素(Flexコンテナ)に合うように自動で幅を調整してくれます。今回の実習で使ったのが、この方法です。 様々な表示領域での閲覧を考慮する必要があるレスポンシブコーディングでは、とても便利ですね。
別のflexプロパティの使い方として、親要素に占める割合(比率)を指定することもできます。 例えば、以下のコードでは2つのflexアイテムを3:7の割合で配置できます。
test1.html(flexレイアウト部分のみ抜粋)
<div class="flexbox">
  <div class="itemA">
    itemA
  </div>
  <div class="itemB">
    itemB
  </div>
</div>
test1.css (必要箇所のみ抜粋)
/* flexプロパティ、比率で指定 */
.flexbox .itemA{
  flex: 3;
}
.flexbox .itemB{
  flex: 7;
}

ここまでのFlexboxレイアウト基礎知識があれば、組み合わせ方次第でかなり多様なレイアウトをレスポンシブに実装できますよ。
まとめ
横並び、縦並びを切り替えるレスポンシブデザインは、CSSのFlexboxレイアウトを使うとコーディングが楽に柔軟に行えます。
Flexboxレイアウトを作るには、親要素(Flexコンテナ)と子要素(Flexアイテム)が必要。 親要素(Flexコンテナ)にdisplay: flex;を指定することで、flexレイアウトに切り替えられます。 デフォルトでは、子要素(Flexアイテム)が横並びになり配置されます。