デザインょゎょゎでも使えるグリッドレイアウト

※この記事はわりと備忘録の側面が強いです｡

## TL;DR

+ `grid-template-area`で名前でグリッドレイアウトを実現できる
+ 配置する子要素は`grid-area`で名前をつける
+ 子孫(`!子`)要素に`grid-area`を付ける場合はグリッドコンテナまでの要素は`display: contents`にする

## グリッドレイアウト

ここでは､CSSグリッドレイアウトのことをグリッドレイアウトとしますが､Webデザインにおいて行(`row`)と列(`column`)を用いて2次元的に要素を配置することを意味します｡

```html
<div class="container">
  <div class="grid-element">grid element</div>
  <div class="grid-element">grid element</div>
  <div class="grid-element">grid element</div>
  <div class="grid-element">grid element</div>
  <div class="grid-element">grid element</div>
</div>
```

このような要素を､

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606626/1ff31cda-8beb-3a34-5fda-6426e5b4b759.png)

こういった様に配置できるレイアウトが､グリッドレイアウトです｡
CSSは以下の通り(色とか余白は適当な値にしています)

```css
.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-gap: 1em;
  padding: 10px;
}

.grid-element {
  display: block;
  background-color: skyblue;
  border: 2px solid limegreen;
  border-radius: 5px;
  padding: 1em;
}
```


もう一つ要素のレイアウトにはフレックスデザインがあったりしますが､比較すると考えることが多いかわりに､より柔軟なデザインをすることが可能です｡

しかし､このグリッドは柔軟性の高さ故､指定できる属性も多く､正直UIなんてフォームアレばいいでしょみたいな人間にとっては苦痛以外の何物でもありません｡
そんな苦痛な作業を軽減しながらでもグリッドレイアウトを使いたい､というのを叶えてくれるのが､`grid-template-area`であります｡

## グリッドレイアウトを使いたい場面

個人的に使いたくなる場面は､サイドバーやナビゲーションバーのある画面を作成するときに､
```
|---      header      ---|
|-------|----------------|
|       |                |
|sidebar|    contents    |
|       |                |
|-------|----------------|
|---      footer      ---|
```

こういった画面や､

```
|---        header        ---|
|-------|----------------|---|
|       |                |   |
|sidebar|    contents    |toc|
|       |                |   |
|-------|----------------|---|
|---        footer        ---|
```

こうした画面のデザインについて､特に下側はナビゲーション属性のある`sidebar`,`toc`(Table of Contents)は中身のデザインを統一したい場合もあるため､一元で管理したいと思うと､HTMLは

```html
<html>
  <body>
    <header class="header">ヘッダー</header>
    <div class="main-wrapper">
      <div class="side-container">
        <aside class="sidebar">サイドバー</aside>
        <aside class="toc">目次(toc)</aside>
      </div>
      <div class="main-contents">
        <article>
          <h2>メイン</h2>
        </article>
      </div>
    </div>
    <footer class="footer">フッター</footer>
  </body>
</html>

```

のようにしておくと､HTML自体はその要素の役割で固まっており､非常に管理がしやすくなります｡
ではこの状態でどうやってあの画面構成を**楽に**実現するのか､に効くのが`grid-template-area`となります｡

## 名前を配置に使う

`grid-template-area`は､それぞれの配置したい要素に名前をつけ､その名前を配置することによって直感的なコーディングと理想に近いグリッドレイアウトを提供できます｡
(要素ごとの空白だったりその他のデザインには干渉できません｡あくまで｢位置関係｣のみを定義していることに注意｡)

先の画面構成に従ってデザインすると以下のようになります｡

### 画面構成

```
|---        header        ---|
|-------|----------------|---|
|       |                |   |
|sidebar|    contents    |toc|
|       |                |   |
|-------|----------------|---|
|---        footer        ---|
```


### CSS

```css
body {
  text-align: center;
}

.main-wrapper {
  display: grid; /* グリッドレイアウト */
  gap: 3em;
  grid-template-areas: "sidebar main toc"; /*  子要素の`grid-area`で定められた名前に従って配置 */
  grid-template-columns: 1fr 2.5fr 5em; /* 要素の幅 */
}

.side-container {
  display: contents; /* 後述 */
}

.sidebar {
  grid-area: sidebar; /* サイドバー */
  border-right: 2px solid;
}

.toc {
  grid-area: toc; /* 目次(toc) */
  border-left: 2px dashed;
}

.main-contents {
  grid-area: main; /* メイン */
}

.header {
  padding: 0.5em;
  border-bottom: 2px dotted;
}

.footer {
  background: gray;
  padding: 0.5em;
}

```

