我最近用一個新主題和一組先鋒角色刷新了我網站上的動畫圖形,將我在本系列中分享的大量技術付諸實踐。當有人與我的一些動畫互動或在一天中的不同時間時,我的一些動畫會改變外觀。
我的部落格頁面頂部圖形的顏色每天從早到晚都會變化。然後是雪模式,它透過覆蓋層和混合模式添加寒冷的顏色和冬季主題。
在研究這個問題時,我開始想知道 CSS 相對顏色值是否可以給我更多的控制權,同時也簡化過程。 注意:在本教程中,我將重點介紹用於主題圖形和動畫的相對顏色值和 OKLCH 顏色空間。如果您想深入了解相對顏色,Ahmad Shadeed 創建了一個出色的互動式指南。至於色彩空間、色域和 OKLCH,我們自己的 Geoff Graham 寫過相關內容。
重複使用元素是關鍵。盡可能重複使用背景,透過縮放和疊加幫助從同一藝術品建立新場景。它是出於必要而誕生的,但它也鼓勵從系列而不是單一場景的角度進行思考。 手動更新調色盤的問題 讓我們直接面對我的挑戰。在像這樣的卡通標題中(基於 1959 年 Yogi Bear Show 劇集“Lullabye-Bye Bear”)以及我的一般作品,調色板僅限於精選的幾種顏色。
我用我所謂的“基礎”顏色創建陰影和色調,以擴展調色板而不添加更多色調。
在 Sketch 中,我在 HSL 色彩空間中工作,因此此過程涉及增加或減少基礎顏色的亮度值。老實說,這不是一項艱鉅的任務,但選擇不同的底色需要創造一套全新的色調和色調。一次又一次手動執行此操作很快就會變得很費力。
我提到了 HSL——H(色調)、S(飽和度)和 L(亮度)——色彩空間,但這只是描述顏色的幾種方法之一。 RGB——R(紅色)、G(綠色)、B(藍色)——可能是最熟悉的,至少是其十六進位形式。 還有 LAB — L(亮度)、A(綠-紅)、B(藍-黃) — 以及較新但現在廣泛支持的 LCH — L(亮度)、C(色度)、H(色調) — OKLCH 形式的模型。使用 LCH(特別是 CSS 中的 OKLCH),我可以調整基礎顏色的亮度值。
或者我可以改變它的色度。 LCH 色度和 HSL 飽和度都描述顏色的強度或豐富度,但它們的描述方式不同。 LCH 為我提供了更廣泛、更可預測的顏色混合。
我還可以更改色調以創建具有相同亮度和色度值的調色板。在 HSL 和 LCH 中,色調光譜從紅色開始,經過綠色和藍色,最後回到紅色。
為什麼 OKLCH 改變了我對顏色的看法 儘管包括 Sketch 在內的設計工具尚未跟上,但瀏覽器對 OKLCH 色彩空間的支援現已廣泛普及。幸運的是,這不會阻止您使用 OKLCH。瀏覽器會很樂意為您將 Hex、HSL、LAB 和 RGB 值轉換為 OKLCH。您可以在任何空間(包括十六進位)中定義具有基礎顏色的 CSS 自訂屬性: /* 基礎顏色 */ --基礎:#5accd6;
從它派生的任何顏色都會自動轉換為 OKLCH: --foundation-light: oklch(來自 var(--foundation) [...]; } --foundation-mid: oklch(來自 var(--foundation) [...]; } --foundation-dark: oklch(來自 var(--foundation) [...]; }
相對顏色作為設計系統 將相對顏色想像為:「採用這種顏色,調整它,然後給我結果。」調整顏色有兩種方法:絕對變化和比例變化。它們在程式碼中看起來很相似,但一旦開始交換基礎顏色,它們的行為就會非常不同。了解這種差異可以將相對顏色轉變為一個系統。 /* 基礎顏色 */ --基礎:#5accd6;
例如,我的底色的亮度值為 0.7837,而較暗版本的值為 0.5837。為了計算差異,我用較高的值減去較低的值,然後使用 calc() 函數應用結果: --基礎-黑暗: oklch(來自 var(--foundation) 計算(l - 0.20) c h);
為了獲得更淺的顏色,我添加了差異: --基礎光: oklch(來自 var(--foundation) 計算(l + 0.10) c h);
色度調整遵循相同的過程。為了將基礎顏色的強度從 0.1035 降低到 0.0035,我從另一個值中減去一個值: oklch(來自 var(--foundation) l 計算(c - 0.10) h);
為了創建色調調色板,我計算了基礎顏色 (200) 和新色調 (260) 的色調值之間的差異: oklch(來自 var(--foundation) l c 計算(h + 60));
這些計算是絕對的。當我減去一個固定的金額時,我實際上是在說:「總是減去這麼多。」添加固定值時也是如此: 計算(c - 0.10) 計算(c + 0.10)
我經歷了慘痛的教訓才認識到這種方法的局限性。當我依靠減去固定色度值時,一旦我改變了基礎,顏色就會變成灰色。適用於一種顏色的調色板不適用於另一種顏色。 乘法的行為有所不同。當我乘以色度時,我告訴瀏覽器:「以一定比例降低該顏色的強度。」即使基礎發生變化,顏色之間的關係也保持不變: 計算(c * 0.10)
我的移動、縮放、旋轉規則
移動亮度(加或減), 縮放色度(乘法), 旋轉色調(增加或減少度數)。
我縮放色度是因為我希望強度變化與基色保持成比例。色調關係是旋轉的,因此相乘色調沒有意義。亮度是感性的、絕對的——乘以它常常會產生奇怪的結果。
從一種顏色到整個主題 相對顏色可讓我定義基礎顏色並從中產生我需要的所有其他顏色 - 填滿、描邊、漸層停止、陰影。到那時,顏色不再是調色板,而是開始成為一個系統。 SVG 插圖傾向於在填滿、描邊和漸層中重複使用相同的幾種顏色。相對顏色讓您可以一次定義這些關係,然後在任何地方重複使用它們,就像動畫師重複使用背景來創建新場景一樣。
更改基礎顏色一次,每種派生顏色都會自動更新,無需手動重新計算任何內容。除了動畫圖形之外,我還可以使用相同的方法來定義互動元素(例如按鈕和連結)的狀態顏色。 我在“Lullabye-Bye Bear”卡通標題中使用的底色是青色的藍色。背景是我的粉底和較暗版本之間的徑向漸層。
要創建具有完全不同心情的替代版本,我只需要更改基礎顏色: --基礎:#5accd6; --grad-end: var(--基礎); --grad-start: oklch(來自 var(--foundation) 計算(l - 0.2357)計算(c * 0.833)h);
為了將這些自訂屬性綁定到我的 SVG 漸層而不重複顏色值,我用內嵌樣式取代了硬編碼的停止顏色值:
<定義>
<路徑 fill="url(#bg-grad)" fill="#5DCDD8" d="[...]"/>
接下來,我需要確保我的卡通文字始終與我選擇的任何底色形成對比。 180 度的色調旋轉會產生一種肯定會流行的互補色,但會產生令人不舒服的振動: .text-light { 填充:oklch(來自 var(--foundation) l c 計算(h + 180)); }
90° 偏移會產生生動的二次色,但不會完全互補: .text-light { 填充:oklch(來自 var(--foundation) l c 計算(h - 90)); }
我對 Quick Draw McGraw 1959 年的卡通標題“El Kabong”的重新製作使用了相同的技術,但調色板更加多樣化。例如,基礎顏色和較深的色調之間還有另一個徑向漸層。
背景中的建築物和樹木只是相同基礎顏色的不同深度。對於這些路徑,我需要兩種額外的填滿顏色: .bg-mid { 填充:oklch(來自 var(--foundation) 計算(l - 0.04)計算(c * 0.91)h); }
.bg-暗{ 填充:oklch(來自 var(--foundation) 計算(l - 0.12)計算(c * 0.64)h); }
當基礎開始移動時 到目前為止,我展示的所有內容都是靜態的。即使有人使用顏色選擇器來更改基礎顏色,這種變化也會立即發生。但動畫圖形很少是靜止不動的——線索就在名字裡。因此,如果顏色是系統的一部分,那麼它也沒有理由不能設定動畫。 要對基礎顏色進行動畫處理,我首先需要將其拆分為 OKLCH 通道— 亮度、色度和色調。但還有一個重要的額外步驟:我需要將這些值註冊為類型化自訂屬性。但這意味著什麼? 預設情況下,瀏覽器不知道 CSS 自訂屬性值是否表示顏色、長度、數字或完全其他內容。這通常意味著它們無法在動畫過程中順利插值,並且無法從一個值跳到下一個值。 註冊自訂屬性會告訴瀏覽器它所代表的值的類型以及它隨著時間的推移應該如何表現。在這種情況下,我希望瀏覽器將我的顏色通道視為數字,以便它們可以順利地進行動畫處理。 @property --f-l { 語法:“<數字>”; 繼承:真實; 初始值:0.40; }
@屬性--f-c { 語法:“<數字>”; 繼承:真實; 初始值:0.11; }
@property --f-h { 語法:“<數字>”; 繼承:真實; 初始值: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; } }
.toon-標題 { 動畫:呼吸 10 秒,緩入無限; }
因為填滿、漸層和描邊中的所有其他顏色都源自 --foundation,所以它們都一起進行動畫處理,並且不需要手動更新任何內容。 一種動畫顏色,多種效果 在這個過程開始時,我想知道 CSS 相對顏色值是否可以提供更多可能性,同時也讓它們更容易實現。我最近在網站的聯絡頁面上新增了一個新的金礦背景,第一個迭代包括發光和擺動的油燈。
我想探索動畫 CSS 相對顏色如何透過燈的顏色著色來使礦井內部更加真實。我希望它們能夠像真實的光一樣影響周圍的世界。因此,我沒有建立多種顏色的動畫,而是建立了一個僅對一種顏色進行動畫處理的小型照明系統。
我的第一個任務是在背景和燈之間放置一個覆蓋層: <路徑 id=“覆蓋” 填充=“var(--overlay-tint)” [...] 樣式=“混合混合模式:顏色” />
我使用 mix-blend-mode: color 因為它可以對下面的內容進行著色,同時保留底層的亮度。由於我只希望在動畫開啟時疊加層可見,因此我選擇了疊加層: .svg-mine #overlay { 顯示:無; }
@media(更喜歡減少運動:無偏好){ .svg-mine[data-animations=on] #overlay { 顯示:塊; 不透明度:0.5; } }
覆蓋層已就位,但尚未連接到燈。我需要一個光源。我的燈很簡單,每個燈都包含一個圓形元素,我用濾鏡模糊了它。濾鏡在整個圓圈上產生非常柔和的模糊效果。
<過濾器id =“lamp-glow-1”x =“-120%”y =“-120%”寬度=“340%”高度=“340%”>
我沒有分別對覆蓋層和燈進行動畫處理,而是對單個“火焰”顏色標記進行動畫處理,並從中導出其他所有內容。首先,我為 OKLCH 通道註冊三個類型化的自訂屬性: @property --fl-l { 語法:“<數字>”; 繼承:真實; 初始值:0.86; } @property --fl-c { 語法:“<數字>”; 繼承:真實; 初始值:0.12; } @property --fl-h { 語法:“<數字>”; 繼承:真實; 初始值: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(更喜歡減少運動:無偏好){ .svg-mine[資料動畫=on] { 動畫:火焰3.6s無限線性; 隔離的英文
/* 從動畫通道建立火焰顏色 */ --flame: oklch(var(--fl-l) var(--fl-c) var(--fl-h));
/* 燈的顏色源自於火焰 */ --lamp-core: oklch(來自 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(更喜歡減少運動:無偏好){ .svg-mine[data-animations=on] #mine-lamp-1 > 圓圈, .svg-mine[data-animations=on] #mine-lamp-2 > 圓 { 填充:var(--燈芯); }
.svg-mine[data-animations=on] #overlay { 顯示:塊; 填充:var(--overlay-tint); 不透明度:0.5; } }
當火焰變成橘色時,燈就會變暖,場景也會隨之變暖。當火焰冷卻時,一切都會安定下來。最好的部分是沒有任何內容是手動編寫的。如果我更改基礎顏色或調整火焰動畫範圍,整個照明系統會同時更新。 你可以在我的網站上看到最終結果。 重複使用、改變用途、重新審視 那些漢納-巴伯拉動畫師出於必要而被迫重新調整元素的用途,但我重複使用顏色,因為它使我的作品更加一致且更易於維護。 CSS 相對顏色值允許我:
定義單一基礎顏色, 描述其他顏色與它的關係, 到處重複使用這些關係,並且 透過更改一個值來動畫系統。
相對顏色不僅使主題更容易。它鼓勵一種思維方式,其中顏色就像運動一樣是有意為之的,並且改變一個值可以改變整個場景,而無需重寫其下面的工作。