CSSの比較関数が便利すぎる! min(), max(), clamp()の使い方を詳しく解説
Post on:2022年5月28日
CSSの数学関数と言えば、calc()が便利ですよね。
しかし、便利な数学関数はcalc()だけではありません!
先月、Firefoxにサポートされたことにより、すべてのモダンブラウザにサポートされたCSSの比較関数「min()」「max()」「clamp()」の使い方を紹介します。
最大幅や最小幅を計算式で定義できる「min()」「max()」、フォントサイズの最小値と最大値をコの字のクランプのように計算式で定義できる「clamp()」、
これからのWebページやスマホアプリの実装にかなり役立つと思います。
Everything I Learned About min(), max(), clamp() In CSS
by Ahmad Shadeed
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- はじめに
- CSSの比較関数のサポートブラウザ
- CSSの比較関数
- min()関数とは
- max()関数とは
- clamp()関数とは
- clamp()関数の計算方法
- コンテキストが重要
- min(), max(), clamp()では数式が使用できる
- CSSの比較関数でデザイン方法がどのように変わるか
- CSSの比較関数の使用例
- CSSの比較関数は単位のない値で壊れる
- サポートされていないブラウザのフォールバック
- アクセシビリティにおける注意点
はじめに
CSSの比較関数(min(), max(), clamp())が、2020年4月にFirefox 75でもサポートされ、すべての主要ブラウザでサポートされました。
これらのCSSの比較関数を使用することで、動的なレイアウトやより柔軟なコンポーネントを実装できるようになり、コンテナのサイズ、フォントのサイズ、スペースなどに利用できます。CSSの比較関数により、Web制作者は今までとは違った考え方をする必要があるかもしれません。
この記事はCSSの比較関数について、機能を明確にし、混乱する可能性のあるポイントを解説し、実用的な使用例を提供したいと思います。
CSSの比較関数のサポートブラウザ
CSSの比較関数min(), max(), clamp()は、すべての主要ブラウザにサポートされています。
min(), max(), clamp()のサポートブラウザ
サポートされていないブラウザへの対応方法は、サポートされていないブラウザのフォールバックをご覧ください。
CSSの比較関数
CSSの仕様によると、min(), max(), clamp()は複数の値を比較し、使用された関数に基づいてそれらの1つを表します。それぞれの機能を見てましょう。
min()関数とは
min()関数には、1つ以上のコンマ区切りの計算が含まれ、それらの最小値を表します。つまり、最大値を設定するにはmin()を使用します。
実際に見てましょう。
要素の最大幅を500pxにしたい場合は、下記のように記述します。
1 2 3 |
.element { width: min(50%, 500px); } |
この記述で、要素は必ず500px以下になります。
要素の最大幅を500pxに
min()関数を使用すると、ブラウザは値(50%, 500px)の中で最も小さい値を選択する必要があります。どちらを選択するかはこの場合は%単位を使用しているため、ビューポートの幅に依存します。50%の値が500pxよりも大きい場合は無視され、代わりに500pxが使用されます。
そうでない場合、つまり50%の値が500px未満の場合は、50%が幅の値として使用されます。そうなる場合のビューポートの幅を計算できますか?
Xの50%イコール500pxなので、ビューポートの幅は1,000pxです。
ビューポートの幅を1,000px未満に
min()関数のこの基本をしっかり理解することを願っています。私はこれを理解するのに、さんざん頭を掻きました。
min()関数がどのように機能するかインタラクティブなデモを作成したので、ビューポートのサイズを変更して試してみてください。
max()関数とは
max()関数には、1つ以上のコンマ区切りの計算が含まれ、それらの最大値を表します。つまり、最小値を設定するにはmax()を使用します。
実際に見てましょう。
要素の最小幅を500pxにしたい場合は、下記のように記述します。
1 2 3 |
.element { width: max(50%, 500px); } |
この記述で、要素は必ず500px以上になります。
要素の最小幅を500pxに
max()関数を使用すると、ブラウザは値(50%, 500px)の中で最も大きい値を選択する必要があります。どちらを選択するかは、ビューポートの幅に依存します。50%の値が500px未満の場合は無視され、代わりに500pxが使用されます。
そうでない場合、50%の値が500pxを超える値の場合は、50%が幅の値として使用されます。
min()関数の反対ですね。
clamp()関数とは
clamp()関数は、2つの定義された値(最小値と最大値)の間をクランプすることです。3つのパラメーター(最小値、推奨値、最大値)を使用します。
実際に見てましょう。
1 2 3 |
.element { width: clamp(200px, 50%, 1000px); } |
最小幅が200px、推奨幅が50%、最大幅が1000pxに定義された要素があります。これを可視化してみましょう。
clamp()関数を適用した要素
文字で説明します。
- 幅は200pxを下回ることはありません。
- 中央の値(推奨値)は50%で、ビューポートの幅が400px以上2000px未満の場合のみ機能します。
- 幅は1000pxを超えません。
clamp()関数は、実際のクランプに似ています。両端にある2つの値(最小と最大)に基づいてクランプします。
clamp()関数の計算方法
MDNによると、clamp()を値として使用する場合は、同時にmax()とmin()関数を使用するのと同等です。
下記の例で確認してみましょう。
1 2 3 4 5 |
.element { width: clamp(200px, 50%, 1000px); /* 以下と同等です */ width: max(200px, min(50%, 1000px)); } |
値50%はブラウザのビューポート幅に依存するので、ビューポート幅を1150pxであると仮定してみましょう。
1 2 3 4 5 6 7 8 9 |
.element { width: max(200px, min(50%, 1000px)); /* ビューポートの幅が1150pxであると仮定 */ width: max(200px, min(575px, 1000px)); /* つまり */ width: max(200px, 575px); /* つまり */ width: 575px; } |
コンテキストが重要
計算される値は、コンテキストに依存します。それは、%, em, rem, vw/vhのいずれかです。パーセンテージ値も、要素が直接<body>にある場合はビューポートの幅に基づくか、親に基づくかのどちらかになります。
min(), max(), clamp()では数式が使用できる
min(), max(), clamp()で特筆すべき点は数学の計算が可能なので、calc()を使用する必要がないということです。
仕様によると、
各引数には数式を使用することができ、calc()を使用する必要はありません。複数の制約を適用したい場合は、2つ以上の引数を指定することもできます。
1 2 3 4 |
.type { /* フォントサイズを12pxから100pxの間に定義する */ font-size: clamp(12px, 10 * (1vw + 1vh) / 2, 100px); } |
CSSの比較関数でデザイン方法がどのように変わるか
Webページをデザインする際に、デザイナーはスマホとデスクトップのサイズで作業する場合がよくありますが、プロジェクトによってはそれら以上のサイズが必要になる場合があります。
CSSの比較機能を使用すると、どのように影響するでしょうか?
上: 今まで、下: これからのデザイン方法
図上は現在のデザイン方法で、デザインサイズやビューポートに明確なスポットがあります。しかし、図下はデザインのプロパティに最小値と最大値を使用した漸進的なものです。将来的にはこのようなアプローチをするのではないかと、私は想像しています。
フォントのサイズも最小値と最大値を決める
ワクワクしませんか?
少なくとも、私はワクワクしています!
コンポーネントにある程度の柔軟性が必要なWebプロジェクトに取り組めることにとても興奮しています。もちろん、すべてのコンポーネントが動的である必要はありませんが、いくつかのコンポーネントは動的である可能性があります。
CSSの比較関数の使用例
サイドバーの幅
通常、ページのサイドバーは固定幅で、メインの幅はフレキシブルに実装されます。サイドバーの実装を強化して、ビューポートが大きい場合にサイドバーをより大きくすることができます。そのためには、max()関数で最小幅を定義して実装します。
1 2 3 4 5 6 7 8 9 10 11 |
.wrapper { display: flex; } aside { flex-basis: max(30vw, 150px); } main { flex-grow: 1; } |
asideの最小幅を150pxに定義し、ビューポートの幅が500px(500*30% = 150)を超えると30vwになります。
見出しのフォントサイズ
clamp()の優れた使用例は、フォントサイズです。最小サイズを16pxに、最大サイズを50pxにした見出しが必要だとします。clamp()関数は、最小値と最大値を超えることなく中間値を提供します。
1 2 3 |
.title { font-size: clamp(16px, 5vw, 50px); } |
このようにclamp()を使用すれば、見出しのフォントサイズはアクセシブルで読みやすさが保証されるため、完璧です。もしmin()で実装してしまうと、ビューポートが小さい場合にサイズを制御できません。
1 2 3 |
.title { font-size: min(3vw, 24px); /* 非推奨、アクセシビリティに悪い */ } |
参考までに、min()を使用すると下記のようになります。
スマホのビューポートでは、フォントサイズが小さすぎます。そのため、フォントのサイズにはmin()関数を使用しないようにしましょう。もちろん、メディアクエリでキャンセルしたり、追加したりもできますが、そうなるとCSSの比較関数を使用する意味がありません。
前述したように、max()関数の中にmin()を入れ子にできます。clamp()関数を模倣したような感じです。
1 2 3 |
.title { font-size: max(16px, min(10vw, 50px)); } |
【アップデート】
Twitterで、font-sizeの優先値として10vwだけを使用するのはよくないことが分かりました。ユーザーがブラウザでズームした時に、アクセシビリティの問題が発生します。
上記のCSSに、(1rem + 5vw)を加えるとこの問題は解決します。
1 2 3 |
.title { font-size: clamp(16px, (1rem + 5vw), 50px); } |
装飾的な見出し
セクションタイトルの下に透明な大きなテキストが見えますか? これは装飾的なテキストで、ビューポートのサイズに応じて拡大縮小される必要があります。max()関数でビューポートの単位を使用して、最小値を設定できます。
1 2 3 4 |
.section-title:before { content: attr(data-test); font-size: max(13vw, 50px); } |
グラデーションをより美しく実装する
CSSでグラデーションを実装する場合、カラーの遷移をより滑らかにすることで、より美しく実装できます。
1 2 3 |
.element { background: linear-gradient(135deg, #2c3e50, #2c3e50 60%, #3498db); } |
スマホでのグラデーション(下)で、カラーを区切る線があることに注目してください。これはメディアクエリで修正できます。
1 2 3 4 5 |
@media (max-width: 700px) { .element { background: linear-gradient(135deg, #2c3e50, #2c3e50 25%, #3498db) } } |
メディアクエリだけでも機能しますが、min()関数を使用することでより動的にすることができます。
1 2 3 |
.element { background: linear-gradient(135deg, #2c3e50, #2c3e50 min(20vw, 60%), #3498db); } |
透明なグラデーション
写真の上にテキストを配置する場合、テキストを読みやすくするために、その下にグラデーションを加える必要があります。上記と同様に、グラデーションのサイズは小さいビューポートと大きいビューポートで異なる必要があります。
1 2 3 |
.element { background: linear-gradient(to top, #000 0, transparent max(20%, 20vw)); } |
このちょっとした工夫で、スマホでもグラデーションがより美しく見せることができます。デスクトップでグラデーションのサイズが親の50%であれば、スマホでは30%程度になるはずです。max()関数を使用することで、最小値を設定できます。
動的なマージン
CSSのビューポートの単位を使用することで、要素間に動的なマージンを持たせることができます。ただし、ユーザーは縦長のスクリーンでデザインを見ることが前提のため、必ずしも良い解決策ではないかもしれません。
1 2 3 4 5 6 7 8 9 |
h1, h2, h3, h4, h5 { margin: 7vh 0 1.05rem; } @media (max-height: 2000px) { h1, h2, h3, h4, h5 { margin: 2.75rem 0 1.05rem; } } |
上記でうまくいきますが、1行だけでも同じことができます!
1 2 3 |
h1, h2, h3, h4, h5 { margin: min(7vh, 2.75rem) 0 1.05rem; } |
min()を使用することで、マージンが2.75remを超えないように最大値を定義します。シンプルで簡単ですね!
コンテナの幅
親の幅の80%を占めるコンテナがあり、その幅は780pxを超えてはいけない場合、どのように実装しますか?
通常は、下記のようになります。
1 2 3 4 |
.container { max-width: 780px; width: 80%; } |
min()関数を使用すると、最大値が780pxを下記のように記述できます。
1 2 3 |
.container { max-width: min(80%, 780px); } |
セクションにおける垂直のパディング
clamp()で私が気に入っているのは、セクションのパディングで最小値と最大値を簡単に実装できることです。
ヒーローセクションを例に見てましょう。
このパディングはたった1行のCSSで実装できます。
1 2 3 |
.hero { padding: clamp(2rem, 10vmax, 10rem) 1rem; } |
ボーダーとシャドウ
デザインによっては、スマホでボーダーの幅や半径を小さくしたい場合があります。clamp()を使用することで、ビューポートの幅に合わせて動的な要素にすることができます。
1 2 3 4 5 6 |
.element { box-shadow: 0 3px 10px 0 red; border: min(1vw, 10px) solid #468eef; border-radius: clamp(7px, 2vw, 20px); box-shadow: 0 3px clamp(5px, 4vw, 50px) 0 rgba(0, 0, 0, 0.2); } |
グリッドのギャップ
素敵な使用例としては、CSS Gridのgrid-gapです。スマホでグリッドのギャップを小さくしたい時は、clamp()を使用すれば簡単に実装できます。
1 2 3 4 5 |
.wrapper { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); grid-gap: clamp(1rem, 2vw, 24px); } |
グリッドでの比較関数をさらに詳しく勉強したい場合は、Dannie Vintherの記事をご覧ください。
CSSの比較関数は単位のない値で壊れる
いろいろ試していたところ、clamp()の最小値に0を定義したいと思いました。
1 2 3 |
.element { width: clamp(0, 10vmax, 10rem); } |
このCSSは無効です。単位のない数値を使用せず、必ず単位をつけてください。
サポートされていないブラウザのフォールバック
新しいCSSの機能と同様に、フォールバックを提供することが重要です。
1. フォールバックを手動で追加
CSSの比較関数の前にプロパティを追加して、フォールバックを提供します。
1 2 3 4 |
.hero { padding: 4rem 1rem; padding: clamp(2rem, 10vmax, 10rem) 1rem; } |
サポートしているブラウザは最初のパディングを次のパディングで上書きします。サポートしていないブラウザは最初のパディングを適用します。
2. @supportsを使用する
CSSの比較関数がサポートされているかどうか検出するために、@suppotsクエリを使用することができます。比較関数をサポートしているブラウザであれば、@supportsをサポートしているはずなので、こちらの方法を推奨します。
1 2 3 4 5 6 7 8 9 10 11 |
.hero { /* 最初は、サポートされていないブラウザ用 */ padding: 4rem 1rem; } @supports (width: min(10px, 5vw)) { /* 比較関数がサポートされているブラウザ用 */ .hero { padding: clamp(2rem, 10vmax, 10rem) 1rem; } } |
アクセシビリティにおける注意点
CSSの比較関数はより動的なWebページを作成する新しい方法を提供してくれますが、その使用方法については注意が必要です。例えば、min()でfont-sizeを定義するのはスマホで小さすぎるので十分ではありません。ユーザーエクスペリエンスに不可欠な最小値と最大値を設定すべきです。
以上です。コメントや提案があれば、@shadeed9までお願いします。
sponsors