CSSのプロパティにmin()
・max()
・clamp()
という値があるのをご存知ですか?
これらのプロパティを使うと、メディアクエリ対応のために何行も書いていたコードが、たった1行に短縮できます!
当記事では、min()・max()・clamp()の概要や、min()・max()・clamp()の便利な使い方について解説します。
IEのサポートが終わったことで、モダンなCSSの情報収集している方は必見です!ぜひ最後までお読みください。
min()・max()・clamp()とは?
min()・max()・clamp()は、プロパティに設定する値を数式で計算するCSSの数学関数です。
これらの関数を使うことで、メディアクエリを使わず、コンテンツベースなレスポンシブレイアウトを実現できます。
例えば、gridを使わない場合のリキッドレイアウトの幅指定に便利なcalc()も、CSSの数学関数のひとつです。
こちらの記事ではcalc()を使った実装例を紹介しています。
min()・max()・clamp()のブラウザ対応状況
現在はほとんどのモダンブラウザにサポートされています。すでにIEのサポートは終了していますので、どんどん使っていきたいですね!
min()とは
min()は二つの値を設定し、どちらか小さい方の値を値を表示します(=最大値が設定される)。
大きさの最大値を定義する時、今までだとmax-widthとwidthを組み合わせていたかと思います。
/* いままでの書き方 */
.box {
width: 50vw;
max-width: 600px;
}
しかし、min()なら同じ内容を1行で書くことができます。
.box {
width: min(50vw, 600px);
}
カンマ区切りで1つ以上の値が設定でき、その中で最小の値が適用されます。
例1:viewportの長さ(100vw)が2000pxの場合
viewportの長さ(100vw)が2000pxのとき、50vwの長さは1000pxです。
つまり、(1000px , 600px)
で比較されるため、600pxが適用します。
例2:viewportの長さ(100vw)が800pxの場合
viewportの長さ(100vw)が800pxのとき、50vwの長さは400pxです。
つまり、(400px , 600px)
で比較されるため、400px(=50vw)のほうが適用します。
max()とは
max()は二つの値を設定し、どちらか大きい方の値を値を表示します(=最小値が設定される)。
大きさの最小値を定義する時、今までだとmix-widthとwidthを組み合わせていたかと思います。
/* いままでの書き方 */
.box {
width: 50vw;
min-width: 400px;
}
しかし、max()を使うと1行で実現できます。
.box {
width: max(50vw, 400px);
}
カンマ区切りで1つ以上の値が設定でき、その中で最大の値が適用されます。
例1:viewportの長さ(100vw)が1200pxの場合
viewportの長さ(100vw)が1200pxのとき、50vwの長さは600pxです。
つまり、(600px , 400px)
で比較されるため、600pxが適用します。
例2:viewportの長さ(100vw)が700pxの場合
viewportの長さ(100vw)が700pxのとき、50vwの長さは350pxです。
つまり、(350px , 400px)
で比較されるため、400pxが適用します。
clamp()とは
clamp() は、 min() と max() をあわせたような働きをします。
.box {
width: clamp(最小値, 推奨値, 最大値);
}
カンマ区切りで(最小値 , 推奨値 , 最大値)の3つを指定し、その中の値から条件に合うものが適用されます。
- 最小値
- 推奨値が最小値よりも小さくなると、要素の長さは最小値が適用されます。
- 最大値
- 推奨値が最大値よりも大きくなると、要素の長さは最大値が適用されます。
- 推奨値
- 要素の長さが最小値より大きく、最大値より小さいとき、要素の長さは推奨値が適用されます。
.box {
width: clamp(400px, 50vw, 600px);
}
例1:viewportの長さ(100vw)が2000pxの場合
viewportの長さ(100vw)が2000pxのとき、推奨値である50vwの大きさは1000pxです。
つまり、(400px , 1000px , 600px)
で比較されます。
このとき、推奨値(1000px)は最大値(600px)より大きくなっているため、最大値の600pxが適用されます。
例2:viewportの長さ(100vw)が700pxの場合
viewportの長さ(100vw)が700pxのとき、推奨値である50vwの大きさは350pxです。
つまり、(400px , 350px , 600px)
で比較されます。
このとき、推奨値(350px)は最小値(400px)より小さくなっているため、最小値の400pxが適用されます。
clamp()の計算方法
以下コードの結果はどちらも同じ結果となります。
/* clamp */
.box {
width:clamp(400px, 50vw, 600px);
}
/* min()・max()をあわせて使用した書き方 */
.box {
width:min(600px, max(50vw, 400px));
}
clamp() は max() と min() をあわせて使用した場合と同じ動きをします。
min() と max() が組み合わさっていると難しく見えるかもしれませんが、ひとつひとつの動きを細かく見れば理解できるはずです。
実際に、viewportに具体的な数字を当てはめて計算してみましょう。
viewportが2000pxの場合
再度min()とmax()をおさらいしておきます。
- min()
- 最大値を定義できる。1つ以上の値を設定し、その中で最小の値が適用される
- max()
- 最小値を定義できる。1つ以上の値を設定し、その中で最大の値が適用される
ここではvewportが2000pxの場合を想定し、以下のコードを分解して解説していきます。
/* min()・max()を組み合わせた書き方 */
.box {
width:min(600px, max(50vw, 400px));
}
max(50vw, 400px)
の50vwは1000pxに置き換えられます。
/* 100vwが2000pxなので、50vwは1000px */
.box {
width:min(600px, max(1000px, 400px));
}
/* max()関数の計算結果 */
.box {
width:min(600px, 1000px);
}
max()は()内の最大値を適用するプロパティですので、1000pxと400pxを比較して、1000pxを採用します。
/* max()の計算結果をもとに、min()関数を実行 */
.box {
width:min(600px, 1000px);
}
/* min()関数の計算結果 */
.box {
width:600px;
}
min()は()内の最小値を適用するプロパティですので、1000pxと600pxを比較し、600pxを採用します。
以上のことから、viewportが2000pxの場合の長さは600pxと計算できます。
clamp関数が効かないときのチェックポイント
推奨値は固定値NG
clamp()が最小値と最大値の間の値を流動的に処理してくれるので、推奨値には固定値ではなく相対値(vw や %)を使用しましょう。
各種単位についての使い方やポイントは、こちらの記事で詳しく解説しています。あわせてチェックしてみてください!
Safariで効かないことがある
clamp()はSafariにもサポートされていますが、うまく計算してくれない事があるようです。
そんなときは以下のCSSを指定することで解決します。
/* Safariで効かないとき */
* {
min-height: 0vw;
}
Sassでコンパイルエラーになる
Sassでmin()・max()・clamp()を使いコンパイルすると、以下のエラーが起きます。
Compilation Error
Internal Error: Incompatible units: 'vw' and 'px'.
この原因は、コンパイル時点で 1vw の値が確定していないため、固定値として出力できないからです。
このような場合、unquote()を使うと解決します。
unquote()は引用符を取り除いてくれるプロパティで、計算式をそのまま出力したいときに使えます。
//文字列としてそのまま出力させる
.box {
width: unquote('min(50vw, 600px)');
}
/* 出力結果 */
.box {
width: min(50vw, 600px);
}
()内でcalc関数のような数式指定
min()・max()・clamp()は、設定値に加算+
減算-
乗算*
除算/
の各演算子が使えます。
/* スペースを忘れずに! */
.box {
width:max(100vw - 50vw, 400px);
}
演算子の両側には、必ず半角スペースが必要です。忘れずに入力しましょう。
各関数の使用例を紹介
モジュールの幅(width)
<div class="container">
<div class="item"></div>
</div>
.container {
max-width: min(85%, 800px);
}
上の例では.containerの幅が最大800pxとなるようにし、それ以下はブラウザ幅(body)に対して85%で表示させる指定になります。
ヘッダーナビゲーション間の余白(padding)
padding に max() を使うと、動的に余白の指定ができます。例ではheader の padding に max() を使用した例をご紹介しています。
.header {
padding: max(12px, 2vw);
}
max()を指定したことで、動的な余白を設定しつつ、12pxは下回ることがないよう指定ができました。
動的に変化するテキスト(font-size)
clamp() を使うことでfont-sizeを可変させることも可能です。計算がしやすいよう、以下の基準でviewportの値を指定します。
- モバイル=400px
- タブレット=800px
- PC=1200px
.text {
font-size:clamp(20px, 4vw, 40px) ;
}
- viewport 400pxの場合 ( 4vw = 16px )
- 4vwが最小値(20px)を下回っているので、このときのフォントサイズは20pxが適用されます。
- viewport 800pxの場合 ( 4vw = 32px )
- 4vwは最小値(20px)と最大値(40px)の間にあるため、このときのフォントサイズは32pxが適用されます。
- viewport 1200pxの場合 ( 4vw = 48px )
- 4vwが最大値(40px)を上回っているので、このときのフォントサイズは40pxが適用されます。
まとめ
今回はmin()
・max()
・clamp()
の使い方を解説しました。
レスポンシブコーディングも、メディアクエリのみでCSSを書いてしまうとブレイクポイントが多発し、コードの見通しが悪くなってしまいます。
デバイスサイズを考慮しないモダンなCSSをマスターし、可能な限りメディアクエリに頼らないアプローチを身につけていけるとコーディングの幅が広がります。
この機会にぜひ導入検討してみてください!