Posted at

できればCSS超上級者?左右で背景色が異なる複雑なレイアウト

More than 1 year has passed since last update.

こんにちは。CSSテクニックをまとめた本を書くために知見を集めている @takamosoo です。今回とあるWebサイトで少し複雑なレイアウトを作成することがありました。そのレイアウトが簡単に実装できそうに見えて少し手こずってしまったので、Twitterにて問題として出してみました。

残念ながら解答してくれる人はいませんでしたが、この記事を見ている人はまず続きを読む前に一度自分で実装してみてください。意外と難しいと思います。少し前の流行りとして、左右半分ずつに分けるレイアウトはありましたが、このように微妙な位置で背景色が分かれているようなレイアウトはあまり見たことがありません。もし、聖杯レイアウト(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の実装のときに指定されているので divsection 要素に指定すればいいことになります。

<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 でした。