11
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

display: grid; を使ってみる

Last updated at Posted at 2017-02-25

display: grid;

floatという地雷原でばっちゃが死んじまっただ。
position: absolute; に margin: auto; という魔界探検で若い衆が何人も行方不明になったっぺ。
そんなおらが村にもついに display: flex; が来たっぺさ。
んじゃが都会っ子(Chrome57)のナウい最新流行は
display: grid; だっぺさ。

とりあえず使ってみる

index.htm
<div class="grid-root">
    <div class="grid11 dark01">
        <div class="contents1 bright01">
            ここはコンテンツ1です。<br />
            1行目かつ1列目なので<br />
            縦横400px<br />
            コンテンツ自体は<br />
            50%なので200px
        </div>
    </div>
    <div class="grid22 dark05">
        <div class="contents5 bright05">
            ここはコンテンツ5です。
        </div>
    </div>
    <div class="grid33 dark09">
        <div class="contents9 bright09">
            ここはコンテンツ9です。
        </div>
    </div>
</div>
index.css
/* グリッドの親要素の設定 */
.grid-root {
    display: grid;
    grid-template-columns: 400px 2fr 1fr;
    grid-template-rows: 400px 3fr 1fr;
    width: 100%;
    height: 800px;
}
/* グリッドの子要素の設定 */
.grid11 {
    grid-column: 1;
    grid-row: 1;
    display: flex;
    justify-content: flex-start;
    align-items: flex-start;
}
.grid22 {
    grid-column: 2;
    grid-row: 2;
    justify-self: center;
    align-self: center;
}
.grid33 {
    grid-column: 3;
    grid-row: 3;
    display: flex;
    justify-content: flex-end;
    align-items: flex-end;
}
/* コンテンツ自体にスタイルを設定 */
.contents1 {
    width: 50%;
    height: 50%;
    margin-top: 20px;
    margin-left: 20px;
}
.contents5 {
    padding: 20px;
    font-size: 2.0rem;
}
.contents9 {
    padding-bottom: 30px;
}
/* カラー設定 */
.dark01 { background: #6c001e; }
.dark05 { background: #012261; }
.dark09 { background: #012947; }
.bright01 { color: #6c001e; background: #ff82cf; }
.bright05 { color: #012261; background: #69cdff; }
.bright09 { color: #012947; background: #34dffe; }

レンダリング例

test.png

解説

  • グリッドレイアウトとはページを格子状に区切って長方形の枠を配置していく構造である。
  • display: grid; を指定するとその子要素がグリッドで並べられる対象となる。
  • 子要素に grid-column: grid-row: を指定してグリッドのどこに配置するかを決定する。
  • grid-template-columns: では横に並ぶ列のスタイルを指定する。
  • 400px 2fr 1frは指定した長さで合計3つのグリッドを作成することを表す。
  • frは長さを指定されなかった分をfrの全体で分け合う単位。この場合 1fr = (width-400)/3 。
  • grid-template-rows: では縦に並ぶ行のスタイルを指定する 1fr = (800-400)/4 = 100px 。

なぜコンテンツ5だけ背景色がグリッドの全体にかかっていないのか。
cssをよく見るとgrid22だけdisplay: flex; がかかっていない。
ただしjustify-self: center; align-self: center; というflexっぽい設定がかかっている。
これはgridの子要素のプロパティで縦配置、横配置をそれぞれ決定することができる。
これによってgrid22のelementはグリッドのサイズではなく、
中のcontents5のelementに合わせられる。

グリッド中の位置指定

index.html
<div class="grid-root">
    <div class="grid11-12 dark01">
        <div class="contents1 bright01">
            ここはコンテンツ1です。
        </div>
    </div>
    <div class="grid22 dark03">
        <div class="contents3 bright03">
            ここはコンテンツ3です。
        </div>
    </div>
    <div class="grid13-33 dark02">
        <div class="contents2 bright02">
            ここはコンテンツ2です。
        </div>
    </div>
    <div class="grid21-32 dark04">
        <div class="contents4 bright04">
            ここはコンテンツ4です。
        </div>
    </div>
</div>
index.css
/* グリッドの親要素の設定 */
.grid-root {
    display: grid;
    grid-template-columns: 2fr 3fr 1fr;
    grid-template-rows: 1fr 2fr 1fr;

    grid-template-areas: "gridA gridA gridB"
                         "gridC gridC gridB"
                         "gridC gridC gridB";
    width: 100%;
}
/* グリッドの子要素の設定 */
.grid11-12 {
    grid-column-start: 1;
    grid-column-end: 3;
    grid-row-start: 1;
    grid-row-end: 2;
}
.grid22 {
    grid-column-start: 2;
    grid-column-end: 3;
    grid-row-start: 2;
    grid-row-end: 3;
    z-index: 1;
    height: 300px;
}
.grid13-33 {
    grid-column-start: 3;
    grid-column-end: 4;
    grid-row-start: 1;
    grid-row-end: 4;
}
.grid21-32 {
    grid-column-start: 1;
    grid-column-end: 3;
    grid-row-start: 2;
    grid-row-end: 4;
}
/* コンテンツ自体にスタイルを設定 */
.contents1 {
    width: 50%;
    height: 50%;
    margin-top: 20px;
    margin-left: 20px;
}
/* カラー設定 */
.dark01 { background: #6c001e; }
.dark02 { background: #510011; }
.dark03 { background: #003019; }
.dark04 { background: #002e83; }
.bright01 { color: #6c001e; background: #ff82cf; }
.bright02 { color: #510011; background: #fca1a8; }
.bright03 { color: #002417; background: #7ff1cf; }
.bright04 { color: #002e83; background: #a8deff; }

レンダリング例

area.png

解説

  • grid-template-columns: 2fr 3fr 1fr; により横は2:3:1に分割される。
  • grid-template-rows: 1fr 2fr 1fr; により縦は1:2:1に分割される。
  • grid22の高さが300pxであるから2fr = 300px である。

z-indexとかgrid-template-areasという謎のマトリックスがあるけどとりあえず無視しよう。
grid-column-start: grid-column-end: grid-row-start: grid-row-end: の4要素がそれぞれにある。
想像通り横の開始位置、終了位置、縦の開始位置、終了位置を表す。
しかし3×3なのに1~4の数字が出てくるのは不可解である。
この数字の意味を図示しよう。

area2.png

なんとマス目ではなく線で数える座標だったのだ。
将棋ではなく囲碁方式。
(2, 3)と(3, 2)の位置は図のように覚えたほうがよい。
コンテンツ1は横が1~3で2セル分、縦は1~2で1セル分確保されている。
コンテンツ3とコンテンツ4は重なっているが z-index; によってコンテンツ3が上に来ている。
なお負の数を指定すると右下を(-1, -1)とした座標系として考えることもできる。

lintを意識

領域の指定の方法は色々あるがちゃんと考えないと混乱してしまう。
そこでわかりやすいルールを考えてみた。
以下のcssの組は全て同じ領域を示す。

rule.css
/* 基本の4値指定 (推奨)
1行に1つの要素しか表現していないので、
他のバッチファイルとかで一元的に生成するなどでは非常に使いやすい。
人が見ても間違えることの少ない優秀な形式。
columnが先かrowが先かは諸説あるかもしれないがstartがendより先の順番は絶対。
*/
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 1;
grid-row-end: 2;

/* 暗黙のend (NG)
※ endを省略するとend = start + 1と解釈される
start、end方式で記述するなら省略するな。
マイナス座標のときややこしくなるし、
後で見返した時に書き忘れかとも思われる恐れあり。
endだけ書くのもNG。
*/
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 1;

/* マイナス座標 (warning)
積極的に使うものではない。
右下からの座標のほうがわかりやすい場合のみ使用すべし。
*/
grid-column-start: -2;
grid-column-end: -4;
grid-row-start: -3;
grid-row-end: -4;

/* startとendの逆転 (NG)
論理構造を考えるとstartはendより小さくなるべき。
そうでないと読んでいるときに混乱する。
start < end
絶対値も付けて |start| < |end| を満たすべし。
*/
grid-column-start: 3;
grid-column-end: 1;
grid-row-start: 2;
grid-row-end: 1;

/* start / end でのショートハンド表記 (推奨)
これが一番スマートでかつヒューマンエラーが少ない表記かと。
*/
grid-column: 1 / 3;
grid-row: 1 / 2;

/* start / end 表記での幅1の省略 (OK)
start, endならちゃんと4つ書いてほしいが、この形式だと省略しても許容される。
*/
grid-column: 1 / 3;
grid-row: 1;

/* マイナス座標で幅1の省略 (NG)
-4は間違いではないです。
マイナスはややこしいんですよ。
なのでマイナスは使用禁止です。
*/
grid-column: -2 / -4;
grid-row: -4;

/* マイナス座標での start / end 表記 (warning)
どうしてもマイナスを使いたい場合はこちら。
*/
grid-column: -2 / -4;
grid-row: -3 / -4;

/* start / span 幅 の表記 (OK)
開始点と要素幅を指定する方式。
*/
grid-column: 1 / span 2;
grid-row: 1 / span 1;

/* span 幅 / end の表記 (OK)
要素幅と終了点を指定する方式。
*/
grid-column: span 2 / 3;
grid-row: span 1 / 1;

/* grid-areaによる集約 (warning)
※先の図に出した座標(1, 1), (2, 3)の領域を表します。
縦と横どっちだっけ案件の戦犯なので禁止した方がいい。
使う場合はいっそ全部この形式にした方がよい。
*/
grid-area: 1 / 1 / 2 / 3;


/* grid-areaによる名前指定 (OK)
※grid-template-areas で設定した名前の領域が使えます。
視覚的にわかりやすいのが利点かと。
*/
grid-area: gridA;

#線(グリッドライン)に名前を付ける

##コード例

index.css
/* グリッドの親要素の設定 */
.grid-root {
    display: grid;
    grid-template-columns: [left] 2fr [menu] 3fr [contents] 1fr [right];
    grid-template-rows: [top] 1fr [header_end] 2fr [footer_start] 1fr [bottom];
    width: 100%;
}
/* グリッドの子要素の設定 */
.grid11-12 {
    grid-column: left / contents;
    grid-row: top / header_end;
}
.grid22 {
    grid-column: menu / contents;
    grid-row: header_end / footer_start;
    z-index: 1;
    height: 300px;
}
.grid13-33 {
    grid-column: contents / right;
    grid-row: top / bottom;
}
.grid21-32 {
    grid-column: left / contents;
    grid-row: header_end / bottom;
}

##解説

grid-template-columns: grid-template-rows: の幅指定の間に[]付きで名前を書くと
それがグリッドラインの名前として定義されstart, endの位置を表す名前として参照できる。
この例だとleftが0にmenuが1になると考えればいい。
むしろ数字を意識せずにレイアウトできる。

Osaka.css
grid-template-columns: [yotsubashi] 1fr [mizosuji] 1fr [sakaisuji] 1fr [tanimati];
grid-template-rows: [touzai] 1fr [keihan] 1fr [tyuou] 1fr [nagahori] 1fr [sennichimae];

こんなcssにすれば御堂筋と堺筋の間で京阪以南だけ色を変えるみたいなことが簡単にできる。

セルの自動配置

grid-auto-flow:

位置を明示的に指定しないと左上に全部重なって詰められる。
grid-auto-flow: を指定するとflexのように横方向または縦方向に順番に詰めるようにできる。

##コード例

index.htm
<div class="grid-root">
    <div class="main dark01">
        <div class="contents1 bright01">
            ここはメインコンテンツです。
        </div>
    </div>
    <div class="dark02">
        <div class="contents2 bright02">
            ここはコンテンツ2です。
        </div>
    </div>
    <div class="dark03">
        <div class="contents3 bright03">
            ここはコンテンツ3です。
        </div>
    </div>
    <div class="dark04">
        <div class="contents4 bright04">
            ここはコンテンツ4です。
        </div>
    </div>
    <div class="dark05">
        <div class="contents5 bright05">
            ここはコンテンツ5です。
        </div>
    </div>
</div>
index.css
/* グリッドの親要素の設定 */
.grid-root {
    display: grid;
    grid-template-columns: 400px [main_start] 1fr [main_end] 400px;
    grid-template-rows: 200px 200px 200px;
    grid-auto-flow: row; // row or column
}
/* グリッドの子要素の設定 */
.main {
    grid-column: main_start / main_end;
    grid-row: 1 / -1;
}

/* カラー設定 */
.dark01 { background: #6c001e; }
.dark02 { background: #510011; }
.dark03 { background: #4b0001; }
.dark04 { background: #002e83; }
.dark05 { background: #012261; }
.bright01 { color: #6c001e; background: #ff82cf; }
.bright02 { color: #510011; background: #fca1a8; }
.bright03 { color: #4b0001; background: #fca88c; }
.bright04 { color: #002e83; background: #a8deff; }
.bright05 { color: #012261; background: #69cdff; }

##レンダリング例

grid-auto-flow: row; の場合

flow1.png

grid-auto-flow: column; の場合

flow2.png

##解説

gridの子要素でgridのパラメータを指定しているのはmainの1つだけ。
この要素は横方向は名前指定で中央のセルを指定している。
縦方向は1~-1、すなわち全てである。
grid-auto-flow: row; の場合は空いているセルを上から順に、左から右へと埋めていく。
grid-auto-flow: column; の場合は空いているセルを左から順に、上から下へと埋めていく。

全部埋まったらどうするんだろう。
私、気になります。

暗黙的なグリッドとは

grid-auto-rows:
grid-auto-columns:

最初に定義したgridのサイズの範囲外に配置しようとすると
グリッドは自動的に拡張される。
そのときにどのように拡張されるのかを定義する。

##コード例

index.htm
<div class="grid-root">
    <div class="main dark01">
        <div class="contents1 bright01">
            ここはメインコンテンツです。
        </div>
    </div>
    <div class="dark02">
        <div class="contents2 bright02">
            ここはコンテンツ2です。
        </div>
    </div>
    <div class="dark03">
        <div class="contents3 bright03">
            ここはコンテンツ3です。
        </div>
    </div>
    <div class="dark04">
        <div class="contents4 bright04">
            ここはコンテンツ4です。
        </div>
    </div>
    <div class="dark05">
        <div class="contents5 bright05">
            ここはコンテンツ5です。
        </div>
    </div>
    <div class="dark06">
        <div class="contents6 bright06">
            ここはコンテンツ6です。
        </div>
    </div>
    <div class="dark07">
        <div class="contents7 bright07">
            ここはコンテンツ7です。
        </div>
    </div>
    <div class="dark08">
        <div class="contents8 bright08">
            ここはコンテンツ8です。
        </div>
    </div>
    <div class="dark09">
        <div class="contents9 bright09">
            ここはコンテンツ9です。
        </div>
    </div>
</div>
index.css
/* グリッドの親要素の設定 */
.grid-root {
    display: grid;
    grid-template-columns: 400px [main_start] 1fr [main_end] 400px;
    grid-template-rows: 200px 200px 200px;
    grid-auto-flow: row; // row or column

    grid-auto-columns: 1fr;
    grid-auto-rows: 200px;
}
/* グリッドの子要素の設定 */
.main {
    grid-column: main_start / main_end;
    grid-row: 1 / -1;
}

/* カラー設定 */
.dark01 { background: #6c001e; }
.dark02 { background: #510011; }
.dark03 { background: #4b0001; }
.dark04 { background: #002e83; }
.dark05 { background: #012261; }
.dark06 { background: #011b5f; }
.dark07 { background: #003019; }
.dark08 { background: #012a31; }
.dark09 { background: #012947; }
.bright01 { color: #6c001e; background: #ff82cf; }
.bright02 { color: #510011; background: #fca1a8; }
.bright03 { color: #4b0001; background: #fca88c; }
.bright04 { color: #002e83; background: #a8deff; }
.bright05 { color: #012261; background: #69cdff; }
.bright06 { color: #011b5f; background: #a5c3fe; }
.bright07 { color: #002417; background: #7ff1cf; }
.bright08 { color: #012a31; background: #34deea; }
.bright09 { color: #012947; background: #34dffe; }

##レンダリング例

rowの場合

anmoku1.png

columnの場合

anmoku2.png

##解説

以下の二行が追加されただけである。
grid-auto-columns: 1fr;
grid-auto-rows: 200px;

grid-auto-flow: row; の場合は下に拡張される。
その高さは指定された200pxである。
mainコンテンツの領域は 1 / -1 で指定していたが拡張されてはいない。

grid-auto-flow: column; の場合は右に拡張される。
その幅は指定された1frである。
1frなのでmainコンテンツの幅と同じになっていることが確認できる。

ちなみにいきなり
grid-column: 100 / 101;
grid-row: 100 / 101;
みたいにやっても配置されるが、
そんなアホなことはやらないように。

#その他のプロパティ

##グリッド間ギャップ

grid-column-gap:
grid-row-gap:

この行だけグリット間隔広げたいとかいうオチが見える。
グリット間隔もグリッドで個別に定義した方がよいのでは。

##ショートハンド

これ以上のショートハンドは基本的には使わないほうが良さげです。
人間業ではないので。
どうしてもショートハンドを使いたがる頭の悪い上司がいる?
上司のPCからリポジトリ参照した時に
minify_css.batでもかましたファイルに見せかけるプロキシでも書いとけ!

まとめ

おそらくメディアクエリによって
grid-template-columns:
grid-template-rows:
といった要素を変更することによって
レスポンシブルなデザインが容易に作れるのが利点なんだろうが
gridの何でもできるが故の不安もある。
動的に拡張されていくのは嫌な予感しかしないぞ。

複雑なレイアウトも試してみた↓
Excel方眼紙をdisplay: grid; で実現する

11
15
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?