Media QueriesとFlexboxでレスポンシブサイトを作るときのメモ

9 min読了の目安(約8300字TECH技術記事

Media Queries

閲覧環境の条件に応じて適用するスタイルを切り替える機能
linkタグにも使えるし

<link rel="stylesheet" href="phone.css" type="text/css" media="screen and (max-width: 480px)">
<link rel="stylesheet" href="pc.css" type="text/css" media="screen and (min-width: 900px)">

CSSのソース内でも使える

@media screen and (max-width: 480px) {
   div#sidebar { width: 100%; }
}
@media screen and (min-width: 900px) {
   div#sidebar { width: 240px }
}

上のように単位はピクセルでもいいし

@media screen and (min-width: 25rem) {
   div#sidebar { width: 10rem; }
}

ルート要素のフォントサイズを基準とした場合の横が25文字以下の場合、などの指定も可能
こうすれば25文字まで入るようなら2カラムで表示、入らないようなら1カラムの2段組という表示も指定できる

scssを使えば

//
// vwもCSS3で追加された単位です
// 1vw=ビューポート幅の1%
// 同様に高さを示すvhという単位もあります
//
#sidebar{
    width: 100%;
    font-size: 4vw;
    @media screen and (min-width: 900px){
        width: 20vw;
        font-size: 2vw;
    }
}   

という書き方ができる
個人的には

  • モバイルファーストで書いてPC用にフォントサイズやレイアウトを調整する
  • ピクセル単位の決めうちではなくvwやvh、remなどのデバイスのビューポートによる相対サイズで指定する

という方法を使っています

CSS上の長さの単位

これまで

  • ピクセル指定
  • ポイント指定
  • em指定

などがありましたが、ここまでデバイス毎の解像度やピクセル密度がバラバラになるとそろそろきつい

新しい単位 vw / vh / vmin / vmax

ビューポートの幅や高さをベースにした単位

  • vw = ビューポートの横幅いっぱい = 100vw
  • vw = ビューポートの高さいっぱい = 100vh
  • vmin = ビューポートの縦横のうち小さいほうの幅いっぱい = 100vmin
  • vmax = ビューポートの縦横のうち大きいほうの幅いっぱい = 100vmax

小数点も使える

利点

  • ブラウザのビューポートをベースにしているのでデバイスの解像度などの影響を受けない
  • どんなに深いところの子や孫要素に書いても基準になるのはビューポートに対するパーセンテージなので、これまでの%指定のように親要素のサイズを常に意識する必要がない

欠点

  • IE9だとvmaxが使えない(祝!IE9サポート終了)
  • Android4.4未満の標準ブラウザをサポートしていない(ChromeならOK)
  • viewportはスクロールバーのエリアも含むので横にスクロールバーが出てるコンテンツでうっかり100vwを指定すると横スクロールバーがこんにちは(2016/08/23 追記)

#Flexboxを使おう

ベースHTML(見た目でわかるようにかなり酷い色にしてます)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Flexbox</title>
<style>
body{
    margin: 0;
}
#parent{
    width: 100vw;
    height: 100vh;
    background-color: black;
}
#child-1{
    background-color: red;
    color: white;
}
#child-2{
    background-color: green;
    color: white;
}
#child-3{
    background-color: blue;
    color: white;
}
</style>
</head>
<body>
    <div id="parent" class="parent">
        <div id="child-1" class="child">
            (1) Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis purus vel quam pulvinar molestie. Nulla est justo, auctor eget laoreet sit amet, euismod sed lorem. Cras magna lorem, hendrerit ut laoreet ut, tincidunt sit amet tortor. Aenean libero felis, faucibus nec maximus non, convallis at arcu. Maecenas eleifend felis quis lectus imperdiet, eu sollicitudin dui aliquam. Ut sed nisi commodo, consequat risus at, sagittis erat. Curabitur cursus accumsan enim, eget rutrum tellus hendrerit quis. Duis ut libero quis diam posuere ornare. Donec tortor ligula, mollis quis tempus et, bibendum sed ex. Phasellus auctor interdum massa, nec viverra libero tristique ut. Proin suscipit, mi finibus commodo elementum, mi mi sollicitudin diam, sit amet blandit ipsum purus sit amet dolor. Proin et lorem tempus, aliquet libero a, aliquet urna. Praesent eget aliquet arcu. Maecenas est libero, placerat at purus vestibulum, interdum ullamcorper tortor. Sed mattis dui a ante bibendum interdum. Sed massa orci, fermentum eu magna id, posuere finibus elit.
        </div>
        <div id="child-2" class="child">
            (2) Pellentesque sollicitudin nisi luctus, efficitur odio nec, ullamcorper diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nullam in orci sed sapien dapibus mollis eu vitae metus. Vestibulum sollicitudin efficitur nisi, at blandit nibh luctus sit amet. Donec et magna nec augue congue condimentum eu non velit. Nunc eu fringilla urna. Proin nec feugiat purus, ut facilisis sapien.
        </div>
        <div id="child-3" class="child">
            (3) In at pretium turpis. Aenean porta vulputate orci eget ultricies. Nullam maximus lacinia arcu a feugiat. Nulla fermentum eros sed metus mollis rhoncus. Suspendisse et velit odio. Vestibulum consectetur mattis arcu, at mattis nibh vestibulum sit amet. Pellentesque viverra, lorem vitae malesuada accumsan, metus lectus fringilla libero, sed convallis metus mi ut lectus.
        </div>
    </div>
</body>
</html>

parent の表示エリア内で child 同士をどうレイアウトするかを指定する

横3カラムに並べる場合

.parent{
	display: flex;
	flex-direction: row;
}

