12
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

CSSAdvent Calendar 2022

Day 10

clamp関数を数学的に理解したい人のための教科書

Last updated at Posted at 2022-12-09

0.はじめに

Web制作をしているとウィンドウサイズに応じてテキストの大きさを調整したいことが頻繁にあります。そのような場面でブレイクポイントを増やさずに部分的にレスポンシブ対応できるcss関数がclamp関数です。

またリキッドデザインのマークアップにおいてフォントサイズの扱いは面倒ですが、clamp関数を用いることでウィンドウサイズに応じて流動的に可変させることが出来ます。

【レスポンシブデザインとリキッドデザイン?それぞれの特徴とメリット、デメリット!】

ここではclamp関数の有用性・使い方・scss関数化について説明し、明日から現場で使える知識として理解していただくことを目的としています。

【clamp関数のブラウザ対応状況】

目次

1. clamp関数とは
2. clamp関数の類似関数であるmin関数とmax関数
3. clamp関数の引数の値の決定方法
4. clamp関数のscss関数化
5. まとめ

1.clamp関数とは

clamp関数 は数学関数に分類されるcss関数の1つです。ここではいくつかのポイントに絞って紹介しますが、詳しいことが知りたい場合は公式ドキュメントをご参照ください。

1-1.clamp関数の引数

clamp関数は数学関数ですので当然引数が存在します。

  • MIN:最小値(絶対単位)
  • VAL:推奨値(相対単位)
  • MAX:最大値(絶対単位)

ここでは 絶対単位 はpxやrem等を想定しており、 相対単位 はvwを想定しています。

clamp関数はこれら3つの引数を持ち、clamp(MIN, VAL, MAX)の形で記述されます。

1-2.clamp関数の挙動

clamp関数は「ウィンドウサイズに対応してテキストの大きさを調整できる関数」ですが、どのようにしてその役割を果たしているのでしょうか。

clamp関数は現在のウィンドウサイズによって3つの引数から適切な値を返す関数です。つまり「現在のウィンドウサイズは〇pxだから適切な値は3つのうち、これ!」と自分で判断して値を返してくれる関数であり、メディアクエリの挙動とよく似ています。そのため3つの値を選択する条件を明確に提示してあげれば、特定のテキストに対してメディアクエリによるフォントの指定と同等かそれ以上のことが出来るようになります。

1-3.clamp関数の返り値の選択条件

clamp関数を効果的に使用するためには返り値がどういった条件で選択されているかを知る必要があります。条件は以下の通り。

  1. $MAX_{(px)} \geq VAL_{(px)}$ のとき、返り値は $MAX_{(px)}$
  2. $MAX_{(px)} < VAL_{(px)} < MIN_{(px)}$ のとき、返り値は $VAL_{(vw)}$
  3. $MIN_{(px)} \geq VAL_{(px)}$ のとき、返り値は $MIN_{(px)}$

それぞれの引数の値を以下のように表記します。

  • VALそのものの値を $VAL_{(vw)}$
  • VALを絶対単位に変換した値のことを $VAL_{(px)}$
  • MAX、MINの値をそれぞれ $MAX_{(px)}$、$MIN_{(px)}$

2.clamp関数の類似関数であるmin関数とmax関数

clamp関数と同じ数学関数にmin関数max関数があります。
これらはそれぞれmin(VAL, MIN)max(VAL, MAX)と表記し、表記の仕方からclamp関数とよく似ていることが分かります。

2-1.clamp関数とmin関数、max関数の使い分け

まず前提としてmin関数、max関数で出来ることは基本的にclamp関数でもすることが出来ます。その上で使い分けをするのであればclamp関数はMAXとMINが与えられているという条件下でVALを算出するのに対し、min関数とmax関数はVALが先に決まっているという条件下で有効に働きます。

例えば「ここは12vwで入れる」ということが決まっているテキストに対して、一定以上(もしくは以下)のウィンドウサイズではそれ以上大きく(もしくは小さく)ならないでほしい時に有効に使えます。このシチュエーションは%単位で入れているコンテンツに対してmax-width()min-width() でコンテンツの大きさに制限をかけるのと非常によく似ています。

