CSSのdisplay: gridを使ってグリッドシステムを作成したときに、コンテナの中の列の幅や行の高さを指定するときに、「fr」という単位を使用することがあります。
この「fr」は非常に便利で、画面幅に合わせて要素の幅を自動調整するレスポンシブ設計にとても役立ちます。
しかし、使い方には少々クセがあります。
また「%」や「auto」など「fr」と似たような指定ができるものもあります。
ここでは「fr」とはそもそも何なのか?「fr」を使って単位を指定する方法、「fr」と「%」の違いは何か?「fr」と「auto」の違いは何かについて実例で解説しています。
そもそも「display: grid」やグリッドシステムって何?という方は下記をご参考ください。
【CSS】グリッドシステム(grid system, display: grid;)とは何か?要素の長さや位置の調整方法を実例で解説
frとは何か?
frとは、指定したfrの合計値でコンテナの中の行あるいは列を分割する指定方法です。
例えば、「grid-template-columns: 1fr 1fr 1fr 1fr;」とした場合、コンテナの横方向を4で割った幅が1frとなります。
例えば、「grid-template-columns: 1fr 2fr 3fr 4fr;」とした場合、コンテナの横方向を10で割った幅が1frとなります。
frとはfractionの略で「分数」という意味です。
frを使うメリット
frを使うメリットは画面幅に合わせて要素のサイズを調整できることです。
「%」でも画面幅に合わせて要素のサイズを調整することができますが、何分割するといった指定は計算が必要になります。
frを使えば、簡単に何分割分を割り当てるかを指定することができます。
frの使用例:repeat関数を使った場合
grid-template-columnsをrepeat(4, 1fr)
とした場合、列をきれいに4分割することができます。
display: grid;
gap: 20px;
grid-template-columns: repeat(4, 1fr);

なお、repeat(4, 1fr)は1frを4回繰り返した以下の指定と同じです。
1fr 1fr 1fr 1fr
1fr, 2fr, 3fr, 4frで幅を指定する
コンテナの中を行あるいは列数で割った幅や高さを1frとして、2fr, 3frといった形で幅を指定することもできます。
「grid-template-columns: 1fr 2fr 3fr 4fr;」とした場合、frの合計値「10」で横幅を割った幅が「1fr」となります。
display: grid;
gap: 20px;
grid-template-columns: 1fr 2fr 3fr 4fr;

frと他の単位を組み合わせる
行や列の幅や高さを指定するときに「fr」を使うときは「fr」だけを使わなければいけないわけではありません。
複数の単位で長さを指定することも可能です。
なお、「fr」を他の単位と組み合わせたときは、1frは長さの指定がない幅を列数で割った値となります。
実例
例えば「grid-template-columns: 150px 1fr 3fr 2fr 10%;」と指定した場合、画面横幅(親要素の最大幅)から150pxと10%を引いた値を、6で割った値が1frとなります。
display: grid;
gap: 20px;
grid-template-columns: 150px 1fr 3fr 2fr 10%;

frと%の違い
frと%の違い
「fr」と「%」ではギャップの取扱に大きな違いがあります。
「fr」はギャップも含んだ長さで分割するのに対し、「%」はギャップを含まない長さとなります。
コードの例
grid-template-columns: repeat(4, 1fr);
↑↓ 異なる
grid-template-columns: repeat(4, 25%);
↑↓ 同じ
grid-template-columns: repeat(4, cals(100%/4));
実例
「%」を使った場合
画面を列方向に4分割したいときに、各列の長さを「%」を使って「25%」にしてしまうと、ギャップの分だけ画面からはみ出てしまいます。
.grid-wrapper{
display: grid;
gap: 20px;
grid-template-columns: repeat(4, 25%);
}
ブラウザの表示は以下のようになります。

開発ツールを使って確認すると、ギャップの分だけ一番最の列の要素がグリッドの幅をオーバーしていることがわかります。

「fr」を使った場合
画面を列方向に4分割したいときに、各列の長さを「fr」を使って「repeat(4, 1fr)」とすれば、きちんとギャップも含めてグリッドの中に納まります。
.grid-wrapper{
display: grid;
gap: 20px;
grid-template-columns: repeat(4, 1fr);
}
ブラウザの表示は以下のようになります。

