💨
レスポンシブに最適なclamp()関数をもっと使いやすくするSass関数について
はじめに
レスポンシブデザインにおいて、要素のサイズを画面幅に応じて可変させる手法としてclamp()
関数は使ってますか?
使いこなせれば、レスポンシブが楽になりますがそのままですと少々使いづらい点があります。
MDNを見ると例としてはこんな形で紹介されています。
font-size: clamp(1.8rem, 2.5vw, 2.8rem);
要約すると
これは:
- 最小値: 1.8rem (≒ 28.8px @ 16px base)
- 可変値: 2.5vw (ビューポート幅の2.5%)
- 最大値: 2.8rem (≒ 44.8px @ 16px base)
となっており:
- 画面幅が狭い時は 1.8rem (28.8px) 以下にはならない
- 画面幅が広い時は 2.8rem (44.8px) 以上にはならない
- その間は画面幅の2.5%で可変する
こういう形になりますが、全然直感的ではなくどうやって使えばいいの?となります。
既存ツールの課題
ちなみに、こういうサイトがあり、
1200px幅〜320px幅の中でMaxが24px Minが16pxで可変していく形になります。
- 毎回こちらに入力するのが手間
- clamp(1rem, 0.818rem + 0.91vw, 1.5rem)が後から見たときにわかりにくい
解決策:直感的に書けるSass関数
これらの課題を解決するため、以下のような関数を作成しました:
@use "sass:math";
// pxで指定された値をremに変換する関数
@function to-rem($value, $base: 16) {
@return math.div($value, $base * 1px) * 1rem;
}
//数値の小数点以下を指定した桁数(デフォルトは3桁)までに丸める。
@function round-to-precision($value, $precision: 3) {
$factor: math.pow(10, $precision);
@return math.div(math.round($value * $factor), $factor);
}
//「画面幅が小さいときは $minValuePx、大きいときは $maxValuePx へ流動的に変化」する clamp() の式を自動生成する。
@function responsive-clamp(
$minValuePx,
$maxValuePx,
$minViewportPx,
$maxViewportPx
) {
$minValueRem: to-rem($minValuePx);
$maxValueRem: to-rem($maxValuePx);
$variablePart: math.div(
($maxValuePx - $minValuePx),
($maxViewportPx - $minViewportPx)
) * 1px;
// 小数点以下第三位までにする
$variablePart: round-to-precision($variablePart, 3);
$constant: to-rem(
$maxValuePx - ($maxViewportPx * math.div($variablePart, 1px))
);
// 小数点以下第三位までにする
$constant: round-to-precision($constant, 3);
@return clamp(
$minValueRem,
#{$constant} + #{100 * math.div($variablePart, 1px)}vw,
$maxValueRem
);
}
SCSSでの使い方としてはこちらになります。
1440px幅で24px そこから375pxにかけて16pxになります。
font-size: responsive-clamp(16px, 24px, 375px, 1440px);
- 1440px幅のとき:24px
- 375px幅のとき:16px
その間:自然に可変
この関数のメリット
- デザインカンプの制作幅(375pxや1440px)をそのまま参照できる
- pxで指定された要素サイズの値をそのまま使える
- レスポンシブ対応は「レイアウト変更」に集中できる
- 個々の要素サイズの可変は関数に任せられる
- ブレイクポイントでのレイアウト調整に注力できる
- コードの意図が後から見ても分かりやすい
この関数をより効率よく使う方法
- お使いのエディタでスニペットとして登録すると更に便利
- よく使う画面幅は変数化しておくのもおすすめ
私はスニペットとして登録して使用しています。
Discussion