そのためmin関数とmax関数は、テキスト版max-width() min-width() と考えて使用するとclamp関数と比べて直感的で使いやすいように思います。

3.clamp関数の引数の値の決定方法

前の章でclamp関数の有用性について以下のように述べました。

(clamp関数が)3つの値を選択する条件を明確に提示してあげれば、特定のテキストに対してメディアクエリによるフォントの指定と同等かそれ以上のことが出来るようになります

ただし、これは言い換えると引数の選択基準が曖昧であれば意図した条件下で意図した値を返すことは難しいということです。実際はMAXとMINの値さえ適切な値で設定されていればVALの値は決定基準が曖昧でもよしなになってくれます。しかしWeb制作の値の決定において、感覚もしくは主観が介入することはあまり好ましくありません。そのため明確な意図を持って値の決定が行える点においてVALの算出方法を数学的に理解しすることは価値のあることでしょう。

またVALの値の決定に感覚や主観が介入することは制作効率の悪化にも繋がります。そのためclamp関数を使用する場合は後述するscss関数化が望ましいでしょう。VALの算出方法の理解はclamp関数のscss関数を理解することの助けにも繋がります。

3-1.MAXの値の決定方法

MAXは基本的にPC系統のデザインカンプのフォントサイズをそのまま採用します。例外もありますが、基本的にPC系統のデザインカンプよりもフォントサイズを大きくしたいというシチュエーションは考えづらいためです。そのため以降はPC系統のデザインカンプのフォントサイズをMAXとして採用し、MAXを基準として他の値を決定していきます。

デザインカンプのフォントサイズを超えてほしいケースは稀である
よって $MAX_{(px)}$ = デザインカンプのフォンサイズ とする

3-2.MINの値の決定方法

MINの値はclamp関数を記述するブレイクポイント内で最もウィンドウサイズが小さい時点でのフォントサイズを採用します。例えばブレイクポイントを1440pxから768pxまでと設定したとき、clamp関数のMINは768px時点でのフォントサイズを指定します。

サイト全体でclamp関数を頻繁に使う場合は、MINの値の選択基準が全くないとウィンドウサイズが小さい時にテキストのジャンプ率が低いサイトになってしまいます。そのため最低限ジャンプ率を崩さない程度の基準は必要です。具体的には「MAXの80%以下にはしない」や「MAX-6px以下にはしない」のような基準が挙げられます。

またスマートフォン系統のデザインカンプのフォントサイズもMINの値の選択肢の1つです。MAX同様、MINの値がスマートフォン系統のデザインカンプより小さな値を取ることはないため、タブレット系統とスマートフォン系統のフォントサイズが同じ値を取る場合に有効です。

逆にタブレット系統のデザインカンプが用意されており、スマートフォン系統と異なるフォントサイズが設定されている場合はタブレット系統のフォントサイズをMINの値に採用するといいでしょう。

PC系統のフォントサイズを$PC_{fz}$、タブレット系統のフォントサイズを$TB_{fz}$、スマートフォン系統のフォントサイズを$SP_{fz}$とすると、常に以下の関係が成り立ちます。
$SP_{fz} \leq MIN_{(px)} \leq TB_{fz}<PC_{fz}=MAX_{(px)}$

3-3.VALの算出方法

VALの決定方法は以下の2種類が考えられます。

1. $WS_{start} = BP_{max}$ かつ $WS_{end} = BP_{min}$の場合
2. $WS_{start} \neq BP_{max}$ または $WS_{end} \neq BP_{min}$の場合

ウィンドウサイズとブレイクポイントに関して以下の書き方を使用します。

  • ウィンドウサイズについて

    • VALを参照させはじめたいウィンドウサイズを$WS_{start}$
    • VALの参照しおわりたいウィンドウサイズを$WS_{end}$
  • ブレイクポイントについて

    • ブレイクポイントの上限値を$BP_{max}$
    • ブレイクポイントの下限値を$BP_{min}$

言い換えると
1. ブレイクポイントの上限値から下限値まで常に同じ変化量で単調減少する場合
2. 特定のウィンドウサイズから特定のウィンドウサイズまでは常に同じ変化量で単調減少し、それ以外ではフォントサイズが変化しない場合