開発ツールを使って確認すると、きれいにグリッドの中に納まっていることがわかります。

frとautoの違い
frとautoの違い
「fr」と「auto」はどちらも要素の幅で自動調整する機能を持っています。ただし何を基準に自動調整するかが異なります。
「fr」はコンテナの外枠の高さや幅に対して分割した値となります。
一方「auto」は中の要素の幅に合わせて自動調整します。
ただし、上記の違いが生じるのは「fr」と「auto」を同時に指定したときのみです。「fr」なしで「auto」のみで指定した場合は、「fr」と同じ挙動になります。
実例
例えば「grid-template-columns: 1fr auto 1fr;」といったように、1frとautoを混ぜ合わせると以下のようになります。
.grid-wrapper{
display: grid;
gap: 20px;
grid-template-columns: 1fr auto 1fr;
}
ブラウザの表示は以下のようになります。

「auto」で指定した部分が要素の幅となり、残りの幅を2で割ったものが「1fr」となっています。
frが無い場合は、autoはfrと同じ働きをする
幅や高さを指定するときに「fr」を使用せず「auto」を使用した場合は、「fr」と同じ働きをします。
autoのみの場合
.grid-wrapper{
display: grid;
gap: 20px;
grid-template-columns: auto auto auto;
}c
ブラウザの表示は以下のようになります。

autoをfr以外の他の単位と組み合わせた場合
「fr」がない状態で、「auto」を「px」などの他の単位と組み合わせた時も、「auto」は「fr」と同じ挙動になります。
.grid-wrapper{
display: grid;
gap: 20px;
grid-template-columns: 20px repeat(3, auto);
}c
ブラウザの表示は以下のようになります。

repeat関数の挙動:画面幅による行列幅の変化
repeat関数の挙動
既にrepeat関数を使ったコードを紹介しましたが、repet関数をpxと組み合わせることで、画面の幅が変わった時に、列や行の幅や長さがそのままとなるものと、画面の幅に合わせて変化するものを作成することができます。
一般的なrepeat関数の使い方は単に、繰り返す関数と値を指定するだけです。
repeat(繰り返す回数, 値)
repeatを使わない表記とは以下のように読み替えることができます。
repeat(4, 1fr)
↓↑ 同じ
1fr 1fr 1fr 1fr
画面幅に追従するグリッド
repat関数と「fr」を使うと画面幅に合わせて追従するグリッドを作成することができます。
.grid-wrapper{
display: grid;
gap: 20px;
grid-template-columns: repeat(4, 1fr);
}
div > div{
width: 40px
}
ブラウザの表示は以下のようになります。

開発ツールで確認すると以下のようになります。

「fr」は画面幅(コンテナの幅)に合わせて各行や列を分割して割り当てるものなので、画面幅が変われば、その各要素が入るマスの幅も変わります。
画面幅を狭めると以下のようになります。

開発ツールで確認すると、各マスの中の余白が少なくなっていることがわかります。

画面幅によって変化しないグリッドとの共存
このrepat関数と「fr」を使った指定と、「px」を使った指定を組み合わせると、画面幅に合わせて追従するグリッドと追従しないグリッドを合わせて作成することができます。
例えば、一番左端の列の幅は固定して、残りの要素は画面の幅に合わせて変化させるというものです。
実例として、4列のグリッドで、一番左端の列を150pxで固定し、残りの列を画面幅に合わせて変化させる場合は以下のようになります。
.grid-wrapper{
display: grid;
gap: 20px;
grid-template-columns: 150px repeat(3, 1fr);
}
ブラウザの表示は以下のようになります。

画面幅を狭めていくと以下のようになります。

左端の列の幅は固定されたままで、残りの列の幅のみが変化していることがわかります。
参考リンク
グリッドシステム自体の概念や使い方については下記をご参考ください。
【CSS】グリッドシステム(grid system, display: grid;)とは何か?要素の長さや位置の調整方法を実例で解説
グリッドシステム(display: grid)のコンテナ内の要素の上下方向や水平方向の位置を調整する細かい方法については下記をご参考ください。