はじめに
本記事は、clamp() の数式や使い方を解説するものではありません。
また、便利なユーティリティを紹介する記事でもありません。
フロントエンドにおけるレスポンシブ設計の判断を、
「個人の裁量」や「暗黙知」のままにせず、
SCSS から JavaScript / TypeScript 側へ引き上げ、
API という形で明示的な契約として固定するまでの設計と実装について書きます。
(ここでいう契約とは、「どこまでを保証し、どこからを保証しないか」を API として明確にすることです)
例えばSCSSでは、引数の順序を間違えてもコンパイルエラーにならず、ブラウザで確認するまで気づかないことがあります。
しかしTypeScriptなら型定義によって実装段階で即座にエラーとして弾くことができます。
対象読者は以下を想定しています。
- clamp やレスポンシブ設計が人によってバラつく現場に心当たりがある方
- CSS 設計を「再現」ではなく「設計」として扱いたい方
- SCSS の限界を感じ始めているフロントエンドエンジニア
使用例
Responsive clamp (px)
import { rClampPx } from 'responsive-size-js';
const fontSize = rClampPx(16, 24, 375, 1440);
// → CSS で使用可能な clamp() 文字列(string)を返します。(数値は公開 API ではありません)
// (※返却される文字列フォーマットは保証されますが、内部計算値は実装詳細として扱われます)
Responsive clamp (rem)
import { rClampRem } from 'responsive-size-js';
const fontSize = rClampRem(16, 24, 375, 1440, {
baseFontSize: 16,
});
// → rem + vw を用いた clamp() 文字列(string)を返します(数値は公開 API ではありません)
// (※返却される文字列フォーマットは保証されますが、内部計算値は実装詳細として扱われます)
Simple unit conversion
import { pxToRem, remToPx } from 'responsive-size-js';
pxToRem(16); // "1rem"
remToPx(1); // "16px"
パッケージ公開先
- npm: https://www.npmjs.com/package/responsive-size-js
- GitHub: https://github.com/minori-003/responsive-size-js
なぜ responsive-size-js を作ったのか
このライブラリを作り始めた理由は、特別なものではありません。
もともとは、
JavaScript / TypeScript 学習の題材として、以前 SCSS で作った関数群を移植してみようというのが出発点でした。
せっかく作るのであれば、
- できるだけ壊れにくくしよう
- 使う側が困らない形にしよう
という、かなり実務寄りの感覚で設計を始めました。
raw レイヤーが生まれた理由
実装を進める中で、
「このライブラリは、単なる CSS 文字列生成ツールではない」
という前提がはっきりしてきました。
内部的には、CSS 文字列になる前の「純粋な数値」が必要な場面が多々あります。
- 複雑な計算ロジックを独立させたい
- 入力値の検証と、文字列生成の責務を分けたい
- ロジック単体で厳密なテストを行いたい
そう考えると、 数値だけを返す関数群(raw レイヤー)を内部で切り出すのが自然でした。
raw レイヤーがあることで、
- 計算ロジックのみを対象とした厳密なテストが可能になる
- 将来的な機能拡張の際に、土台として利用できる
という、ライブラリの品質と保守性を高めるための利点があります
css レイヤーの役割
一方で、すべての利用者が 数値計算や前提条件を意識したいわけではありません。
- 初心者
- 普段の制作作業
- 単純に clamp を使いたいケース
こうした用途では、
CSS 向けの文字列をそのまま返してくれる関数 があれば十分です。
そこで、次の様な役割分担にしました。
- raw レイヤー:数値計算の責務
- css レイヤー:CSS 向けへの翻訳
設計判断を JS/TS 側に引き上げた理由
制作を進める内に私は、設計判断そのものを JavaScript / TypeScript 側へ引き上げることにしました。
実装を進める中で、以下の点が 設計として必要不可欠だと分かってきました。
- 型で前提条件を表現できる
- 不正な入力をエラーとして失敗させられる
- API として契約を定義できる
- README を仕様書として機能させられる
SCSS では難しかった「何を保証し、何を保証しないか」を、JS/TS なら明示できます。
これらが、設計判断を JS/TS 側へ引き上げる決め手となりました。
responsive-size-js のレイヤー設計
本ライブラリは、意図的にレイヤーを分けています。
公開 API(css レイヤー)
- rClampPx
- rClampRem
- pxToRem など
これらは 必ず単位付きの CSS 文字列を返します。
利用者は計算結果を気にせず、そのまま CSS に使えます。
内部実装(raw / utils / setting)
- 数値ベースの計算
- 単位除去・変換
- 設定値管理
これらは README では触れません。
将来的な公開余地は残しつつ、現時点では契約しない判断をしています。
raw レイヤーを「保証しない」という判断
数値計算を担う raw レイヤーは存在しますが、
あえて外部から直接利用できない構成にしています。
理由は、設計上の判断として次の点を重視したためです。
- 初心者が誤って使う必要はない
- 将来の変更余地を残したい
- 保証範囲を明確にしたい
内部実装として存在しますが、
公開 API と同じレベルの後方互換性や安定性は保証しません。
API 設計で最も重視したポリシー
設計において、次のポリシーを一貫して守りました。
- 不正な入力を黙って補正しない(必ずエラー)
- デフォルト値を極力排除する
- 数値計算と CSS 出力を分離する
- README に明示した内容のみを保証する
clamp() 内部で生成される具体的な計算式の文字列(数値の丸め方など)は、将来的に変更される可能性があるため保証しません。
保証するのは API の振る舞いと契約 です。
rClampPxとrClampRemを分けた理由
pxとremは、実務では混在します。
そして混在するからこそ、名前で意図を固定する必要があります。
- rClampPx:pxベースのclamp
- rClampRem:pxをremに正規化したclamp
名前が設計意図を語ることで、
利用者は「今どの前提で書いているか」を意識できます。
また、元となった SCSS の rClamp については、
README に明示的にクレジットを記載しています。
テストは「数値」ではなく「契約」を保証する
本ライブラリのテストは、 数学的な正しさを証明するものではありません。
- APIがstringを返すこと
- エラー条件が変わらないこと
- README の使用例が壊れないこと
これらを保証します。
README はドキュメントではなく、契約です。
このライブラリの立ち位置
正直に言うと、通常の Web 制作ではオーバースペックです。
このライブラリは、
- 「ローカル環境に組み込むclampジェネレーター」
- 設計判断をJS側で確定させるための道具
という位置づけだからです。
SCSSは「使うだけ」。
設計は JS/TS 側で完結させます。
私はこのライブラリを、
「誰でも使える便利ツール」ではなく、
設計責任を引き受けるための道具として位置づけています。
実務・フリーランスでの活用イメージ
- レスポンシブ設計が属人化している現場の整理
- CSS / SCSS の共通設計ルールの策定
- 新規開発時の初期設計フェーズへの参加
- clamp / viewport 設計の標準化
「clamp が書ける」よりも、「clamp の設計責任を持てる」 ことを重視しています。
おわりに
便利なツールを作りたかったわけではありません。
学習目的で始めたものが、
実務的な判断を積み重ねた結果として、
レイヤー化された設計に落ち着いた。
responsive-size-js は、その結果として出来上がったものです。