※デフォルトはこっちなので明示的なflex-directionは要らないかも

縦に1個ずつ並べる場合

.parent{
	display: flex;
	flex-direction: column;
}

尺あまりや尺足らずの処理

child ボックスの内容によっては尺が余ったり足りない場合が出てきますが

デフォルトは左(始めの要素)寄せ

.parent{
	display: flex;
	justify-content: flex-start;
}

右(終わりの要素)寄せ

.parent{
	display: flex;
	justify-content: flex-end;
}

真ん中寄せ

.parent{
	display: flex;
	justify-content: center;
}

均等割(1) 始点と終点をピッタリ合わせる

.parent{
	display: flex;
	justify-content: space-between;
}

均等割(2) 始点と終点にも適度なスペース

.parent{
	display: flex;
	justify-content: space-around;
}

横の尺がたりないとき

無理やりにでもおさめる(デフォルト)

.parent{
	display: flex;
	justify-content: flex-start;
	flex-wrap: no-wrap;
}

レスポンシブサイトでこれはあんまりない

無理をせず折り返す

.parent{
	display: flex;
	justify-content: flex-start;
	flex-wrap: wrap;
}

折り返された行がどう並ぶかはjustify-content次第

ショートハンド

flex-directionとflex-wrapをまとめて書くショートハンドがあります

.parent{
	flex-flow: row wrap;
}

デフォルトはrow, no-wrap

ボックス要素の表示順

<article class="parent">
	<section id="child-1" class="child"></section>
	<section id="child-2" class="child"></section>
	<section id="child-3" class="child"></section>
</article>

HTML的には child-1, child-2, child-3の順に流れるのですが

並びを逆転させることができます

.parent{
	display: flex;
	flex-direction: row-reverse; /* 横に3,2,1の順に表示 */
}
.parent{
	display: flex;
	flex-direction: column-reverse; /* 縦に3,2,1の順に表示 */
}
.parent{
	display: flex;
	justify-content: flex-start;
	/* 横の尺が足りない場合は3,2 <折り返し> 1などの順に表示 */
	flex-wrap: wrap-reverse;
}

さらに子要素に order プロパティを加えれば順番を複雑にいじることが可能

#child-1{
	order: 2;
}

#child-2{
	order: 3;
}

#child-3{
	order: 1;
}

orderは小さいものから順番に並ぶ(負の数も設定可)

この場合は child-3 => child-1 => child-2 の順番に並ぶ

これで何ができるかというと

  • メディアクエリとの合わせ技で画面幅ごとに組み換えができる
  • 「見た目」にのみ影響してHTML文書構造には影響しないので読み上げブラウザ向けにも対応しやすい
  • 文書構造と見た目の分割

高さの調整(1)

flex-direction: row の場合、親ボックスの高さに対して子ボックスを縦にどう配置するか

デフォルトは高さの余りを各ボックスに均等分配

.parent{
	display: flex;
	align-content: stretch;
}

上にどんどん詰める

.parent{
	display: flex;
	align-content: flex-start;
}

下からどんどん詰める

.parent{
	display: flex;
	align-content: flex-end;
}

中央に合わせて詰める

.parent{
	display: flex;
	align-content: center;
}

上下をピッタリ合わせつつ残りのスペースを均等に

.parent{
	display: flex;
	align-content: space-between;
}

上下も含めて残りのスペースを均等に

.parent{
	display: flex;
	align-content: space-around;
}

高さの調整(2)

flex-direction: row の場合、高さがバラバラな子要素をどう処理するか

デフォルトは高さの足りないボックスを引き延ばして一番高いボックスに揃える

.parent{
	display: flex;
	align-items: stretch;
}

引き延ばさずに上に合わせる場合(下はデコボコ)

.parent{
	display: flex;
	align-items: flex-start;
}

引き延ばさずに下に合わせる場合(上はデコボコ)

.parent{
	display: flex;
	align-items: flex-end;
}

引き延ばさずに中央に合わせる場合(上下はデコボコ)

.parent{
	display: flex;
	align-items: center;
}

引き延ばさずにベースラインに合わせる場合(上下はデコボコ)

.parent{
	display: flex;
	align-items: baseline;
}

子要素に設定するプロパティ

子要素同士の大きさ調整

拡大

#child-1{
	flex-grow: 1; /* デフォルト値は auto */
}
#child-2{
	flex-grow: 2;
}
#child-3{
	flex-grow: 3;
}

もし余白が生じるようなら、#child-1,#child-2,#child-3はそれぞれ1:2:3の比率で拡大される

縮小

#child-1{
	flex-shrink: 0; /* デフォルト値は 0 */
}
#child-2{
	flex-shrink: 2;
}
#child-3{
	flex-shrink: 3;
}

もし不足が生じるようなら、#child-2と#child-3は不足分を2:3の割合で補完するように
詰められるが#child-1はオリジナルサイズを維持する

固定幅の子要素とそれ以外

#child-1{
	flex-basis: 250px; /* デフォルト値は auto */
}

child-1は250px固定、残りは拡縮

ショートハンド

.child{
	flex: 0 1 auto;
}

順番はshrink, grow, basis

その他

align-itemsの個別上書き

親要素で指定されたalign-itemsの指定を子要素単位で上書きできる

.parent{
	display: flex;
	align-items: flex-start;
}
#child-2{
	align-self: stretch;
}
#child-3{
	align-self: flex-end;
}

基本的に先頭に合わせるが#child-2はボックスを拡大、#child-3は下に合わせる

1/3なんかの%指定では厳密に割り切れない分割の記述

33.333333%などの無理やり感満載の指定をするより、calc()を使えばよしなにはからってくれる

.child{
    width: calc(100% / 3);
}