もっと知りたい! CSS Grid 前編 minmax()関数の使い方

2016年にCodeGridで連載された「これからのグリッドレイアウト」の続編です。前回紹介できなかったトピックのひとつmixmax()関数。これをプロパティの値にを使うと、レスポンシブな画面に対応することができます。

発行

著者 坂巻 翔大郎 フロントエンド・エンジニア
もっと知りたい! CSS Grid シリーズの記事一覧

はじめに

CSS Gridの記事は2016年のはじめに一度書かれています。ですが、現在では古い情報もあります。また、前回のシリーズでは解説をしていない機能もありました。

そこでこのシリーズでは、前回のシリーズから変更があった仕様や、紹介しなかった機能にもフォーカスして解説を進めます。

まずは、CSS Gridの最新状況を見てみましょう。

CSS Gridの最新状況

執筆現在、CSS Gridに関する仕様書は次のとおりです。

前回の記事で参照していたのは、2015年の仕様書です(CSS Grid Layout Module Level 1 W3C Working Draft, 17 September 2015)。それから2年経っているため、ブラウザの実装状況や、仕様の一部に変更がありました。それらについて確認していきましょう。

ブラウザの対応状況

ブラウザへの実装状況は、大きく進みました。IE11以外の最新ブラウザでCSS Gridを利用することができます。IE11は古いCSS Gridの仕様を参照しているため、一部の機能を使うことができないので注意が必要です。

また、モバイル環境でいうと、iOS 10.2のSafariと、Android 4.4の標準ブラウザでは対応しておらず、使えません。

grid-gapプロパティがgapプロパティに変更

変更されたプロパティを紹介します。

グリッド間の行や列の隙間を定義するためのgrid-gapgrid-column-gapgrid-row-gapプロパティが削除されました。

仕様書に記載されている変更履歴を見ると次のようにあります。

Removed grid-row-gap and grid-column-gap from the list of properties reset by the grid shorthand. (Issue 1036) Removed grid-row-gap, grid-column-gap, and grid-gap properties, replacing with row-gap, column-gap, and gap which are now defined in CSS Box Alignment. (Issue 1696)

ですが、それらの置き換えとして、CSS Grid Layout ModuleではなくCSS Box Alignment Moduleにgapcolumn-gaprow-gapプロパティが追加されました。

CSS Box Alignment 3 §8 Gaps Between Boxesを見ると

Applies to: multi-column elements, flex containers, grid containers

と記述されていることから、CSS Gridだけでなく、Flexboxなどほかのレイアウト系のプロパティでもgapプロパティを使えるようにする目的があり、grid-gapgapへと変更することになったようです。

使用方法や機能は変わっていませんが、古いものと新しいものを並べて、おさらいしておきましょう。

<div class="Grid  -old">
  <div class="Grid_Item"></div>
  <div class="Grid_Item"></div>
  <!-- 以下繰り返し -->
</div>

<div class="Grid  -new">
  <div class="Grid_Item"></div>
  <div class="Grid_Item"></div>
  <!-- 以下繰り返し -->
</div>
.Grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}
.Grid.-old {
  grid-row-gap: 10px;
  grid-column-gap: 25px;
  /* grid-gap: 10px 25px; と同じ意味 */
}
.Grid.-new {
  row-gap: 10px;
  column-gap: 25px;
  /* gap: 10px 25px; と同じ意味 */
}

このプロパティ名の変更は、筆者が確認したところ、Chrome 67とFirefox 61で実装を確認できました。後方互換として古いgrid-gapプロパティにも対応していました。現在grid-gapプロパティが使われていたとしても、この変更によって表示が崩れたりすることはないでしょう。

subgrid

入れ子状のグリッドを定義できるsubgridについては、CSS Grid Layout Module Level 2へ見送りになっています。まだ実装しているブラウザはありません。

グリッドトラックのさまざまなサイズ指定

ここからは、前回のシリーズでは触れなかった、CSS Gridをより活用するための機能を紹介します。

まず最初は、グリッドトラックのサイズを指定するための値に使えるminmax()関数についてです。

minmax()関数は、その引数に最小値と最大値を指定することで、トラックの最小幅と最大幅を定義することができます。

minmax()関数の文法

minmax(最小値, 最大値)

どちらの引数も、次の値を取ることができます。

  • <length> (例:100px)
  • <percentage> (例:50%)
  • <flex> (例: 1fr)*
  • auto
  • max-content
  • min-content

*注:fr単位

後述しますが、現在の仕様ではfrを最小値の値として指定することができません。

それぞれの値は見慣れた値がほとんどです。しかしmax-contentmin-contentはあまり見ない値です*。この2つの値については後述しますので、今はこういった値が使えるということを覚えておきましょう。

*注:min/max-contentとmin/max-widthの違い