ブレイクポイント1400px~768px内で1200px~768pxの間だけclamp関数にVALを参照させたい場合
$BP_{max}:1400px$ $BP_{min}:768px$
$WS_{start}:1200px$ $WS_{end}:768px$

3-3-1.VALの算出方法と一次関数

VALの算出方法は一次関数の変化の割合と切片の計算問題に置き換えることができます。これはVALがcalc()のように計算式として指定することができ、その形が一次関数と同じであることに起因します。
$VAL_{(vw)}$は以下の形で指定し、ここでの相対単位はvwであると仮定します。

 $VAL_{(vw)}\quad=\quad$ 相対単$位_{(vw)}\quad+\quad$絶対単$位_{(px)}$

また$VAL_{(vw)}$ が実際にブラウザ上で計算され$VAL_{(px)}$ に変換されるとき、以下のような計算式を用います。

 $VAL_{(px)}\quad=\quad VAL_{(vw)}\quad \times\quad$現在のウィンドウサイ$ズ_{(px)}\quad +\quad$絶対単$位_{(px)}$

実際は$VAL_{(vw)}$ が実際にブラウザ上で計算され$VAL_{(px)}$ に変換されるときは、百分率表記である$VAL_{(vw)}$を割合に変換するために0.01倍されますが、0.01は定数であり式の性質には影響を与えないのでここでは視認性を考慮し、省略しています。

ここで$VAL_{(vw)}$と絶対単位は定数、ウィンドウサイズは変数であることから$VAL_{(px)}$は変化の割合が$VAL_{(vw)}$ で切片が絶対単位の一次関数であることがわかります。そのため、一次関数の変化の割合と切片の計算問題と同様に$VAL_{(vw)}$と絶対単位を求めることができ、適切なVALの値を算出することが出来ます。

3-3-2.一次関数の方程式問題のVALの算出方法への置き換え

問)点A(1400,32)と点B(768,18)を通る直線の方程式を求めなさい。

一般的な一次関数の計算問題です。まず変化の割合を計算し、求めた変化の割合を用いて切片を求めます。

問)最大フォントサイズを32px、最小フォントサイズを18pxとして、ウィンドウサイズ1400pxから768pxまでの間を一定の割合で変化するVALの値を求めたい。

clamp関数で適切なVALの値を算出したいときのシチュエーションです。問題の書き方は違いますが、上記の一次関数の計算問題と同様の方法で解くことが出来ます。大事なのは$WS_{max}$と$MAX_{(px)}$、$WS_{min}$と$MIN_{(px)}$をそれぞれ座標のようにセットとして扱うことです。なぜこれらを形式上の座標として扱うことができるのか、一次関数のグラフを用いて考えてみます。

3-3-3.グラフで理解するVALの算出方法と一次関数の関係

1. $WS_{start} = BP_{max}$ かつ $WS_{end} = BP_{min}$の場合
IMG_2547.PNG

現在のウィンドウサイズとフォントサイズの関係をグラフにしました。VALの式は「幅1400pxでフォントサイズが32px」と「幅768pxでフォントサイズが18px」の2つの条件を満たす必要があります。そのためグラフにすると点(1400,32)と点(768,18)を通る一次関数として表すことが出来ます。

つまり、$WS_{max}$と$MAX_{(px)}$、$WS_{min}$と$MIN_{(px)}$をそれぞれ座標のようにセットに扱えるのは、VALの式が「幅1400pxでフォントサイズが32px」と「幅768pxでフォントサイズが18px」の2つの条件を満す直線であるためです。

2. $WS_{start} \neq BP_{max}$ または $WS_{end} \neq BP_{min}$の場合
IMG_2548.PNG

VALの算出には$WS_{start}$と$WS_{end}$さえ設定されていれば、その値は$BP_{max}$ 、$BP_{min}$である必要はありません。$WS_{start}$と$WS_{end}$ は $BP_{max} \leq WS\leq BP_{min}$かつ$WS_{end} < WS_{start}$ さえ満たしていれば任意の値を取ることが出来ます。

上記のグラフは$WS_{start}=1200px$ と設定したときのVALの式を表しています。グラフから分かるように$WS$の値が変化すれば直線の方程式も変わるため、VALの値も$WS_{start} = BP_{(max)}$のときとは異なります。

