k8o

Blog

progress()で値が2つの境界のどこにあるかを比率で取り出す

progress()は、値が開始値と終了値の間のどこにあるかを0から1の数値で返すCSSの関数です。Baseline 2026で主要ブラウザに揃い、長さや個数といった別の型の値を比率に変換して、文字サイズや不透明度の補間を係数計算なしで書けるようになりました。

4分で読めます
公開: 2026年9月10日(木)
更新: 2026年9月10日(木)
Newly availableprogress()2026年〜
  • Chrome138
  • Edge138
  • Firefox155
  • Safari26

はじめに

画面幅が400pxから1200pxに広がるあいだに、文字サイズを1remから2remへ滑らかに変えたいとします。これをCSSで書くには、幅400pxで1rem、幅1200pxで2remになる一次式を自分で用意する必要がありました。1remを16pxとすると、幅が800px増えるあいだに文字は16px増えるので、傾きは幅100pxあたり2px、つまり2vwです。幅400pxのとき2vwは8pxなので、1remに届かせるには0.5remを足します。こうして得た0.5rem + 2vwclamp(1rem, 0.5rem + 2vw, 2rem)の中に置いて両端で止める、というのがこれまでの書き方です。逆算そのものは難しくありませんが、できあがった式から元の条件を読み取るのは難しく、境界を変えるたびに解き直しになります。

progress()は、値が開始値と終了値の間のどこにあるかを0から1の数値で返す関数です。補間したい両端と今の値をそのまま書けば比率が手に入るので、係数を解く工程がなくなります。Chrome 138とSafari 26で先行して使えており、Firefox 155が対応したことでBaseline 2026に加わりました。

構文と返り値

引数は3つで、順に今の値、開始値、終了値です。返り値は(value - start) / (end - start)を計算した<number>です。冒頭の例をprogress()で書き直すと、こうなります。

css
/* これまで: 傾き2vwと切片0.5remを400pxと1200pxから逆算する */
h1 {
  font-size: clamp(1rem, 0.5rem + 2vw, 2rem);
}

/* progress(): 両端の幅と両端のサイズをそのまま書く */
h1 {
  font-size: calc(1rem + progress(100vw, 400px, 1200px) * 1rem);
}

幅が800pxなら(800 - 400) / (1200 - 400)で0.5になり、font-sizeは1.5remです。400pxと1200px、1remと2remという条件がそのまま式に並ぶので、あとから幅の境界を変えるときも該当の数字を書き換えるだけで済みます。

返り値は0から1にクランプされます。値が開始値より小さければ0、終了値より大きければ1です。冒頭の例でclamp()が担っていた両端の固定はprogress()が引き受けるので、外側で包む必要はありません。開始値と終了値が同じ場合は0を返します。

3つの引数は単位が違っていても構いませんが、型は揃っている必要があります。progress(3em, 0px, 100px)は長さ同士なので有効で、3em48pxに解決されるなら0.48になります。progress(3s, 0px, 100px)のように型が混ざると関数全体が無効になります。

返り値は単位を持たない数値なので、入力が長さでも、opacityline-heightのように数値しか受け付けないプロパティに使えます。100vwの代わりに100cqwを渡せば、画面幅ではなくコンテナの幅を基準にできます。

画面幅を動かして文字サイズを見る

画面幅に見立てた値をスライダーで動かします。clamp()の一次式とprogress()の式が同じ大きさになり、400pxより狭い側と1200pxより広い側では両端で止まります。

400pxより狭ければ1rem、1200pxより広ければ2remで止まります

clamp(1rem, 0.5rem + 2vw, 2rem)

見出しのサンプル

calc(1rem + progress(100vw, 400px, 1200px) * 1rem)

見出しのサンプル

実際の画面幅の代わりに、スライダーの値を--widthとして両方の式に渡しています。上は逆算した係数で書いた一次式、下はprogress()で両端をそのまま書いた式で、どの幅でも同じ大きさになります。

並び順を0から1に正規化する

progress()に渡せるのは長さだけではありません。sibling-index()sibling-count()を組み合わせると、リストの先頭を0、末尾を1にした比率が取れます。

css
li {
  --ratio: progress(sibling-index(), 1, sibling-count());
先頭が0、末尾が1。項目数が変わっても両端は固定
  opacity: calc(0.3 + var(--ratio) * 0.7);
}

sibling-index()をそのまま係数に使うと項目数に応じて値の幅が変わってしまいますが、progress()で正規化すれば項目数に関係なく両端が固定されます。sibling-index()の記事で扱った遅延の計算も、この形にすると全体の所要時間を固定できます。

項目数を変えても両端を固定する

sibling-index()とsibling-count()をprogress()に渡し、項目数に関係なく先頭を0、末尾を1にして幅と不透明度を段階的に変えています。

  • 項目
  • 項目
  • 項目
  • 項目
  • 項目

progress(sibling-index(), 1, sibling-count())で先頭を0、末尾を1にしています。項目数を変えても、最初と最後が両端に張り付いたまま間が等分されます。

おわりに

progress()は、値が2つの境界のどこにあるかを0から1の数値にする関数です。長さや個数を比率に変換できるので、opacityfont-sizeの補間を、係数を逆算せずに両端の値で書けるようになります。clamp()の一次式で書いてきた流体タイポグラフィや、sibling-index()を係数にしていた段階的な表現は、progress()で条件がそのまま読める形に置き換えられます。

読了率 0%
もくじ