最近、新しいテーマと先駆的なキャラクターのグループでウェブサイトのアニメーション グラフィックを更新し、このシリーズで共有したテクニックをたくさん実践しました。私のアニメーションのいくつかは、誰かが操作したとき、または一日のさまざまな時間に外観が変わります。
私のブログ ページの上部にあるグラフィックの色は、毎日朝から夜まで変わります。次に、オーバーレイ レイヤーとブレンド モードを使用して、寒い色と冬のテーマを追加するスノー モードがあります。
これに取り組んでいる間、CSS の相対カラー値を使用すると、プロセスを簡素化しながら、より詳細な制御ができるのではないかと考え始めました。 注: このチュートリアルでは、グラフィックスとアニメーションのテーマを設定するための相対カラー値と OKLCH カラー スペースに焦点を当てます。相対的な色について深く知りたい場合は、Ahmad Shadeed が素晴らしいインタラクティブなガイドを作成しました。色空間、色域、OKLCH については、私たちの Geoff Graham が書いています。
要素を繰り返し使用することが鍵でした。背景は可能な限り再利用され、ズームやオーバーレイを使用して同じアートワークから新しいシーンを構築できました。これは必然的に生まれたものですが、個々のシーンではなくシリーズの観点から考えることも促進されました。 カラーパレットの手動更新の問題 早速私の挑戦に移りましょう。このようなトゥーン タイトル (1959 年のヨギ ベア ショーのエピソード「Lullabye-Bye Bear」に基づく) や私の作品では、パレットは選ばれた数色に限定されています。
私は、色相を追加せずにパレットを拡張するために、いわゆる「ファンデーション」カラーから色合いと色合いを作成します。
Sketch では HSL カラー空間で作業するため、このプロセスには基礎色の明度の値を増減することが含まれます。正直なところ、それは難しい作業ではありませんが、異なるファンデーションの色を選択するには、全く新しい色合いと色合いを作成する必要があります。これを手動で何度も行うと、すぐに面倒になってしまいます。
HSL(H(色相)、S(彩度)、L(明度))色空間について言及しましたが、これは色を表現するいくつかの方法のうちの 1 つにすぎません。 RGB (R (赤)、G (緑)、B (青)) は、少なくとも 16 進形式ではおそらく最もよく知られています。 LAB — L (明度)、A (緑 - 赤)、B (青 - 黄) — と、新しいものの現在広くサポートされている LCH — OKLCH 形式の L (明度)、C (彩度)、H (色相) — モデルもあります。 LCH (特に CSS の OKLCH) を使用すると、ファンデーションの色の明度の値を調整できます。
または、彩度を変更することもできます。 LCH 彩度と HSL 彩度はどちらも色の強度または豊かさを表しますが、その方法は異なります。 LCH を使用すると、色の範囲がより広く、より予測可能な色の混合が可能になります。
色相を変更して、同じ明度と彩度の値を共有する色のパレットを作成することもできます。 HSL と LCH の両方で、色相スペクトルは赤から始まり、緑、青を経て赤に戻ります。
OKLCH が私の色に対する考え方を変えた理由 Sketch を含むデザイン ツールがまだ追いついていないにもかかわらず、OKLCH 色空間のブラウザー サポートは現在広く普及しています。幸いなことに、それによって OKLCH の使用が妨げられることはありません。ブラウザは、Hex、HSL、LAB、および RGB 値を OKLCH に喜んで変換します。 CSS カスタム プロパティは、16 進数を含む任意の空間の基本色で定義できます。 /* ファンデーションカラー */ --基礎: #5accd6;
そこから派生した色はすべて、自動的に OKLCH に変換されます。 --foundation-light: oklch(from var(--foundation) [...]; } --foundation-mid: oklch(from var(--foundation) [...]; } --foundation-dark: oklch(from var(--foundation) [...]; }
デザインシステムとしての相対色 相対的な色は、「この色を取り出し、微調整して、結果を教えてください」と言うようなものだと考えてください。カラーを調整するには、絶対的な変更と比例的な変更の 2 つの方法があります。コード的には似ていますが、ファンデーションの色を交換し始めると、動作は大きく異なります。その違いを理解することで、相対的な色の使用をシステムに変えることができます。 /* ファンデーションカラー */ --基礎: #5accd6;
たとえば、私のファンデーション カラーの明度の値は 0.7837 ですが、より暗いバージョンの明度の値は 0.5837 です。差を計算するには、高い値から低い値を引き、その結果を calc() 関数を使用して適用します。 --foundation-dark: oklch(var(--foundation) から calc(l - 0.20) c h);
明るい色を実現するには、代わりに差を追加します。 --ファンデーションライト: oklch(var(--foundation) から 計算(l + 0.10) c h);
クロマ調整も同じプロセスに従います。ファンデーションの色の強度を 0.1035 から 0.0035 に下げるには、一方の値をもう一方の値から減算します。 oklch(var(--foundation) から l calc(c - 0.10) h);
色相のパレットを作成するには、基礎色の色相値 (200) と新しい色相 (260) の差を計算します。 oklch(var(--foundation) から l c calc(h + 60));
これらの計算は絶対的なものです。一定の金額を引くときは、事実上、「常にこれだけ差し引いてください」と言っていることになります。固定値を追加する場合も同じことが当てはまります。 計算(c - 0.10) 計算(c + 0.10)
私はこのアプローチの限界を苦労して学びました。固定彩度値の減算に頼っていた場合、基盤を変更するとすぐに色がグレーに向かって崩壊してしまいました。ある色ではうまく機能したパレットが、別の色ではうまくいかなくなりました。 乗算の動作は異なります。彩度を乗算するとき、私はブラウザに「この色の強度を一定の比率で下げてください」と指示していることになります。基礎が変わっても、色の間の関係はそのまま残ります。 計算(c * 0.10)
私の移動、拡大縮小、回転のルール
明度を移動(加算または減算)、 スケールクロマ(乗算)、 色相を回転します (度を加算または減算)。
強度の変化がベースカラーに比例するようにしたいため、彩度をスケールします。色相の関係は回転的なものであるため、色相を乗算することは意味がありません。明るさは知覚的かつ絶対的なものであり、それを掛け合わせると奇妙な結果が生じることがよくあります。
1 つの色からテーマ全体まで 相対カラーを使用すると、基本カラーを定義し、そこから必要な他のすべてのカラー (塗りつぶし、ストローク、グラデーション ストップ、シャドウ) を生成できます。その時点で、色はパレットではなくなり、システムになり始めます。 SVG イラストは、塗りつぶし、ストローク、グラデーション全体で同じ数色を再利用する傾向があります。相対カラーを使用すると、これらの関係を一度定義すれば、どこでも再利用できます。これは、アニメーターが背景を再利用して新しいシーンを作成するのと同じです。
基本カラーを一度変更すると、手動で再計算することなく、派生したすべてのカラーが自動的に更新されます。アニメーション グラフィック以外でも、これと同じアプローチを使用して、ボタンやリンクなどのインタラクティブな要素の状態の色を定義できます。 「Lullabye-Bye Bear」のトゥーン タイトルで使用したファンデーションの色は、シアンに見える青です。背景は、ファンデーションと暗いバージョンの間の放射状のグラデーションです。
まったく異なる雰囲気の別のバージョンを作成するには、基礎の色を変更するだけです。 --基礎: #5accd6; --grad-end: var(--foundation); --grad-start: oklch(var(--foundation) から 計算(l - 0.2357) 計算(c * 0.833) h);
カラー値を複製せずにこれらのカスタム プロパティを SVG グラデーションにバインドするために、ハードコードされたストップ カラー値をインライン スタイルに置き換えました。
<定義>
次に、トゥーン テキストが、選択した基礎の色と常に対照的であることを確認する必要がありました。色相を 180 度回転すると、確かにポップな補色が生成されますが、不快に振動する可能性があります。 .text-light { 塗りつぶし: oklch(var(--foundation) から l c calc(h + 180)); }
90°シフトすると、完全に補色ではなくても鮮やかな二次色が生成されます。 .text-light { 塗りつぶし: oklch(var(--foundation) から l c calc(h - 90)); }
私のクイック ドロー マグロウの 1959 年のトゥーン タイトル「エル カボン」の再現では、同じテクニックを使用していますが、より多様なパレットを使用しています。たとえば、ファンデーションの色と暗い色合いの間には、別の放射状のグラデーションがあります。
背景の建物と木は、同じ基礎の色の異なる色合いにすぎません。これらのパスには、さらに 2 つの塗りつぶし色が必要でした。 .bg-mid { 塗りつぶし: oklch(var(--foundation) から 計算(l - 0.04) 計算(c * 0.91) h); }
.bg-dark { 塗りつぶし: oklch(var(--foundation) から 計算(l - 0.12) 計算(c * 0.64) h); }
基礎が動き始めるとき これまでのところ、私が示したものはすべて静的なものでした。カラーピッカーを使用してファンデーションの色を変更した場合でも、その変更は即座に行われます。しかし、アニメーション化されたグラフィックスが静止することはほとんどありません。ヒントは名前にあります。したがって、色がシステムの一部である場合、アニメーション化できない理由はありません。 基礎の色をアニメーション化するには、まず基礎の色を OKLCH チャンネルに分割する必要があります— 明度、彩度、色相。ただし、重要な追加手順があります。これらの値を型指定されたカスタム プロパティとして登録する必要があります。しかし、それは何を意味するのでしょうか? デフォルトでは、ブラウザーは CSS カスタム プロパティ値が色、長さ、数値、またはその他のものを完全に表しているかどうかを知りません。これは多くの場合、アニメーション中にスムーズに補間できず、ある値から次の値にジャンプすることを意味します。 カスタム プロパティを登録すると、それが表す値のタイプと、それが時間の経過とともにどのように動作するかがブラウザーに通知されます。この場合、ブラウザでカラー チャネルを数値として処理して、スムーズにアニメーション化できるようにしたいと考えています。 @プロパティ --f-l { 構文: "<数値>"; 継承: true; 初期値: 0.40; }
@プロパティ --f-c { 構文: "<数値>"; 継承: true; 初期値: 0.11; }
@プロパティ --f-h { 構文: "<数値>"; 継承: true; 初期値: 305; }
登録されると、これらのカスタム プロパティはネイティブ CSS のように動作します。ブラウザはフレームごとにそれらを補間できます。次に、これらのチャネルから基礎カラーを再構築します。 --foundation: oklch(var(--f-l) var(--f-c) var(--f-h));
これにより、他の数値と同様に、基礎の色がアニメーション化可能になります。これは、時間の経過とともに明るさを緩やかに変化させる、シンプルな「呼吸」アニメーションです。 @keyframes 呼吸 { 0%、100% { --f-l: 0.36; } 50% { --f-l: 0.46; } }
.トゥーンタイトル { アニメーション: 10 秒呼吸すると、イーズインアウトが無限になります。 }
塗りつぶし、グラデーション、ストロークの他のすべての色は --foundation から派生するため、それらはすべて一緒にアニメーション化し、手動で更新する必要はありません。 1 つのアニメーション色、多数の効果 このプロセスの開始時に、CSS の相対カラー値を使用すると、より多くの可能性を提供できると同時に実装が簡単になるのではないかと考えました。最近、Web サイトの連絡先ページに新しい金鉱の背景を追加しました。最初の反復には、光ったり揺れたりする石油ランプが含まれていました。
私は、CSS の相対カラーをアニメーション化して、鉱山の内部をランプの色で着色することで、どのようにしてより現実的なものにすることができるかを探りたかったのです。本物の光と同じように、周囲の世界に影響を与えたいと考えました。そこで、複数の色をアニメーション化するのではなく、1 つの色だけをアニメーション化する小さな照明システムを構築しました。
私の最初のタスクは、背景とランプの間にオーバーレイ レイヤーを挿入することでした。 <パス id="オーバーレイ" fill="var(--overlay-tint)" [...] style="ミックスブレンドモード:カラー" />
mix-blend-mode: color を使用したのは、下にある輝度を維持しながらその下にあるものに色合いを付けるためです。アニメーションがオンになっている場合にのみオーバーレイを表示したいので、オーバーレイをオプトインにしました。 .svg-mine #overlay { 表示: なし。 }
@media (reduced-motion を優先: 優先なし) { .svg-mine[data-animations=on] #overlay { 表示: ブロック; 不透明度: 0.5; } }
オーバーレイは所定の位置にありましたが、まだランプに接続されていませんでした。光源が必要でした。私のランプはシンプルで、それぞれにフィルターでぼかした円の要素が含まれています。このフィルターは、円全体に非常に柔らかいぼかしを生成します。
オーバーレイとランプを個別にアニメーション化するのではなく、単一の「炎」カラー トークンをアニメーション化して、そこから他のすべてを派生させます。まず、OKLCH チャネルの 3 つの型指定されたカスタム プロパティを登録します。 @プロパティ --fl-l { 構文: "<数値>"; 継承: true; 初期値: 0.86; } @プロパティ --fl-c { 構文: "<数値>"; 継承: true; 初期値: 0.12; } @プロパティ --fl-h { 構文: "<数値>"; 継承: true; 初期値: 95; }
これらのチャンネルをアニメーション化して、意図的に数フレームをオレンジ色に近づけて、ちらつきが明らかに火の光のように見えるようにしました。
@keyframes 炎 { 0%、100% { --fl-l: 0.86; --fl-c: 0.12; --fl-h: 95; } 6% { --fl-l: 0.91; --fl-c: 0.10; --fl-h: 92; } 12% { --fl-l: 0.83; --fl-c: 0.14; --fl-h: 100; } 18% { --fl-l: 0.88; --fl-c: 0.11; --fl-h: 94; } 24% { --fl-l: 0.82; --fl-c: 0.16; --fl-h: 82; } 30% { --fl-l: 0.90; --fl-c: 0.12; --fl-h: 90; } 36% { --fl-l: 0.79; --fl-c: 0.17; --fl-h: 76; } 44% { --fl-l: 0.87; --fl-c: 0.12; --fl-h: 96; } 52% { --fl-l: 0.81; --fl-c: 0.15; --fl-h: 102; } 60% { --fl-l: 0.89; --fl-c: 0.11; --fl-h: 93; } 68% { --fl-l: 0.83; --fl-c: 0.16; --fl-h: 85; } 76% { --fl-l: 0.91; --fl-c: 0.10; --fl-h: 91; } 84% { --fl-l: 0.85; --fl-c: 0.14; --fl-h: 98; } 92% {--fl-l: 0.80; --fl-c: 0.17; --fl-h: 74; } }
次に、そのアニメーションのスコープを SVG に設定し、ランプとオーバーレイの両方で共有変数を利用できるようにしました。
@media (reduced-motion を優先: 優先なし) { .svg-mine[data-animations=on] { アニメーション: 炎 3.6 秒無限リニア; 隔離:隔離する。
/* アニメーションチャンネルから炎の色を構築します */ --flame: oklch(var(--fl-l) var(--fl-c) var(--fl-h));
/* 炎から派生したランプの色 */ --lamp-core: oklch(from var(--flame) calc(l + 0.05) calc(c * 0.70) h);
/* 同じ炎から派生したオーバーレイの色合い */ --overlay-tint: oklch(var(--flame) から 計算(l + 0.06) 計算(c * 0.65) 計算(h - 10)); } }
最後に、これらの派生カラーを白熱ランプとそれらが影響するオーバーレイに適用しました。 @media (reduced-motion を優先: 優先なし) { .svg-mine[data-animations=on] #mine-lamp-1 > 円、 .svg-mine[data-animations=on] #mine-lamp-2 > サークル { 塗りつぶし: var(--lamp-core); }
.svg-mine[data-animations=on] #overlay { 表示: ブロック; 塗りつぶし: var(--overlay-tint); 不透明度: 0.5; } }
炎がオレンジ色に変わると、ランプが温まり、シーンも一緒に温まります。炎が冷めると、すべてが落ち着きます。最も良い点は、手動で何も書かれていないことです。基礎の色を変更したり、炎のアニメーション範囲を微調整したりすると、照明システム全体が同時に更新されます。 最終結果は私のウェブサイトでご覧いただけます。 再利用、再利用、再訪 ハンナ・バーベラのアニメーターたちは、必要に迫られて要素を再利用することを余儀なくされましたが、私は色を再利用することで、作品の一貫性が高まり、メンテナンスが容易になるからです。 CSS 相対カラー値により、次のことが可能になります。
単一のファンデーションカラーを定義し、 他の色がどのように関係しているかを説明し、 それらの関係をあらゆる場所で再利用し、 1 つの値を変更することでシステムをアニメーション化します。
相対色はテーマ設定を容易にするだけではありません。これは、動きと同様に色も意図的であり、1 つの値を変更するだけで、その下にある作業を書き直すことなくシーン全体を変換できるという考え方を奨励します。