より具体的な数値を用いた参考記事はこちら

3-3-4.VALの算出方法の一般化

後述のscss関数化のためにVALの算出方法を変数を用いて一般化する必要があります。

ここでは$VAL_{(vw)}$を構成する相対単位と絶対単位を以下のように表します。

  • 相対単位(一次関数の変化の割合)の値を $RU_{(vw)}$
  • 絶対単位(一次関数の切片)の値を $AU_{(px)}$
RU_{(vw)}= \frac{MAX_{(px)}-MIN_{(px)}}{WS_{start}-WS_{end}}\times 100 \\
AU_{(px)}= MAX_{(px)}\ -\ \frac{MAX_{(px)}-MIN_{(px)}}{WS_{start}-WS_{end}}\times WS_{start}

ただし、$AU_{(px)}$の与式における
$( WS_{start}, MAX_{(px)} )$ は $( WS_{end} , MIN_{(px)} )$ に置換可能

VAL_{(vw)}=RU_{(vw)} + AU_{(px)}

また$VAL_{(vw)}$について上記の式が成り立つため、$VAL_{(vw)}$を$( WS_{start}, MAX_{(px)} )$ $( WS_{end} , MIN_{(px)} )$ を用いて表すことが出来ました。

単純な一次関数との違いは$RU_{(vw)}$の算出のために100をかける必要がある点です。vwの取る値は百分率です。そのため割合のままではVALの値を正しく計算できません。一方で$AU_{(px)}$の計算はこれまでの一次関数の計算と同様に割合を用います。そのため$AU_{(px)}$の計算に$RU_{(vw)}$がそのまま流用できない点に注意してください。

3-3-5.VALの値内の切片をpxからremに置き換える

ここまで$VAL_{(vw)}$の切片$AU_{(px)}$はpxと仮定して進めてきましたが、フォントサイズの単位はpxではなくremを使用しているケースもよくあります。そのため、事前に変換係数$\alpha$を設定しておくことで、変換係数をフォントサイズ(px)にかければフォントサイズ(rem)が得られるようにしておきます。

remの基準となるルートのフォントサイズを $root_{(px)}$ とする

\alpha = \frac{1}{root_{(px)}}

4.clamp関数のscss関数化

VALの値の決定に感覚や主観が介入することは制作効率の悪化にも繋がります。

先にこのように述べた通り、clamp関数を実用化したい場合scssを用いて独自関数化することをおすすめします。

clamp関数を使うたびにツールを用いてVALの値を計算するのでは制作効率の低下は避けられません。その点独自関数は任意の引数を設定するだけで自動的にVALの値を計算してくれるため、一貫性と制作効率の両側面から見て優れています。

4-1.clamp関数の既存の独自関数

今回はこちらの記事で紹介されている独自関数を基に、様々な状況設定でも汎用的に使うことのできるロバストな独自関数を目指します。

4-2.既存の関数から拡張可能な点

既存の関数は引数を4つ持っていますが、毎回引数に同じ値を持たせる場合では記述を省略することが出来ます。

4-2-1.MINのデフォルト値

「MINの値の決定方法」の節でも言及した通り、MINの値はある程度の選択基準がないとジャンプ率で破綻を起こす可能性があります。タブレット系統やスマートフォン系統のデザインカンプの値を引数に指定する場合は問題ありませんが、そうでない場合のためにデフォルト値として選択基準を基に計算した値を設定し、任意の値を取りたい場合は引数で指定するのが良いと思います。

4-2-2.ウィンドウサイズの上限下限値の決定方法

VALの値の決定方法には以下の2種類がありました。

1. $WS_{start} = BP_{max}$ かつ $WS_{end} = BP_{min}$の場合
2. $WS_{start} \neq BP_{max}$ または $WS_{end} \neq BP_{min}$の場合

2つのシチェーションのうち、$WS_{start} = BP_{max}$ かつ $WS_{end} = BP_{min}$ の場合では $WS_{start}$と$WS_{end}$ において任意の値を取らないため、1つのプロジェクトで同じ値が繰り返し用いられるケースが多いと考えられます。

