こんにちは。CSSテクニックをまとめた本を書くために知見を集めている @takamosoo です。今回とあるWebサイトで少し複雑なレイアウトを作成することがありました。そのレイアウトが簡単に実装できそうに見えて少し手こずってしまったので、Twitterにて問題として出してみました。
【CSS超上級者?問題】
— たかもそ@本執筆 (@takamosoo) 2018年5月9日
・ヘッダー/フッター可変
・フッターはコンテンツが少ないときは最下部に固定
・サイドバーは250px
・メインは可変
・サイドバーとメインで背景色を変える
・IE11、その他モダンブラウザで動作
できた方はjsfiddleなりcodepenなりgithubなりで教えてください!#拡散希望 pic.twitter.com/4iUH6Gsu8Z
残念ながら解答してくれる人はいませんでしたが、この記事を見ている人はまず続きを読む前に一度自分で実装してみてください。意外と難しいと思います。少し前の流行りとして、左右半分ずつに分けるレイアウトはありましたが、このように微妙な位置で背景色が分かれているようなレイアウトはあまり見たことがありません。もし、聖杯レイアウト(Holy Grail Layout)みたいにこのレイアウトの名称が分かる人もしくは適当な名前を思いついた人がいれば教えて欲しいです。
実装の手段はいくつかあるとは思いますが、ここではほぼ全てのブラウザで使えるFlexboxを使っていきます。
コンテンツが少ないときは最下部にフッターを固定
<html>
<body>
<header>ヘッダー</header>
<div>コンテンツ</div>
<footer>フッター</footer>
</body>
</html>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
height: 100%;
}
body {
display: flex;
flex-direction: column;
height: 100vh;
}
div {
flex: 1 0 auto;
}
footer {
flex-shrink: 0;
}
コンテンツが少ないとき、フッターがページの途中に表示されると不恰好なので、Sticky Footerというテクニックを使ってフッターを最下部に固定しています。Sticky Footerについては解説しないので、気になる人は調べてみてください。Flexboxを使っているので、この時点でヘッダーとフッターは自動的に可変対応となります。
header {
background: red;
}
footer {
background: blue;
}
また、分かりやすいように適当に背景色をつけておきます。
サイドバーとメイン
サイドバーとメイン部分に着手していきます。ここで、重要となるのが高さの問題です。サイドバーとメインの高さは領域いっぱいに広がるようにしなければなりません。そうしないと背景色が途中で途切れてしまいます。高さを継承するためにすべての要素に height: 100%;
を指定する方法がありますが、これは場合によっては一部のブラウザで高さを継承しません。一番有名な例で言えば、float
を使うとたとえ height: 100%;
を指定したとしても高さは継承されません。どのブラウザでも安全に高さを継承するためにはFlexboxを使うのが一番簡単で安全です。
<div style="display: flex;">
<div style="display: flex;">
<div style="display: flex;">
<div style="display: flex;">
...
</div>
</div>
</div>
</div>
このように display: flex;
の子要素であるFlexアイテムに、さらに display: flex;
を指定することで孫要素まで高さを継承させることができます。今回の例で言うと、body
div
section
要素に display: flex;
を指定することで高さを継承することができます。body
にはすでにSticky Footerの実装のときに指定されているので div
と section
要素に指定すればいいことになります。
<html>
<body>
<header>ヘッダー</header>
<div>
<section>
<aside>サイドバー</aside>
<main>メイン</main>
</section>
</div>
<footer>フッター</footer>
</body>
</html>
div {
display: flex;
justify-content: center;
}
section {
flex-basis: 800px;
}
まず、高さを継承するために div
要素に display: flex;
を指定し、その子要素である section
要素は最大800pxになるようにします。そして、justify-content: center;
で左右中央揃えにします。
section {
display: flex;
}
aside {
width: 250px;
}
main {
flex: 1;
}
section
要素に display: flex;
を指定して高さを継承しつつ、サイドバーとメインを横並びにします。サイドバーは固定250px、メインは可変にするために flex: 1;
を指定します。
aside {
background: green;
}
main {
background: yellow;
}
サイドバーとメインに適当に背景色をつけます。すると、高さが継承されていることが確認できると思います。ここまでこればほとんど完成で、あとは左右の白い領域にも背景色をつけるだけです。
左右の空白部分に背景色を適用
空白部分に背景色をつけるためには、左半分は緑色で右半分は黄色を指定すれば大丈夫そうです。CSSのグラデーションを使うと簡単に実装できます。
background: linear-gradient(90deg, green 0%, green 50%, yellow 50%, yellow 100%);
このようにすれば左右で色の異なる背景色が作れます。
div {
background: linear-gradient(90deg, green 0%, green 50%, yellow 50%, yellow 100%);
}
div
要素に指定すると、実現したいレイアウトが完成します。
全ソースコード
<html>
<body>
<header>ヘッダー</header>
<div>
<section>
<aside>
サイドバー
</aside>
<main>
メイン
</main>
</section>
</div>
<footer>フッター</footer>
</body>
</html>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
height: 100%;
}
body {
display: flex;
flex-direction: column;
height: 100vh;
}
header {
background: red;
}
div {
display: flex;
justify-content: center;
flex: 1 0 auto;
background: linear-gradient(90deg, green 0%, green 50%, yellow 50%, yellow 100%);
}
section {
display: flex;
flex-basis: 800px;
}
aside {
width: 250px;
background: green;
}
main {
flex: 1;
background: yellow;
}
footer {
flex-shrink: 0;
background: blue;
}
分かってしまえば非常に簡単ですよね。そして、Flexboxがいかに万能か分かってもらえたかと思います。このレイアウトの名称お待ちしております。以上、@takamosoo でした。