### 描画結果:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606626/a4af3550-9d95-5b8a-e910-06183202bd5c.png)

※要素の境界がわかるように装飾を加えています｡

### 補足

`display: grid`は､通常1つ中の要素､子要素をレイアウトの影響範囲とします｡しかし先程のコードでは更にもう1つ内部の孫要素である`.sidebar`､`.toc`の要素の`grid-area`がきちんと反映され､想定した画面構成どおりの描画結果になっています｡

この結果になる理由が`display: contents`です｡詳細は省きますが､その要素の持つデザインをすべて無視して内部の要素を描画する指定で､これによりあたかも2つの並べたい要素を`.main-wrapper`の子要素のように扱うことができているわけです｡

## グリッドレイアウトで遊ぶ

先程の章では実用性のある画面構成のデザインについて話しましたが､これだとあまり`grid-template-areas`の強みを十分に扱えているかというと少し疑問が残ります｡
もちろん､役割ごとにHTML内の配置を分けながらユーザーにとっては見やすいデザインを提供できるという点で十分な仕事をしています｡が､この章ではグリッドレイアウトを**楽に**､**楽しく**､使うことを考えてみましょう｡

### 2次元レイアウトを考える

長方形限定ではありますが､`grid-template-areas`は複数行書くことで柔軟なレイアウトを実現できます｡

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606626/375eb643-f225-3919-9904-d65367703b39.png)


```html
<html>
  <body>
    <div class="main-wrapper">
      <div>One(a)</div>
      <div>Two(b)</div>
      <div>Three(c)</div>
    </div>
  </body>
</html>
```

```css
body {
  text-align: center;
}

.main-wrapper {
  display: grid;
  gap: 1em;
  grid-template-areas:
      "a a b"
      "a a b"
      ". c .";
  grid-template-columns: 1fr 1fr 1fr;
}

.main-wrapper :first-child {
  padding: 3em;
  background-color: rgba(0, 0, 255, .2);
  border: 3px solid #00f;
  grid-area: a;
}

.main-wrapper :nth-child(2) {
  padding: 3em;
  background-color: rgba(0, 255, 0, .2);
  border: 3px solid #00f;
  grid-area: b;
}

.main-wrapper :nth-child(3) {
  padding: 3em;
  background-color: rgba(255, 0, 0, .2);
  border: 3px solid #00f;
  grid-area: c;
}

```

これ､頑張れば建物のレイアウトとかを配置できるのではと思ったりしているので､夢が広がりそうですよね｡

こうしてグリッドレイアウトをデザインで頭が爆発しそうなょゎょゎな私でも高度なコードを書くことなく柔軟性のある画面デザインをすることができました｡

## 参考記事

HTML+CSS+JacaScriptは80% ***†MDN†*** が解決してくれます｡

+ [グリッド- ウェブ開発を学ぶ| MDN]()
+ [grid-template-areas| MDN](https://developer.mozilla.org/ja/docs/Web/CSS/grid-template-areas)


**************************************************

## 補足 グリッドレイアウトにおける単位について

https://developer.mozilla.org/ja/docs/Web/CSS/CSS_grid_layout/Basic_concepts_of_grid_layout#the_fr_unit

詳しくは上の記事を参照してほしいのですが､単位`fr`について｡

`fr`は､グリッドコンテナ(グリッドを用いて配置するときの親要素､本に対する本棚とかのイメージ)の領域のうち､利用可能な幅や高さに応じて相対的に長さを割り振ります｡例えば､幅にたいして`grid-template-columns: 1fr 1fr 1fr`というようにすると､グリッドでの配置時には､利用可能なスペースを3等分した幅を要素に割り当て配置します｡

`fr`は他の単位とも併用でき､本記事の`grid-template-columns: 1fr 2.5fr 5em;`のような使い方も可能です｡この場合は､まず固定単位の`5em`を確保した後､残りの利用可能な幅を`3.5f`とし､例えばそれが`350px`であれば`100px 250px`の用に割り当てられることになります｡

この単位はグリッドレイアウトをデザインする上で結構見かけることになると思うので､覚えておいて損はしないでしょう｡