- 著者
- app-hacks
- 公開日
- 更新日
- 確認日
CSS / グラデーション / JavaScript
CSSグラデーション生成ツールの設計と実装
線形・放射状グラデーション、色停止点、CSS出力、コピー処理を備えるCSSグラデーション生成ツールの設計を解説します。
CSSグラデーション生成ツールの設計と実装
CSSグラデーションのコードを手で組み立てると、色を追加したときに位置がずれたり、画面のプレビューとコピーしたCSSが一致しなかったりします。生成ツールでは、入力を検証してから一つの状態にまとめ、プレビューとコード出力の両方を同じ処理から作ることが重要です。
この記事では、linear・radial・conicの3種類を扱う場合の設計を説明します。実際に設定と出力を試す場合は、CSSグラデーションジェネレーターを利用できます。
入力を一つの状態として持つ
種類、色停止点、角度、形状、中心位置を別々の値として場当たり的に扱うと、種類を切り替えたときに古い値が残りやすくなります。グラデーション全体を表す状態を用意し、色と位置は必ず同じ停止点オブジェクトに入れます。
type ColorStop = { color: string; position: number };
type GradientOptions = {
type: 'linear' | 'radial' | 'conic';
stops: ColorStop[];
angle: number;
radialShape: 'circle' | 'ellipse';
radialPosition: string;
conicAngle: number;
conicPosition: string;
};
色と位置を別配列にすると、行の追加・削除・並べ替えで対応関係を失いやすくなります。停止点は2〜5個のように範囲を決めておくと、UIと検証の条件を必要以上に増やさずに済みます。
プレビューとコード出力を同じ関数から作る
プレビュー用とコピー用で別々にCSSを生成すると、片方だけ修正されて表示と出力が食い違います。グラデーション値を組み立てる関数を一つにし、コピーする場合だけbackground:を付けます。
function gradientValue(options: GradientOptions) {
const stops = options.stops
.map(({ color, position }) => `${color} ${position}%`)
.join(', ');
if (options.type === 'radial') {
return `radial-gradient(${options.radialShape} at ${options.radialPosition}, ${stops})`;
}
if (options.type === 'conic') {
return `conic-gradient(from ${options.conicAngle}deg at ${options.conicPosition}, ${stops})`;
}
return `linear-gradient(${options.angle}deg, ${stops})`;
}
function backgroundDeclaration(options: GradientOptions) {
return `background: ${gradientValue(options)};`;
}
プレビューにはgradientValue()の戻り値を、コード欄にはbackgroundDeclaration()の戻り値を使います。この形なら、種類を変更しても色停止点の扱いは共通です。
入力を正規化してから検証する
HEXカラーは#の有無や英字の大文字・小文字をそろえ、位置と角度は数値に変換してから使います。不正な入力の間は最後に有効だったプレビューを残すと、入力途中に画面全体が崩れることを防げます。
確認する項目は、停止点が2〜5個であること、色が許可したHEX形式であること、位置が0〜100の範囲で重複していないこと、角度が0〜360の範囲であることです。停止点は位置順に並べてから出力すれば、入力行を操作した順番に左右されないCSSになります。同じ位置を許可すると意図的な色の切り替えは可能ですが、基本機能では誤操作との区別が難しいため、エラーにする方が扱いやすくなります。
コピーの成功・失敗を利用者に伝える
コピーにはnavigator.clipboard.writeText()を使えますが、権限や実行環境によって失敗する可能性があります。コピーできた場合とできなかった場合の両方を、画面上のテキストで伝えます。
async function copyCss(css: string) {
try {
await navigator.clipboard.writeText(css);
return { ok: true, message: 'CSSをコピーしました。' };
} catch {
return { ok: false, message: 'コピーできませんでした。コードを選択してコピーしてください。' };
}
}
失敗時には次に取る操作を示すことが大切です。また、生成されたCSSや色は利用者が作成した内容です。利用状況を計測する場合も、コードそのものを送らず、コピー操作が行われたかどうかなど必要最小限の情報にとどめます。
出力をテストして変更に強くする
文字列を返す関数は、入力と期待するCSSを対応させてテストできます。linear・radial・conicの各形式、停止点の並び替え、境界値、不正なHEXを確認しておけば、画面の実装を変更しても出力形式を守れます。
グラデーションは背景に使われることが多いため、実装後は文字を重ねたときの読みやすさも確認してください。CSSが正しく生成されることと、配色が読みやすいことは別の問題です。生成、検証、コピーの責務を分けることで、後から機能を追加しても壊れにくいツールになります。