読者です 読者をやめる 読者になる 読者になる

#24 CSSでブロックレベル要素を上下左右センターリングする方法

こんにちは、フロントエンドエンジニアのコウです!
この記事はTech KAYAC Advent Calendar 201524日目です。

小テスト

問題:CSSで、灰色の円 div.circle をラッパー div.wrapper の中央に配置する方法は?
CSSを下のテキストエリアに書いてください。.circle の高さと幅は 100px です。

See the Pen center the block both vertically and horizontally by GSSxGSS (@gssxgss) on CodePen.

できましたか?
おめでとうございます〜

どの方法をつかいましたか?
それでは、様々なセンターリングの方法を見てみましょう!


(プレビューコード画面右下の"+"と"-"を何回か押してみてください)

CSSレベル1の大先輩ーーvertical-aligntext-align

vertical-align プロパティは、インラインまたはテーブルセル要素の、縦方向の整列方法を定義します。 -- MDN

text-align プロパティは、テキストのようなインラインコンテンツが、その親ブロックの中でどのように文字寄せされるのかを定義します。 -- MDN

vertical-alignとtext-alignはCSSレベル1のプロパティなので、IE8のような古いブラウザでも安心してセンタリングに使うことができます。

table での解決方法

.table {
    display: table;
    width: 100%;
    height: 100%;
}
.wrapper.table-cell {
    display: table-cell;
    text-align: center;
    vertical-align: middle;
}
.target.inline-block {
    display: inline-block;
}

inline-block での解決方法

inline-block 要素を縦方向にセンタリングするためには、親要素の高さが重要です。
親要素の高さが定義されていない場合は
- 親要素に高さ100%で inline-block の擬似要素(:before or :after)を作る
- 親要素のline-heightをheightと同じ値にする
のどちらかが必要です。

方法1 height: 100%の擬似要素を作る

.wrapper.block {
    text-align: center;
    &:before {
        content: "";
        display: inline-block;
        width: 0;
        height: 100%;
        vertical-align: middle;
    }
}
.target.inline-block {
    display: inline-block;
    vertical-align: middle;
}

方法2 親要素のline-heightheightと同じ値にする

.wrapper.block {
    text-align: center;
    line-height: 465px;
}
.target.inline-block {
    display: inline-block;
    vertical-align: middle;
}

まとめ

inline-blockでの解決方法を使うときは親要素の高さが重要です。
またこの方法はIE8でも使うことができますが、複数の子要素をセンタリングしたい場合に、
子要素の幅の合計が親要素の幅を超えると、親要素をはみ出して表示が崩れてしまうので注意が必要です(画面右下の"+"を何回か押してみてください)。

inline-block要素はinline要素の特徴を持っているため、.targetの周りにはスペースができてしまいます。こちらも注意してみてください。

使いやすいなposition: absolute

もしセンタリングしたい要素が1つだけの場合、position: absoluteはとても便利です。

margin: auto での解決方法

この方法でもいけますが、ある場合にバグが起きるのでお勧めはできません。
何故この方法でセンタリングできるかについては、この記事に詳しく書いてあります

.wrapper.relative {
    position: relative;
}
.target.absolute {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
}

ネガティブ margin での解決方法

IE8でも使うことができます。
しかし、.target自身の高さと幅に依存するので、使うときは注意してください。

.wrapper.relative {
    position: relative;
}
.target.absolute {
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -50px 0 0 -50px;
}

transform での解決方法

transformはCSSレベル3のプロパティですが、IE9以降のブラウザ全てが対応しています。
おすすめです。

.wrapper.relative {
    position: relative;
}
.target.absolute {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

flexの凄さ

flex要素は、ブロック要素のようにふるまいつつ、そのコンテンツを flexbox モデルに従ってレイアウトします。 -- MDN

flexboxモデルはすごく便利です。たったの3行で子要素をセンタリングすることができます。
勿論、センタリングだけではなくflexboxモデルはとても柔軟で色々なレイアウトに適用できるので、これから是非使ってください。

flexboxは3回仕様策定(box, flexbox, flex)されていて、ベンダープレフィックスもあるため、記述が複雑になってしまいます。
なので、compassやstylusやgrunt, gulp-moduleのautoprefixerを使うとよいと思います。
興味ある方はこの記事(flexboxの旧仕様、改定仕様、現行仕様の一覧)を読んで下さい。

IEは10以降、Androidは4以降で対応していますが複数行の場合、Andoroid4.3以下(4.0~4.3)で使えません。

一行センタリング例

複数行センタリング例

.wrapper.flex {
    display: flex;
    align-items: center;
    justify-content: center;

    // 下の二行は複数行対応です。
    align-content: center;
    flex-wrap: wrap;
}

サイトフレックスカエルで、Flexboxモデルを簡単に勉強できます。
是非試してみてください。

最後に

まだ日本語が上手くできないので、基礎的な話をしました。
来年のAdvent Calendarでは上手に発表できるように、日本語頑張ります!

それでは、また来年のAdvent Calendarでお会いしましょう。
皆さん、メリークリスマス!