そのためデフォルト値としてそれぞれ $WS_{start} = BP_{max}\ ,$ $WS_{end} = BP_{min}$ を設定し、任意のウィンドウサイズ間でレスポンシブしたい場合は、引数で設定するのが良いと思います。

4-2-3.rem変換に関する拡張

既存の関数ではremの $root_{(px)}=16$ で固定されていますが、変換係数を用いることで $root_{(px)} \neq 16$ であるプロジェクトに対しても同様の独自関数が使えるようにします。またVALの切片の単位をremで計算するかpxで計算するかを指定するフラグも用意します。

4-3.拡張後の独自関数

前述の通りこちらで紹介されている独自関数を参考に拡張しています。
$WS_{start}$と$WS_{end}$のデフォルト値にはよくメディアクエリで用いられるウィンドウサイズの変数を流用しています。またMINのデフォルト値はMAXの値の80%としています。

この独自関数はpx基準で作られています。そのためremで使用すると変換係数の四捨五入の影響で誤差の範囲でズレが生じます。主にremで使用したい場合は変換係数の代わりに$root_{px}$をremの値にかけてrem基準にしてしまっても良いと思います。

mixin.scss
// コンテンツ幅
$sm: 600;
$md: 768;
$lg: 1200;
$xl: 1400;
$xx: 1920;
function.scss
@use "sass:math";
@use "mixin";

// 小数点込みで四捨五入する($floatIndex:2 のとき小数第2位までの数値で出力)
@function divFunc($value01,$value02,$floatIndex:2){
    $floatNum: math.pow(10,$floatIndex);
    $divValue: math.div($value01,$value02)*$floatNum;
    $roundValue: math.div(math.round($divValue),$floatNum);
    @return $roundValue;
}
// clamp計算
@function clampAuto($fontMax,$fontMin:($fontMax * 0.8),$windowMax:mixin.$xl,$windowMin:mixin.$md,$remBoolean:false,$remRoot:16) {
    $vwRootRate: 1px;
    @if $remBoolean == true{
        $remRootRate: divFunc(1rem,$remRoot);
    }
    $fontRate: $fontMax - $fontMin;
    $windowRate: $windowMax - $windowMin;

    $valSlope: divFunc($fontRate,$windowRate,$floatIndex:4) * 100vw;
    $valIntercept: (($fontMax - divFunc($fontRate,$windowRate,$floatIndex:4) * $windowMax) * $remRootRate);

    $fontMaxReturn: $fontMax * $remRootRate;
    $fontMinReturn: $fontMin * $remRootRate;

    @return clamp(#{$fontMinReturn}, #{$valIntercept} + #{$valSlope}, #{$fontMaxReturn});
}
sample.scss
.sample01{
    font-size: function.clampAuto($fontMax:40);
}
// font-size: clamp(32px, 17.8px + 1.85vw, 40px);

.sample02{
    font-size: function.clampAuto($fontMax:32,$fontMin:24);
}
// font-size: clamp(24px, 9.8px + 1.85vw, 32px);

.sample03{
    font-size: function.clampAuto($fontMax:36,$fontMin:26,$windowMax:1200,$remBoolean:true);
}
// font-size: clamp(1.56rem, 0.4968rem + 2.31vw, 2.16rem);

.sample04{
    font-size: function.clampAuto($fontMax:36,$fontMin:26,$windowMax:1200,$windowMin:1000,$remBoolean:true,$remRoot:10);
}
// font-size: clamp(2.6rem, -2.4rem + 5vw, 3.6rem);

5.まとめ

clamp関数はリキッドデザインや部分的なレスポンシブで有効なcss関数でした。また面倒なVAL計算も関数化することで省略することができました。

デバイスの多様化によりWeb制作におけるリキッドデザインの需要は以前よりも増しています。それに伴いclamp関数が必要になる機会も今まで以上に増えることが予想されます。その際にこの記事が少しでもお役に立てれば嬉しく思います。

○ 参考記事
https://developer.mozilla.org/ja/docs/Web/CSS/clamp
https://developer.mozilla.org/ja/docs/Web/CSS/min
https://developer.mozilla.org/ja/docs/Web/CSS/max
https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Functions
https://www.m-hand.co.jp/design/8504/
https://qiita.com/soundweaver/items/9b5a3a7c0b0e198f4570

12
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?