レスポンシブでフォントサイズや要素のサイズを変える時に、毎回メディアクエリで、画面幅毎にこんな指定をしていませんか?
@media screen and (max-width:768px) {
.title {
font-size: 14px;
}
@media screen and (min-width:768px) and (max-width:1024px) {
.title {
font-size: 24px;
}
@media screen and (min-width:1024px) {
.title {
font-size: 32px;
}
実は、今回紹介するclamp()を使用すれば、こんな煩わしい指定を毎回しなくても、一行で実装できます!
.title {
font-size: clamp(0.875rem, -2.5rem + 7.03vw, 2rem);
}
この記事ではclamp()を実際に利用する際に必須となるジェネレーターの使い方や、scss関数の組み方も解説するので、
是非この記事を通してclamp()を今日から利用していってもらえればと思います。
Sassを使わない人はジェネレーターを使って、Sassを使う人は関数でラクラクclamp()でレスポンシブを管理できるようになります。
この記事を書いたのは
しょーご(@samurabrass)
当ブログ「しょーごログ」の運営者。2018年からWeb制作・フロントエンドエンジニアとして主にWordPressでのサイト制作やシステム開発のフロントエンドを担当。同時にブログとYouTubeで情報発信を行っている。駆け出しエンジニアのコーディング課題添削も行い、スクール講師を4年以上している経験を活かした分かりやすい記事制作を心がけている。
\現役エンジニアのレビュー付き/
実践レベルのコーディング課題公開中
- デザインカンプからのコーディングを経験したい
- 現役エンジニアのレビューを受けてみたい
- 即戦力級のポートフォリオを用意したい
2024年にデザインを完全リニューアルしています!
コーディングに自身をつけるにはプロからのレビューを貰うのが必須なため、制作会社も利用するレビューツールで添削をしています。
Web制作学習ロードマップにも取り入れているため、学習終了まで迷わず進むことが可能です。コーディングを本気で仕事したい方はぜひご活用ください!
\無料の入門編から本格企業サイトまで/
clamp()の対応ブラウザ
一応caniuseで確認した所、モダンブラウザでは問題なく使えます。IEを切っている現場が多いと思うので、ほぼ前線に出しても問題無い関数と言えます。
clamp()とは
clamp()はCSSの関数で、最小値、推奨値、最大値の3つの引数を取ります。
clamp(最小値, 推奨値, 最大値)
最小値 | 要素が取ることができる最小の値を示します。通常、画面が非常に小さい場合や、コンテンツが非常に狭い場合にこの値が適用されます。 |
推奨値 | 常の状況で要素が持つべき推奨される値です。通常、この値が画面サイズやコンテンツの幅に応じて柔軟に変化します |
最大値 | 要素が取ることができる最大の値を示します。通常、画面が非常に大きい場合や、コンテンツが非常に広い場合にこの値が適用されます。 |
この説明で理解できる人はほぼいないでしょう。
例えば、
.container {
width: clamp(300px, 50vw,1000px);
}
という記述だと、基本的にwidthが50vwで動きつつ、300pxより小さくならなくならず、1000pxより大きくならなくなるので、
要素がスマホ時に小さすぎたり、PC幅以上の大画面時に大きすぎる状態を防ぐことができます。
具体的な動作を見てみましょう。
これまでのレスポンシブ対応では、テキストサイズは以下のように、メディアクエリを使用してPC、タブレット、SPで段階的に切り替えている人が多かったかもしれません。
もしかしたら、vwでレスポンシブ対応している人もいるかもしれませんが、その場合に大画面時に要素が巨大化して違和感が発生しているケースがあります。
要は、「PC幅〜のときはPCの固定サイズ、タブレット付近はよしなにフレキシブルに変化して、SPのときはSPデザインの固定サイズ」にしたいのですよね。
それ、clamp()を使えば簡単にできます。例えば以下は滑らかにフォントサイズが変わっているのが分かると思います。
ここで使用したコードは以下ですが、
font-size: clamp(3rem, 1rem + 6.67vw, 6rem);
これをメディアクエリを使って書くと、結構めんどくさいです。
@media screen and (max-width: 768px) {
/* 768px以下の場合 */
font-size: 3rem;
}
@media screen and (min-width: 768px) and (max-width: 1440px) {
/* 768px以上1440px以下の場合 */
font-size: calc(1rem + 6.67vw);
}
@media screen and (min-width: 1440px) {
/* 1440px以上の場合 */
font-size: 6rem;
}
1rem + 6.67vwという数値は、768px~1440pxの範囲でいい感じにレスポンシブすることを示していますが、この数式は自動で出せるので詳しくは後述します。
もう一つ例を見てみましょう。
こちらはコンテナのwidthと中の見出しのfont-sizeに対してclamp()を使用した例です。
まずコンテナのwidthはこうなっています。
width: clamp(320px, 0.682rem + 82.42vw, 1000px);
これをメディアクエリを使うと、
@media screen and (max-width: 768px) {
/* 768px以下の場合 */
width: 320px;
}
@media screen and (min-width: 768px) and (max-width: 1440px) {
/* 768px以上1440px以下の場合 */
width: calc(0.682rem + 82.42vw);
}
@media screen and (min-width: 1440px) {
/* 1440px以上の場合 */
width: 1000px;
}
font-sizeに関しては以下になっています。
font-size: clamp(1.5rem, 0.364rem + 4.85vw, 4rem);
これをメディアクエリを使うと、
@media screen and (max-width: 768px) {
/* 768px以下の場合 */
font-size: 1.5rem;
}
@media screen and (min-width: 768px) and (max-width: 1440px) {
/* 768px以上1440px以下の場合 */
font-size: calc(0.364rem + 4.85vw);
}
@media screen and (min-width: 1440px) {
/* 1440px以上の場合 */
font-size: 4rem;
}
ただここで疑問が出てきます。
clamp(1.5rem, 0.364rem + 4.85vw, 4rem)
真ん中の推奨値である、0.364rem + 4.85vwはどうやって出せばいいのでしょうか?
clamp()の推奨値ってどうやって計算するの?
でも、タブレット付近をよしなにしてくれる真ん中のremとvwが+されてるところとか、どうやって計算すればいいの?
なんかめんどくさそう。。。
これには2つの方法があります。
- ジェネレーターを使う(初心者におすすめ)
- scss関数を組む(Sassに自信ニキにおすすめ)
順番に解説します。
clamp()の利用方法❶ジェネレーターを使う
お試しでとりあえずclamp()を使う程度なら、脳死で「Min-Max-Value Interpolation」を利用して、推奨値を算出すればいいかと思います。
例えばフォントサイズで、
PCデザイン1200pxのときは64px
SPデザイン375pxのときは24px
その間375px~1200pxはよしなに動いて欲しい
こんなときは、この画像のように入力すればOKです。
単位がremになっていますが、どうしてもpxを使いたい人は、remの数値を16倍してpxにしてもいいと思います。
今回の本題とずれますが、
remじゃないとダメなのかな?
と思われる方がいるかもなので、補足です。
基本的にアクセシビリティなどの観点からremを使ったほうが良い場合が多く、sassの関数で簡単にpx→remに変換できるので、
まだremに慣れていない人はこのタイミングで導入するといいかなと思います。
// 基準となるフォントサイズを設定
$baseFontSize: 16px;
// pxをremに変換する関数
@function rem($pxValue) {
@return ($pxValue / $baseFontSize) * 1rem;
}
// 使用例
.box h1 {
font-size: rem(24px); // 24pxを16px基準のremに変換
}
もしclamp()を使うまでも無い場面では、この関数を使えばいいと思います。
clamp()の利用方法❷sassの関数を使う
毎回ジェネレーター使うの煩わしいですね。。。
こう思ったなら、Sassで関数を組めばよいでしょう。
以下がclamp()を生成する関数です。
@function rclamp($min, $max, $minViewport, $maxViewport) {
$vwScale: ($max - $min) / ($maxViewport - $minViewport); // vw単位でのスケールを計算
$baseOffset: $min - $minViewport * $vwScale; // 基準となる最小値からのオフセットを計算
$minRem: $min / 16; // 最小値をremに変換
$maxRem: $max / 16; // 最大値をremに変換
$baseOffsetRem: $baseOffset / 16; // オフセットをremに変換
$vwScaleRem: $vwScale * 100; // vwスケールを調整
@return clamp(#{$minRem}rem, #{$baseOffsetRem}rem + #{$vwScaleRem}vw, #{$maxRem}rem);
}
// 使用例
.example {
font-size: rclamp(24, 64, 375, 1200);
}
実際に使う際には、
rclamp(最小値, 最大値, 最小viewport,最大viewport)
を入力することで、コンパイル後のCSSでclamp()が生成されます。
関数定義の下に使用例を載せていますが、この使用例だと、以下の画像と同じ値が出力されます。
補足:自作関数の詳細説明
この関数の詳細な動きを知りたい人向けに、一応噛み砕いて説明しておきます。
とはいえかなり難しいので、理解できなければとりあえず飛ばして関数だけ利用しておけばOKです。
関数定義
@function rclamp($min, $max, $minViewport, $maxViewport) {
rclamp
関数は、4つのパラメータを受け取ります。$min
と$max
は、フォントサイズの最小値と最大値(ピクセル単位で指定)。$minViewport
と$maxViewport
は、このフォントサイズ調整を適用するビューポートの最小幅と最大幅(ピクセル単位)。
計算
$vwScale: ($max - $min) / ($maxViewport - $minViewport); // vw単位でのスケールを計算
$baseOffset: $min - $minViewport * $vwScale; // 基準となる最小値からのオフセットを計算
$vwScale
は、ビューポートが$minViewport
から$maxViewport
に変化する間に、フォントサイズがどれだけ変わるかの比率を計算します。$baseOffset
は、最小ビューポート幅でフォントサイズが$min
になるように調整するためのオフセットを計算します。
単位変換
$minRem: $min / 16; // 最小値をremに変換
$maxRem: $max / 16; // 最大値をremに変換
$baseOffsetRem: $baseOffset / 16; // オフセットをremに変換
$vwScaleRem: $vwScale * 100; // vwスケールを調整
- ここで、フォントサイズとオフセットの単位をピクセルから
rem
に変換しています。通常、1remはブラウザの基本フォントサイズ(多くの場合16px)に相当します。これにより、スタイルの設定がより柔軟になります。 $vwScaleRem
は、vw
スケールを100倍にして、vw単位がビューポート幅の百分率を反映するように調整しています。
clamp() 関数のリターン部分
@return clamp(#{$minRem}rem, #{$baseOffsetRem}rem + #{$vwScaleRem}vw, #{$maxRem}rem);
- ここでは計算された値を使用してCSSの
clamp()
を構築し、フォントサイズがビューポートの幅に応じて柔軟に調整されるようにします。 clamp()
の第一引数は最小値、第三引数は最大値、第二引数はビューポート幅に応じて変化する中間の値です。
使用例(ここが理解できればOK)
ここまで関数を指定したので、その使用例です。
この関数の使い方だけ覚えて貰えれば今回は特に問題ありません。
.example {
font-size: rclamp(24, 64, 375, 1200);
}
ここで指定された数値は、ピクセル単位での最小値、最大値、ビューポートの最小幅、最大幅です。
この値の場合、CSSにコンパイルしてみると、実際にSassで定義した独自関数の中では以下の処理が行われます。
$minRem = 24 / 16 = 1.5rem
$maxRem = 64 / 16 = 4rem
$vwScale = (64 - 24) / (1200 - 375) = 40 / 825 ≈ 0.0484848
$vwScaleRem = 0.0484848 * 100 = 4.84848vw
$baseOffset = 24 - 375 * 0.0484848 ≈ 6.18181818
$baseOffsetRem = 6.18181818 / 16 ≈ 0.38636364rem
そうしてこの関数内での計算の結果、CSSのclamp()として出力された時に、
clamp(1.5rem, 0.38636364rem + 4.8484848485vw, 4rem)
というように最小、最大値はremで、推奨値では、rem+vwの値が出力されます。
これによって、タブレット付近でいい感じに大きさが変化してくれるわけです。
Sassの関数の処理がわからなかった人は、この具体的数値を入れた処理の流れと同時に見ると分かりやすいと思います。
clamp()の実用例
では、今日学んだことの実践です。
例えばPCデザイン時に1440pxでfont-size96pxだったとして、
スマホデザインでは、375pxでfont-size48pxのときはどう設定しますか?
ジェネレーターとSass独自関数の2つの例をみていくと、
ジェネレーターを使う場合は、以下のような指定になり、
Sassの関数を使う場合は、
font-size: rclamp(48, 96, 375, 1440);
この指定にすればいいですね!
試しにCSSに出力された結果を見ると、
font-size: clamp(3rem, 1.9436619718rem + 4.5070422535vw, 6rem);
となっていて、ジェネレーター出力の数値よりも桁数が多いですが、ほぼ同じ数値になっているのが分かります。
clamp()がsafariで動かない場合
safariのバージョンによってはclamp関数が動かない場合があるので、そのときは
* {
min-height: 0vw;
}
これを加えるようにしてください。
clamp()のデメリット
タブレットデザインに柔軟に対応できない
タブレット付近はよしなに動いて貰う関数なので、もし
タブレットデザインでピクセルパーフェクトにならないんですけど!!
という場合は向きません。
しかし、私はそんな丁寧な現場に出会ったことが無いです。
強いていえば、タブレット時に柔軟に変化する仮定で他の要素とぶつかる可能性はあるので、そこは丁寧に検証する必要はあるかと思います。
まとめ clamp()の可能性は無限大!
基本的にclamp()はフォントサイズに使うことが一番多いですが、
- PCとSPデザインの数値が異なる
- PC~SPデザイン間はよしなに変化させたい
このような場合には、width、padding、marginなど幅広く使えるので、是非積極的に使ってみてください!
うまく使えれば、メディアクエリをわざわざ分けて書く機会が減ると思います。
また、clamp()を活用した関数なんかは、実はAIを使えばすぐに生成できます。
Web制作におけるChatGPTの使い方や、Cursorエディターの使い方を解説しているので、そちらも参考にしてください。
ちなみに、今回題材として動画で挙動をお見せしたのは、私が出しているデザインカンプからのコーディング練習課題の上級編になるので、
腕試しされたい方は、是非挑戦してみてください💪
またこのブログではclamp()の他にもモダンコーディングに関して記事を書いているので、こちらも是非↓
超実践編では納期厳守の模擬案件を経験し、スキル面以外にコミュニケーションも徹底レビューを受けることができます。
最近は実案件のノウハウも多いですが、「納期が短い案件の中で、丁寧なコミュニケーションを本当に実践できますか?」
この課題では、極限まで実案件に近い状況で、発注者である私とコミュニケーションを取りながら、
- 見積書提出
- 実装→初稿提出
- レビュー→修正
- 再修正→納品
- 請求書
この流れを実践していただき、最後にzoomであなたに全体レビューを行います。
- 学習はだいたい終わったけど、納期までに納品できるか不安
- 中々継続と紹介で案件が回らない
このような中級者を飛躍させる超実践編、受講には条件がありますので、詳細はリンク先よりご確認下さい。
あなたの挑戦を待っています!!
\レビューを受けて圧倒的な自信を身につける!/
ご寄付を頂けると今後の更新の励みになります!
ここではファーストビューのメインコピーだけclamp()を適用しています。