IEがサポート終了したので、そろそろGrid Layoutを使ってみよう!
- 目次
Grid Layoutの基本
基本概念とポイント
- グリッドコンテナーを作成
要素に対して「display: grid
」か「display: inline-grid
」を指定
直接の子要素がグリッドアイテムに変わります - グリッドトラック(行や列)を定義
「grid-template-columns
」行数と幅
「grid-template-rows
」列数と高さ - トラック(行や列)のサイズ
*repeat()
関数で繰り返す書き方ができます- 固定の行や列のサイズ(px単位)
- 可変の行や列サイズ(%や
fr
単位)
*fr
はグリッドコンテナー内の利用可能な空間の比です - auto
同じ列または行にfr
単位がある場合アイテムのコンテンツ幅に合わせてグリッドサイズを調整します(なけれがfr
と同じ)
- 暗黙的なグリッド
*明示的なグリッドは定義したトラック(行と列)で構成されます
すなわち行は定義しなくても、列グリッドは勝手に行を作ります
これは暗黙的なグリッドです
*暗黙的なグリッドでは、デフォルトで自動サイズ調整するのでサイズはトラック内の内容物で決まります - 暗黙的なグリッドのトラックに高さや幅をつけます
grid-auto-rows
grid-auto-columns
*minmax()
関数を使うことでより柔軟に指定することができます - グリッドアイテムの配置
- 位置が明示されていないアイテムはアルゴリズムにより自動で配置されます
- 「線番号」や「エリア(名前)」を指定してアイテムを配置することができます
用語
- グリッド
- 列と行を定義する水平線と垂直線の集合が交差したものです
要素をグリッド上の行と列の中に配置できます
- Grid Track(グリッドトラック)
- 行と列のこと
2本のグリッド線の間の空間
暗黙的グリッドにもトラックが生成されます
- Grid Cell (グリッドセル)
- 4つの交差するグリッド線に囲まれた領域
最小単位
- Grid Line (グリッド線)
- トラックを定義すると作成されます
アイテムの配置はトラックではなくグリッド線が対象になります
- Grid Areas(グリッド領域ーエリア)
- 1つまたは複数のセルの範囲(
*必ず四角形でL字型は作れません
1、display: gridでグリッドコンテナーを作成
2、grid-template-columnsで3つの同幅の行トラックを作成
3、自動で配置(線ベースの配置)される子要素(グリッドアイテム)の高さを
grid-auto-rows(最小値50px,最大値auto)で指定
*親のコンテナで指定します
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
/* repeat()関数を使用すると
grid-template-columns: repeat(3, 1fr); */
grid-auto-rows: minmax(50px, auto);
}
<div class="grid">
<div class="grid__item">1</div>
<div class="grid__item">2</div>
<div class="grid__item">3</div>
<div class="grid__item">4</div>
<div class="grid__item">5</div>
<div class="grid__item">6</div>
</div>
グリッドアイテムの配置
グリッドアイテムに「線番号」や「エリア(名前)」を指定してアイテムを配置します
線番号で指定
グリッドアイテムに「grid-column
」「grid-row
」
グリッド線の線番号
- 列の左端から順に:列線の1・2・3…
- 行の上端から順に:行線の1・2・3…
反対から数える時は「-値」で指定できます
- 列の右端から順に:列線の-1・-2・-3…
- 行の下端から順に:行線の-1・-2・-3…
「grid-column-start,grid-column-end」と
「grid-row-start ,grid-row-end」は
「grid-column
」と「grid-row
」で値は「開始の線番号/終了の線番号
」の一括指定ができます
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(50px, auto);
}
.grid__item:nth-child(1) {
/* 1から3の列・1の行 */
grid-column: 1 / 4;
grid-row: 1;
}
.grid__item:nth-child(2) {
/* 1の列・2から3の行 */
grid-column: 1;
grid-row: 2 / 4;
}
エリアで指定
- グリッドコンテナーに「
grid-template-areas
」
*「grid-template-columns」「grid-template-row」と併用
グリッドアイテムに「gird-area
」 - グリッドコンテナーに「
grid-template
」
「grid-template-columns」「grid-template-row」は不要
*各行の末尾で行の幅を指定(省略可)
一番最後の行の後ろに「/」その下の行で各列の幅を指定
グリッドアイテムに「gird-area
」
グリッドコンテナは、grid-template-areas
でエリアに名前をつけて
グリッドアイテムは、grid-area
で配置します
.wrap {
display: grid;
grid-template-areas:
"title title"
"sub main";
grid-template-columns: 100px auto;
/*grid-templateで書くと
grid-template:
"title title"
"sub main"/
100px auto;
*/
}
.wrap .title {
grid-area: title;
text-align: center;
}
.wrap .sub {
grid-area: sub;
}
.wrap .main {
height: 150px;
grid-area: main;
}
<div class="wrap">
<div class="title">タイトル</div>
<div class="sub">サブです</div>
<div class="main">メインです</div>
</div>
*grid-areaで場所を指定できるのは名前をつけた場所だけです
セル間隔・その他
セル間隔grid-column-gap
(column-gap )と grid-row-gap
(row-gap)
または一括指定:grid-gap
( gap )
*接頭辞付き(grid-)の方がブラウザ対応がいいようです
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 50px;
grid-column-gap: 10px;
grid-row-gap: 15px;
}
入れ子
グリッドアイテムはグリッドコンテナーにもなれます
.grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-auto-rows: 100px;
}
.grid .grid__item:nth-child(1) {
display: grid;
grid-template-columns: repeat(2, 1fr);
padding:1em;
}
.grid .grid__item >div{
border:solid 1px red;
}
<div class="grid">
<div class="grid__item">
<div>1の1</div>
<div>1の2</div>
</div>
<div class="grid__item">2</div>
</div>
グリッドアイテムが同じセルを占有する場合はz-index
で重ね合わせの順を指定できます
*z-indexがなければ後に書かれた方が上になります
例では
2番目のアイテムは「列が1と2のセル」「行が1と2のセル」のエリアに配置
1番目のアイテムは「列が2のセル」「行が1のセル」で「z-index」で2番目のアイテムの上に重なっています
3番目のアイテムアイテムは「列が1のセル」「行が2のセル」で後に書かれているのでそのまま2番目のアイテムの上に重なっています
.grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-auto-rows: 50px;
}
.grid .grid__item:nth-child(1) {
grid-column: 2;
grid-row: 1;
z-index: 1;
}
.grid .grid__item:nth-child(2) {
grid-column: 1/3;
grid-row: 1/3;
}
.grid .grid__item:nth-child(3) {
grid-column: 1;
grid-row: 2;
}
<div class="grid">
<div class="grid__item">1</div>
<div class="grid__item">2</div>
<div class="grid__item">3</div>
</div>
自動配置アルゴリズムの動作を制御grid-auto-flow
: デフォルトはrow
ですgrid-auto-flow : column;
アイテムは各列を順番に埋めていきます
.grid {
display: grid;
grid-auto-flow: column;
}
Grid LayoutとFlexbox
- Grid Layoutは列と行の2次元で子要素を管理
まずはレイアウトを作成 - Flexboxは縦か横の1次元で子要素を管理
内容物のサイズに合わせて
レスポンシブな動作
ウィンドウのサイズに応じて子要素(アイテム)の数を調整
<div class="wrap">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
</div>
repeat()
関数とauto-fill
およびauto-fit
を使用してトラックリストを作ります
*あくまでコンテンツは行と列に配置されます
auto-fill
:グリッドアイテムが1つ以上入るスペースができたら、空のアイテムで埋める
*余白があるauto-fit
:スペースができたら、グリッドアイテムの幅が変わってスペースが埋められます*minmax()
関数のmaxの値を1frなどサイズが自動で決まる値であることが大前提
repeat()
関数でauto-fill
キーワードを使用して
コンテナーに収まるだけの150pxの列トラックを作成します
.wrap{
display: grid;
grid-template-columns: repeat(auto-fill, 150px);
}
repeat()
関数にauto-fit
とminmax()
関数を組み合わせてスペースを埋めます
.wrap{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
Flexboxで実装した場合
.wrap{
display: flex;
flex-wrap: wrap;
}
.wrap .item{
flex-basis:150px;
}
.wrap{
display: flex;
flex-wrap: wrap;
}
.wrap .item{
flex-grow:1;
flex-basis:150px;
}
ボックスの配置
<div class="wrap">
<div class="item">box1</div>
<div class="item">box2</div>
<div class="item">box3</div>
<div class="item">box4</div>
</div>
Flexbox
フレックスコンテナーの高さ(min-height: 100px;)を決めて
align-itemsの初期値はstreachなので1つ目は高さいっぱいに伸びます
フレックスアイテムのalign-selfを上書きしています
*フレックスアイテムの幅は内容物で自動調整されるので「100%」にして自動で縮小させることで均等に分割しています
.wrap {
display: flex;
min-height: 100px;
}
.wrap .item {
width:100%
}
.wrap .item:nth-child(2) {
align-self: flex-start;
}
.wrap .item:nth-child(3) {
align-self: center;
}
.wrap .item:nth-child(4) {
align-self: flex-end;
}
Grid Layout
グリッド領域(エリア)の中にアイテムを配置します
.wrap {
display: grid;
grid-template-columns: repeat(4,1fr);
grid-auto-rows: 100px;
}
.wrap .item:nth-child(2) {
align-self: flex-start;
}
.wrap .item:nth-child(3) {
align-self: center;
}
.wrap .item:nth-child(4) {
align-self: flex-end;
}
グリッドアイテムをインライン軸に配置しますjustify-items: start / center / end
.wrap {
display: grid;
grid-template-columns: repeat(3,1fr);
grid-auto-rows: 50px;
justify-items: start;
}
どっちを使う?
アイテムの複雑な配置以外で「どちらでも実装できそうなとき」ってどっちがいいのだろう?
まだ実感がないのでググってみたメモ
Grid Layout
メインとサイドバー
*サイドバーにalign-selfを指定しない場合はコンテンツの長さに関係なくサイドバーの高さはメインと同じになります
<div class="wrapper">
<aside>Sidebar</aside>
<main>Main</main>
</div>
@media (min-width: 1024px) {
.wrapper {
display: grid;
grid-template-columns: 300px 1fr;
/* grid-template-columns: 30% 70%;*/
}
aside {
align-self: start;
}
}
コンテンツ全体のレイアウト(入れ替えが簡単にできる)
1024px以上で2カラム(Sideを横に)
600px以上でContentを3列に
<div id="container">
<main id="main">Main</main>
<aside id="side">Side</aside>
<section id="section">
<article>Content1</article>
<article>Content2</article>
<article>Content3</article>
</section>
#container {
display: grid;
/*side main sectionの位置を変更がすぐできる*/
grid-template:
"side"
"main"
"section"/
1fr;
grid-gap: 1rem;
}
@media (min-width: 600px) {
#section{
display: grid;
grid-template-columns: repeat(3, 1fr);
/* 複数行になった場合の高さ対策 不要かも*/
grid-auto-rows: minmax(100px, auto);
grid-gap: 1rem;
}
}
@media (min-width: 1024px) {
#container {
display: grid;
grid-template:
"side main main main" auto
"side section section section" 1fr/
1fr 1fr 1fr 1fr;
grid-gap: 1rem;
}
}
#main {
grid-area: main;
}
#side {
grid-area: side;
}
#section {
grid-area: section;
}
カードのグリッド
<div class="wrap">
<div class="item">あ</div>
<div class="item">ああ</div>
<div class="item">ああああ</div>
<div class="item">ああああああああ</div>
<div class="item">ああああああああああああああああああああああああああああああああ</div>
</div>
余談:例えば3列並びのレイアウトでアイテム数が3で割り切れないとき
アイテムを左端に揃えたい場合の最終行の対策
Flexboxだと無理やりでした
最後の要素の後ろにafterで空のブロックを作って最終行を左に揃えたりしていた
.wrap {
display:flex;
flex-wrap: wrap;
justify-content:space-between;
gap: 16px;
}
.wrap::after {
display: block;
content:"";
width: 30%;
}
.wrap .item{
width:30%;
}
Grid Layoutだと
*例では最低横幅を200pxでそれよりも狭くなる場合には列を減らします
.wrap{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: 16px;
}
例では3列は固定され、高さの最小値(100px)を決めて高さを調整しています
.wrap {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(100px, auto);
grid-gap: 16px;
}
Flexbox
ヘッダー
左にロゴ、右にナビメニューの一般的な例
<header>
<div class="header__wrapper">
<a href="#"><img src="logo.svg" alt="" /></a>
<nav class="nav"></nav>
</div>
</header>
.header__wrapper{
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.nav{
margin-left: auto;
}
カードのコンポーネント
*600px以上で横並びに
<div class="card">
<img src="..." alt="">
<div class="card-text">
<h2>見出しが入ります</h2>
<p>テキストが入ります</p>
</div>
</div>
.card {
display: flex;
flex-direction: column;
}
@media (min-width: 600px) {
.card {
flex-direction: row;
}
}
画像を左と右交互に配置
.box {
display: flex;
}
.box:nth-child(even) {
flex-direction: row-reverse;
}
コンテンツの中央揃え
Flexbox
.center {
display: flex;
flex-direction: column;
/* 水平方向の中央揃え */
align-items: center;
/* 垂直方向の中央揃え */
justify-content: center;
}
コンテンツの中央揃え
Grid
.center {
display: grid;
place-items: center;
}