似たような表記なので混乱しがちですが、min/max-contentはプロパティに指定できる値です。min/max-widthはご存じのとおり、プロパティです。ですからmin-width: min-contentなどという指定も理論的には可能です。それぞれサイズの指定に関わるものではありますが、根本的に違うものです。

まずは、mimmax()関数を使用したデモを見てみましょう。

minmax()関数の使用例

.Grid {
  display: grid;
  grid-template-columns: minmax(200px, 1fr) 1fr;
}

適用するHTML

<div class="Grid">
  <div class="Grid_Item">
    最小サイズ:200px<br>
    最大サイズ:1fr
  </div>
  <div class="Grid_Item">
    サイズ:1fr
  </div>
</div>

画面幅が広いときは、2つの.Grid_Itemのサイズは1frとなります。ですが画面幅が狭いときには、1つめの.Grid_Itemは最小幅200pxとなり、それ以下のサイズにはなりません。

最小サイズと最大サイズを指定できるminmax()関数は、リストやページのレイアウトに活躍するでしょう。

minmax()関数を活用したリスト

minmax()関数を活用したリストを、その引数の値の種類を変えて紹介していきます。

px指定

まずはpx<length>)を指定した場合です。HTMLとCSSは次のようになります。

<div class="List">
  <div class="List_Item"></div>
  <div class="List_Item"></div>
  <!-- 以下繰り返し -->
</div>
.List {
  display: grid;
  grid-template-columns: minmax(30px, 100px) 100px 100px;
}

1つめのグリッドトラックのサイズが最小30pxで最大100pxとなっているので、画面サイズを変更するとその最小最大サイズの中で可変になります。

%指定

次に%<percentage>)を指定した場合です。

.List {
  display: grid;
  grid-template-columns: minmax(10%, 50%) 100px 100px;
}

1つめのグリッドトラックのサイズが最小10%で最大50%となっているので、画面サイズを変更すると、その中で可変になります。

fr指定

さらに、fr<flex>)*を指定した例も続けて見てみましょう。

*注:fr単位

frという単位については、次の記事に詳しく解説されています。

.List {
  display: grid;
  grid-template-columns: minmax(200px, 1fr) 1fr 1fr;
}

1つめのグリッドトラックのサイズが最小200pxで最大1frとなっているので、画面サイズを変更すると、その中で可変になります。2つめと3つめのグリッドトラックは1frなので、全体幅から1つめのグリッドトラックの幅を引き、そのあまりの幅を2つめと3つめのグリッドトラックで均等に割り振った幅になります。

広い画面では、それぞれのグリッドトラックは同じサイズになります。ですが狭い画面になると、1つめのグリッドトラックだけは最小200pxとしているので、それ以上狭くなることはありません。

【ワンポイント】指定によっては無効になる場合

次のような指定をした場合、ブラウザは正しく解釈できなくなってしまいます。

.List {
  display: grid;
  grid-template-columns: minmax(1fr, 2fr) 1fr 1fr;
}

仕様書によれば、minmax()関数の最小値にfrによる値指定をすると、その指定は無効(invalid)になります(仕様書のNote:によると将来的にこの仕様が変更になる可能性もあるようですが)。

DevToolsで見てみると、図のように値が無効になっていることがわかります。

min-contentとmax-content

これまで紹介してきたminmax()に指定できる値として、min-contentmax-contentがあります。

min-contentはグリッドトラックに含まれるもっとも幅が狭い要素と同じ幅になるように指定されます。逆にmax-contentはグリッドトラックに含まれるもっとも幅が広い要素と同じ幅になるように指定されます。

説明
min-content overflowを起こさない範囲で要素を縮めた最小の幅。そのボックス内にある一番文字数の多い単語や、一番長いインラインアイテムまで縮める
max-content その中のインライン要素やテキストが改行を起こさない範囲で伸ばした最小の幅

min-contentの動きをデモで確認してみましょう。HTMLは前述のリストに画像を加えたものです。

<div class="List">
  <div class="List_Item">
    <img class="List_Img" src="./img/banner.png" alt="">
  </div>
  <div class="List_Item"></div>
  <!-- 以下繰り返し -->
</div>

追加した画像の幅は500pxですが、CSSでは幅100%かつ最小幅を250pxとしています。

.List {
  display: grid;
  gap: 10px;
  grid-template-columns: minmax(min-content, min-content) 1fr 1fr;
  /* grid-template-columns: min-content 1fr 1fr; と同じ意味 */
}
.List_Img {
  display:block;
  width: 100%;
  min-width: 250px;
}

デモを見るとわかりますが、1つめのグリッドトラックの幅は、最小のコンテンツになるので、ここではCSSで指定された画像幅の250px(min-width: 250px)がグリッドトラックの幅となります。

