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

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

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">【CSS超上級者？問題】<br>・ヘッダー/フッター可変<br>・フッターはコンテンツが少ないときは最下部に固定<br>・サイドバーは250px<br>・メインは可変<br>・サイドバーとメインで背景色を変える<br>・IE11、その他モダンブラウザで動作<br><br>できた方はjsfiddleなりcodepenなりgithubなりで教えてください！<a href="https://twitter.com/hashtag/%E6%8B%A1%E6%95%A3%E5%B8%8C%E6%9C%9B?src=hash&amp;ref_src=twsrc%5Etfw">#拡散希望</a> <a href="https://t.co/4iUH6Gsu8Z">pic.twitter.com/4iUH6Gsu8Z</a></p>&mdash; たかもそ＠本執筆 (@takamosoo) <a href="https://twitter.com/takamosoo/status/994023491048325120?ref_src=twsrc%5Etfw">2018年5月9日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

![](https://qiita-image-store.s3.amazonaws.com/0/151220/e5a5ad09-1ad6-5b6f-da33-067ae6d84625.png)

残念ながら解答してくれる人はいませんでしたが、この記事を見ている人はまず続きを読む前に一度自分で実装してみてください。**意外と難しい**と思います。少し前の流行りとして、左右半分ずつに分けるレイアウトはありましたが、このように**微妙な位置**で背景色が分かれているようなレイアウトはあまり見たことがありません。もし、聖杯レイアウト（Holy Grail Layout）みたいにこのレイアウトの名称が分かる人もしくは適当な名前を思いついた人がいれば教えて欲しいです。

実装の手段はいくつかあるとは思いますが、ここではほぼ全てのブラウザで使える**Flexbox**を使っていきます。


# コンテンツが少ないときは最下部にフッターを固定

```html
<html>
<body>

<header>ヘッダー</header>
<div>コンテンツ</div>
<footer>フッター</footer>

</body>
</html>
```
```css
* {
  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を使っているので、この時点でヘッダーとフッターは自動的に**可変**対応となります。

![](https://qiita-image-store.s3.amazonaws.com/0/151220/64c7ce24-0305-df92-83b3-6cd2eb1f6836.png)

```css
header {
  background: red;
}
footer {
  background: blue;
}
```
また、分かりやすいように適当に背景色をつけておきます。


# サイドバーとメイン

サイドバーとメイン部分に着手していきます。ここで、重要となるのが**高さ**の問題です。サイドバーとメインの高さは領域いっぱいに広がるようにしなければなりません。そうしないと背景色が途中で途切れてしまいます。高さを継承するためにすべての要素に `height: 100%;` を指定する方法がありますが、これは場合によっては一部のブラウザで高さを継承しません。一番有名な例で言えば、`float` を使うとたとえ `height: 100%;` を指定したとしても高さは継承されません。どのブラウザでも安全に高さを継承するためには**Flexbox**を使うのが一番簡単で安全です。

```html
<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` 要素に指定すればいいことになります。

![](https://qiita-image-store.s3.amazonaws.com/0/151220/79546700-84cf-e059-d490-864639820a7d.png)

```html
<html>
<body>

<header>ヘッダー</header>
<div>
  <section>
    <aside>サイドバー</aside>
    <main>メイン</main>
  </section>
</div>
<footer>フッター</footer>

</body>
</html>
```
```css
div {
  display: flex;
  justify-content: center;
}
section {
  flex-basis: 800px;
}
```
まず、高さを継承するために `div` 要素に `display: flex;` を指定し、その子要素である `section` 要素は**最大800px**になるようにします。そして、`justify-content: center;` で**左右中央揃え**にします。

```css

section {
  display: flex;
}
aside {
  width: 250px;
}
main {
  flex: 1;
}
```
`section` 要素に `display: flex;` を指定して高さを継承しつつ、サイドバーとメインを**横並び**にします。サイドバーは**固定250px**、メインは**可変**にするために `flex: 1;` を指定します。

![](https://qiita-image-store.s3.amazonaws.com/0/151220/cf7eaf7d-dbbf-52f4-f254-5db24e225e72.png)

```css
aside {
  background: green;
}
main {
  background: yellow;
}
```
サイドバーとメインに適当に背景色をつけます。すると、高さが継承されていることが確認できると思います。ここまでこればほとんど完成で、あとは左右の白い領域にも背景色をつけるだけです。


# 左右の空白部分に背景色を適用

空白部分に背景色をつけるためには、左半分は緑色で右半分は黄色を指定すれば大丈夫そうです。CSSのグラデーションを使うと簡単に実装できます。

![](https://qiita-image-store.s3.amazonaws.com/0/151220/cd6a0bd6-00c4-1242-844b-e159b4fb68f2.png)

```css
background: linear-gradient(90deg, green 0%, green 50%, yellow 50%, yellow 100%);
```
このようにすれば左右で色の異なる背景色が作れます。

![](https://qiita-image-store.s3.amazonaws.com/0/151220/99f6ab4e-5405-5757-54e7-9c4f0c1b65a7.png)

```css
div {
  background: linear-gradient(90deg, green 0%, green 50%, yellow 50%, yellow 100%);
}
```
`div` 要素に指定すると、実現したいレイアウトが完成します。


# 全ソースコード

```html
<html>
<body>

<header>ヘッダー</header>
<div>
  <section>
    <aside>
      サイドバー
    </aside>
    <main>
      メイン
    </main>
  </section>
</div>
<footer>フッター</footer>

</body>
</html>
```
```css
* {
  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](https://twitter.com/takamosoo) でした。