max-contentの動きもデモで確認してみましょう。

.List {
  display: grid;
  gap: 10px;
  grid-template-columns: minmax(max-content, max-content) 1fr 1fr;
  /* grid-template-columns: max-content 1fr 1fr; と同じ意味 */
}
.List_Img {
  display:block;
  width: 100%;
  min-width: 250px;
}

1つめのグリッドトラックの幅は、最大のコンテンツになるので、画像の最大幅500pxがグリッドトラックの幅となります。

min-contentとmax-contentとの組み合わせ

これだけですと、どう活用すればいいのかがわかりにくいですが、2つの値を組み合わせると次のようになります。

.List {
  display: grid;
  gap: 10px;
  grid-template-columns: minmax(min-content, max-content) 1fr 1fr;
}
.List_Img {
  display:block;
  width: 100%;
  min-width: 250px;
}

1つめのグリッドトラックのサイズを、minmax(min-content, max-content)としたことで、最小が「最小コンテンツの幅」となり、最大が「最大コンテンツ幅」になるため、幅が可変するようになります。

auto

minmax()関数に使うautoは次のような振る舞いをします。

  • minmax()関数の最小(第一引数)に指定された場合はmin-contentと同じになる
  • minmax()関数の最小(第二引数)に指定された場合はmax-contentと同じになる

つまり、先ほどのリストで紹介したCSSは、autoを使い、次のように書き換えることができます。

.List {
  grid-template-columns: minmax(auto, auto) 1fr 1fr;
  /* grid-template-columns: minmax(min-content, max-content) 1fr 1fr; と同じ意味になる */
  /* grid-template-columns: auto 1fr 1fr; とも同じ意味になる */
}

筆者は、automin/max-contentと同じ振る舞いをするなら、autoだけで良いのでは?という疑問がありました。しかし、次のようなことをしたい場合に、最小値にmax-contentを指定することがあるかもしれません。

.List {
  grid-template-columns: minmax(max-content, 1fr) 1fr 1fr;
}

こうすれば、最小はコンテンツの最大幅になり、画面幅が広いときは1frになるといったことが指定ができます。

minmax()を活用したページレイアウト

ここまで個別にminmax()関数に指定できる値を解説してきましたが、まとめとして、このminmax()をページのレイアウトに使用した例を紹介します。

このデモでは、ヘッダーは画面幅いっぱいに配置され、コンテンツ部は指定した最大幅以上にならず、左右に均等な余白を持って、画面の中央に配置されます。

HTMLは次のとおりです。

<div class="Grid">
  <div class="Grid_Header">
    ヘッダ
  </div>
  <div class="Grid_Body">
    メインコンテンツ
  </div>
</div>

CSSでは、どういった枠を作り、その枠にどの要素を当てはめるか、という指定をしています。

.Grid {
  display: grid;
  gap: 10px;
  grid-template-columns: minmax(10px, 1fr) minmax(0, 980px) minmax(10px, 1fr);
  grid-template-rows: auto auto;
}
.Grid_Header {
  grid-row: 1 / 2;
  grid-column: 1 / 4;
}
.Grid_Body {
  grid-row: 2 / 3;
  grid-column: 2 / 3;
}

この実装の要になるのはgrid-template-columnsの指定です。

grid-template-columns: minmax(10px, 1fr) minmax(0, 980px) minmax(10px, 1fr);

このgrid-template-columnsプロパティ値の意味を図解すると次のようになります。

  • 1つめと3つめのグリッドトラックは、最小10px、最大は1fr
  • 2つめのグリッドトラックは、最小0px、最大は980px

ここに、.Grid_Header.Grid_Bodyを配置します。抜粋したコードは次のとおりです。

.Grid_Header {
  grid-row: 1 / 2;
  grid-column: 1 / 4;
}
.Grid_Body {
  grid-row: 2 / 3;
  grid-column: 2 / 3;
}

このコードを図解すると次のようになります。

  • .Grid_Headerは画面幅いっぱいに配置される
  • .Grid_Bodyは中心の部分に配置され、左右に余白を持つようにする

CSS Gridを使用せずに、同様の振る舞いを実装しようとすると、ネガティブマージンを使用したり、.Grid_Bodyに幅や左右の余白の指定をする必要があります(他にも方法はありますが)。

CSS Gridを使用すれば、グリッドコンテナである.Gridでレイアウトを定義し、グリッドアイテム(.Grid_Header.Grid_Body)をそのレイアウトに当てはめればいいので、CSSが簡潔になります。

ここまでのまとめ

今回はCSS Gridの仕様で変更があったgapプロパティをはじめ、前回の「これからのグリッドレイアウト」シリーズで書ききれなかったプロパティの値を紹介しました。

次回はrepeat()関数などを中心にプロパティの値を紹介をしたいと思います。