{"id":1146,"date":"2026-01-14T09:00:00","date_gmt":"2026-01-14T10:00:00","guid":{"rendered":"https:\/\/computercoursesonline.com\/?p=1146"},"modified":"2026-01-15T23:15:45","modified_gmt":"2026-01-15T23:15:45","slug":"smashing-animations-part-8-theming-animations-using-css-relative-colour","status":"publish","type":"post","link":"https:\/\/computercoursesonline.com\/index.php\/2026\/01\/14\/smashing-animations-part-8-theming-animations-using-css-relative-colour\/","title":{"rendered":"Smashing Animations Part 8: Theming Animations Using CSS Relative Colour"},"content":{"rendered":"

Smashing Animations Part 8: Theming Animations Using CSS Relative Colour<\/title><\/p>\n<article>\n<header>\n<h1>Smashing Animations Part 8: Theming Animations Using CSS Relative Colour<\/h1>\n<address>Andy Clarke<\/address>\n<p> 2026-01-14T10:00:00+00:00<br \/>\n 2026-01-15T23:02:56+00:00<br \/>\n <\/header>\n<p>I\u2019ve recently refreshed the animated graphics on <a href=\"https:\/\/stuffandnonsense.co.uk\/\">my website<\/a> with a new theme and a group of pioneering characters, putting into practice plenty of the techniques I shared in <a href=\"https:\/\/www.smashingmagazine.com\/author\/andy-clarke\/\">this series<\/a>. A few of my animations change appearance when someone interacts with them or at different times of day.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/stuffandnonsense.co.uk\/blog\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"341\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Graphics from Andy\u2019s website\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/1-andy-website-animated-graphics.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n View this animated SVG on <a href=\"https:\/\/stuffandnonsense.co.uk\/blog\">my website<\/a>. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/1-andy-website-animated-graphics.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>The colours in the graphic atop <a href=\"https:\/\/stuffandnonsense.co.uk\/blog\">my blog pages<\/a> change from morning until night every day. Then, there\u2019s the <a href=\"https:\/\/stuffandnonsense.co.uk\/blog\/let-it-snow\">snow mode<\/a>, which adds chilly colours and a wintery theme, courtesy of an overlay layer and a blending mode.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/2-snow-mode.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"359\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Snow mode applied to the town background\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/2-snow-mode.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Snow mode allows my pioneer town background to adapt throughout the day. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/2-snow-mode.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>While working on this, I started to wonder whether CSS relative colour values could give me more control while also simplifying the process.<\/p>\n<p><strong>Note<\/strong>: <em>In this tutorial, I\u2019ll focus on relative colour values and the OKLCH colour space for theming graphics and animations. If you want to dive deep into relative colour, Ahmad Shadeed created a superb <a href=\"https:\/\/ishadeed.com\/article\/css-relative-colors\/\">interactive guide<\/a>. As for colour spaces, gamuts, and OKLCH, our own Geoff Graham <a href=\"https:\/\/www.smashingmagazine.com\/2023\/08\/oklch-color-spaces-gamuts-css\/\">wrote<\/a> about them.<\/em><\/p>\n<div class=\"refs\">\n<ul>\n<li><a href=\"https:\/\/www.smashingmagazine.com\/2025\/05\/smashing-animations-part-1-classic-cartoons-inspire-css\/\"><strong>Smashing Animations Part 1<\/strong>: How Classic Cartoons Inspire Modern CSS<\/a><\/li>\n<li><a href=\"https:\/\/www.smashingmagazine.com\/2025\/05\/smashing-animations-part-2-css-masking-add-extra-dimension\/\"><strong>Smashing Animations Part 2<\/strong>: How CSS Masking Can Add An Extra Dimension<\/a><\/li>\n<li><a href=\"https:\/\/www.smashingmagazine.com\/2025\/05\/smashing-animations-part-3-smil-not-dead\/\"><strong>Smashing Animations Part 3<\/strong>: SMIL\u2019s Not Dead Baby, SMIL\u2019s Not Dead<\/a><\/li>\n<li><a href=\"https:\/\/www.smashingmagazine.com\/2025\/06\/smashing-animations-part-4-optimising-svgs\/\"><strong>Smashing Animations Part 4<\/strong>: Optimising SVGs<\/a><\/li>\n<li><a href=\"https:\/\/www.smashingmagazine.com\/2025\/10\/smashing-animations-part-5-building-adaptive-svgs\/\"><strong>Smashing Animations Part 5<\/strong>: Building Adaptive SVGs With <code><symbol><\/code>, <code><use><\/code>, And CSS Media Queries<\/a><\/li>\n<li><a href=\"https:\/\/www.smashingmagazine.com\/2025\/11\/smashing-animations-part-6-svgs-css-custom-properties\/\"><strong>Smashing Animations Part 6<\/strong>: Magnificent SVGs With <code><use><\/code> And CSS Custom Properties<\/a><\/li>\n<li><a href=\"https:\/\/www.smashingmagazine.com\/2025\/12\/smashing-animations-part-7-recreating-toon-text-css-svg\/\"><strong>Smashing Animations Part 7<\/strong>: Recreating Toon Text With CSS And SVG<\/a><\/li>\n<\/ul>\n<\/div>\n<div data-audience=\"non-subscriber\" data-remove=\"true\" class=\"feature-panel-container\">\n<aside class=\"feature-panel\">\n<div class=\"feature-panel-left-col\">\n<div class=\"feature-panel-description\">\n<p>Meet <strong><a data-instant href=\"https:\/\/www.smashingconf.com\/online-workshops\/\">Smashing Workshops<\/a><\/strong> on <strong>front-end, design & UX<\/strong>, with practical takeaways, live sessions, <strong>video recordings<\/strong> and a friendly Q&A. With Brad Frost, St\u00e9ph Walter and <a href=\"https:\/\/smashingconf.com\/online-workshops\/workshops\">so many others<\/a>.<\/p>\n<p><a data-instant href=\"smashing-workshops\" class=\"btn btn--green btn--large\">Jump to the workshops \u21ac<\/a><\/div>\n<\/div>\n<div class=\"feature-panel-right-col\"><a data-instant href=\"smashing-workshops\" class=\"feature-panel-image-link\"><\/p>\n<div class=\"feature-panel-image\">\n<img loading=\"lazy\" class=\"feature-panel-image-img lazyload\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Feature Panel\" width=\"257\" height=\"355\" data-src=\"\/images\/smashing-cat\/cat-scubadiving-panel.svg\"><\/p>\n<\/div>\n<p><\/a>\n<\/div>\n<\/aside>\n<\/div>\n<h2 id=\"how-cartoon-animation-taught-me-to-reuse-everything\">How Cartoon Animation Taught Me To Reuse Everything<\/h2>\n<p>The <a href=\"https:\/\/en.wikipedia.org\/wiki\/Hanna-Barbera\">Hanna-Barbera<\/a> animated series I grew up watching had budgets far lower than those available when William Hanna and Joseph Barbera produced <em>Tom and Jerry<\/em> shorts at MGM Cartoons. This meant the animators needed to develop techniques to work around their cost restrictions.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/3-yogi-bear-show.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"196\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Repeated use of elements in the Yogi Bear Show\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/3-yogi-bear-show.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n The Yogi Bear Show, copyright Warner Bros. Entertainment Inc. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/3-yogi-bear-show.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>Repeated use of elements was key. Backgrounds were reused whenever possible, with zooms and overlays helping construct new scenes from the same artwork. It was born of necessity, but it also encouraged thinking in terms of series rather than individual scenes.<\/p>\n<h2 id=\"the-problem-with-manually-updating-colour-palettes\">The problem With Manually Updating Colour Palettes<\/h2>\n<p>Let\u2019s get straight to my challenge. In Toon Titles like this one — based on the 1959 Yogi Bear Show episode \u201cLullabye-Bye Bear\u201d — and my work generally, palettes are limited to a select few colours.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/4-yogi-bear.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"450\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Illustration of Yogi Bear asleep in a hammock tied between two thin, white trees. Andy Clarke\u2019s Toon Titles is displayed above Yogi in cartoon-style typography.\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/4-yogi-bear.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n View this on my <a href=\"https:\/\/stuffandnonsense.co.uk\/toon-titles\/24b.html\">Toon Titles website<\/a>. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/4-yogi-bear.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>I create shades and tints from what I call my \u201cfoundation\u201d colour to expand the palette without adding more hues.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/5-colour-palette.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"450\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Colour palette of a foundation colour\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/5-colour-palette.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Colour palette with shades and tints of a foundation colour. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/5-colour-palette.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>In <a href=\"https:\/\/www.sketch.com\">Sketch<\/a>, I work in the <a href=\"https:\/\/www.smashingmagazine.com\/2021\/07\/hsl-colors-css\/\">HSL colour space<\/a>, so this process involves increasing or decreasing the lightness value of my foundation colour. Honestly, it\u2019s not an arduous task — but choosing a different foundation colour requires creating a whole new set of shades and tints. Doing that manually, again and again, quickly becomes laborious.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/6-foundation-colour.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"450\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Shades and tints of a different foundation colour.\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/6-foundation-colour.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Shades and tints of a different foundation colour. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/6-foundation-colour.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>I mentioned the HSL — <strong>H<\/strong> (hue), S (saturation), and <strong>L<\/strong> (lightness) — colour space, but that\u2019s just one of several ways to describe colour.<\/p>\n<p>RGB — <strong>R<\/strong> (red), <strong>G<\/strong> (green), <strong>B<\/strong> (blue) — is probably the most familiar, at least in its Hex form.<\/p>\n<p>There\u2019s also LAB — <strong>L<\/strong> (lightness), <strong>A<\/strong> (green\u2013red), <strong>B<\/strong> (blue\u2013yellow) — and the newer, but now widely supported LCH — <strong>L<\/strong> (lightness), <strong>C<\/strong> (chroma), <strong>H<\/strong> (hue) — model in its OKLCH form. With LCH — specifically OKLCH in CSS — I can adjust the lightness value of my foundation colour.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/7-lightness-change-foundation-colour.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"334\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Lightness changes to the foundation colour.\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/7-lightness-change-foundation-colour.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Lightness changes to my foundation colour. Chroma and Hue remain the same. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/7-lightness-change-foundation-colour.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>Or I can alter its <em>chroma<\/em>. LCH chroma and HSL saturation both describe the intensity or richness of a colour, but they do so in different ways. LCH gives me a wider range and more predictable blending between colours.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/8-chroma-changes-foundation-colour.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"334\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Chroma changes to the foundation colour\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/8-chroma-changes-foundation-colour.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Chroma changes to my foundation colour. Lightness and Hue remain the same. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/8-chroma-changes-foundation-colour.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>I can also alter the hue to create a palette of colours that share the same lightness and chroma values. In both HSL and LCH, the hue spectrum starts at red, moves through green and blue, and returns to red.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/9-hue-changes-foundation-colour.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"334\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Hue changes to the foundation colour.\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/9-hue-changes-foundation-colour.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Hue changes to my foundation colour. Lightness and Chrome remain the same. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/9-hue-changes-foundation-colour.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<h2 id=\"why-oklch-changed-how-i-think-about-colour\">Why OKLCH Changed How I Think About Colour<\/h2>\n<p>Browser support for the OKLCH colour space <a href=\"https:\/\/caniuse.com\/wf-oklab\">is now widespread<\/a>, even if design tools — including Sketch — haven\u2019t caught up. Fortunately, that shouldn\u2019t stop you from using OKLCH. Browsers will happily convert Hex, HSL, LAB, and RGB values into OKLCH for you. You can define a CSS custom property with a foundation colour in any space, including Hex:<\/p>\n<pre><code class=\"language-css\">\/* Foundation colour *\/\n--foundation: #5accd6;\n<\/code><\/pre>\n<p>Any colours derived from it will be converted into OKLCH automatically:<\/p>\n<pre><code class=\"language-css\">--foundation-light: oklch(from var(--foundation) [...]; }\n--foundation-mid: oklch(from var(--foundation) [...]; }\n--foundation-dark: oklch(from var(--foundation) [...]; }\n<\/code><\/pre>\n<h2 id=\"relative-colour-as-a-design-system\">Relative Colour As A Design System<\/h2>\n<p>Think of relative colour as saying: <em>\u201cTake this colour, tweak it, then give me the result.\u201d<\/em> There are two ways to adjust a colour: absolute changes and proportional changes. They look similar in code, but behave very differently once you start swapping foundation colours. Understanding that difference is what can turn using relative colour into a system.<\/p>\n<pre><code class=\"language-css\">\/* Foundation colour *\/\n--foundation: #5accd6;\n<\/code><\/pre>\n<p>For example, the lightness value of my foundation colour is <code>0.7837<\/code>, while a darker version has a value of <code>0.5837<\/code>. To calculate the difference, I subtract the lower value from the higher one and apply the result using a <code>calc()<\/code> function:<\/p>\n<pre><code class=\"language-css\">--foundation-dark: \n oklch(from var(--foundation)\n calc(l - 0.20) c h);\n<\/code><\/pre>\n<p>To achieve a lighter colour, I add the difference instead:<\/p>\n<pre><code class=\"language-css\">--foundation-light:\n oklch(from var(--foundation)\n calc(l + 0.10) c h);\n<\/code><\/pre>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/10-calculating-colour-difference.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"334\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Calculations of the difference between the foundation colour and Lightness, Chroma, and Hue-adjusted colours.\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/10-calculating-colour-difference.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Calculating the difference between my foundation colour and Lightness, Chroma, and Hue-adjusted colours. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/10-calculating-colour-difference.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>Chroma adjustments follow the same process. To reduce the intensity of my foundation colour from <code>0.1035<\/code> to <code>0.0035<\/code>, I subtract one value from the other:<\/p>\n<pre><code class=\"language-css\">oklch(from var(--foundation)\nl calc(c - 0.10) h);\n<\/code><\/pre>\n<p>To create a palette of hues, I calculate the difference between the hue value of my foundation colour (<code>200<\/code>) and my new hue (<code>260<\/code>):<\/p>\n<pre><code class=\"language-css\">oklch(from var(--foundation)\nl c calc(h + 60));\n<\/code><\/pre>\n<p>Those calculations are absolute. When I subtract a fixed amount, I\u2019m effectively saying, <em>\u201cAlways subtract this much.\u201d<\/em> The same applies when adding fixed values:<\/p>\n<pre><code class=\"language-css\">calc(c - 0.10)\ncalc(c + 0.10)\n<\/code><\/pre>\n<p>I learned the limits of this approach the hard way. When I relied on subtracting fixed chroma values, colours collapsed towards grey as soon as I changed the foundation. A palette that worked for one colour fell apart for another.<\/p>\n<p>Multiplication behaves differently. When I multiply chroma, I\u2019m telling the browser: <em>\u201cReduce this colour\u2019s intensity by a proportion.\u201d<\/em> The relationship between colours remains intact, even when the foundation changes:<\/p>\n<pre><code class=\"language-css\">calc(c * 0.10)\n<\/code><\/pre>\n<div class=\"partners__lead-place\"><\/div>\n<h2 id=\"my-move-it-scale-it-rotate-it-rules\">My Move It, Scale It, Rotate It Rules<\/h2>\n<ul>\n<li><strong>Move<\/strong> lightness (add or subtract),<\/li>\n<li><strong>Scale<\/strong> chroma (multiply),<\/li>\n<li><strong>Rotate<\/strong> hue (add or subtract degrees).<\/li>\n<\/ul>\n<p>I scale chroma because I want intensity changes to stay proportional to the base colour. Hue relationships are rotational, so multiplying hue makes no sense. Lightness is perceptual and absolute — multiplying it often produces odd results.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/11-move-scale-rotate.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"334\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Lightness: Move it. Chroma: Scale it. Hue: Rotate it\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/11-move-scale-rotate.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Lightness: Move it. Chroma: Scale it. Hue: Rotate it. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/11-move-scale-rotate.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<h2 id=\"from-one-colour-to-an-entire-theme\">From One Colour To An Entire Theme<\/h2>\n<p>Relative colour allows me to define a foundation colour and generate every other colour I need — fills, strokes, gradient stops, shadows — from it. At that point, colour stops being a palette and starts being a system.<\/p>\n<blockquote><p>SVG illustrations tend to reuse the same few colours across fills, strokes, and gradients. Relative colour lets you define those relationships once and reuse them everywhere — much like animators reused backgrounds to create new scenes.<\/p><\/blockquote>\n<p>Change the foundation colour once, and every derived colour updates automatically, without recalculating anything by hand. Outside of animated graphics, I could use this same approach to define colours for the states of interactive elements such as buttons and links.<\/p>\n<p>The foundation colour I used in my \u201cLullabye-Bye Bear\u201d Toon Title is a cyan-looking blue. The background is a radial gradient between my foundation and a darker version.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/stuffandnonsense.co.uk\/toon-titles\/24b.html\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"450\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"\u201cLullabye-Bye Bear\u201d Toon Title\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/12-toon-titles-website.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n View this on my <a href=\"https:\/\/stuffandnonsense.co.uk\/toon-titles\/24b.html\">Toon Titles website<\/a>. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/12-toon-titles-website.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>To create alternative versions with entirely different moods, I only need to change the foundation colour:<\/p>\n<pre><code class=\"language-css\">--foundation: #5accd6;\n--grad-end: var(--foundation);\n--grad-start: oklch(from var(--foundation)\n calc(l - 0.2357) calc(c * 0.833) h);\n<\/code><\/pre>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/stuffandnonsense.co.uk\/toon-titles\/24b.html\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"171\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Three alternative versions of the \u201cLullabye-Bye Bear\u201d Toon Title\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/13-toon-titles-website.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Use the colour picker on my <a href=\"https:\/\/stuffandnonsense.co.uk\/toon-titles\/24b.html\">Toon Titles website<\/a> to see this in action. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/13-toon-titles-website.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>To bind those custom properties to my SVG gradient without duplicating colour values, I replaced hard-coded <code>stop-color<\/code> values with inline styles:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-svg\"><defs>\n <radialGradient id=\"bg-grad\" [\u2026]>\n <stop offset=\"0%\" style=\"stop-color: var(--grad-end);\" \/>\n <stop offset=\"100%\" style=\"stop-color: var(--grad-start);\" \/>\n <\/radialGradient>\n<\/defs>\n<\/code><\/pre>\n<\/div>\n<pre><code class=\"language-svg\"><path fill=\"url(#bg-grad)\" fill=\"#5DCDD8\" d=\"[...]\"\/>\n<\/code><\/pre>\n<p>Next, I needed to ensure that my <a href=\"https:\/\/stuffandnonsense.co.uk\/toon-text\/index.html\">Toon Text<\/a> always contrasts with whatever foundation colour I choose. A <code>180deg<\/code> hue rotation produces a complementary colour that certainly pops — but can vibrate uncomfortably:<\/p>\n<pre><code class=\"language-css\">.text-light {\n fill: oklch(from var(--foundation)\n l c calc(h + 180));\n}\n<\/code><\/pre>\n<p>A <code>90\u00b0<\/code> shift produces a vivid secondary colour without being fully complementary:<\/p>\n<pre><code class=\"language-css\">.text-light {\n fill: oklch(from var(--foundation)\n l c calc(h - 90));\n}\n<\/code><\/pre>\n<p>My recreation of Quick Draw McGraw\u2019s 1959 Toon Title \u201cEl Kabong\u201c uses the same techniques but with a more varied palette. For example, there\u2019s another radial gradient between the foundation colour and a darker shade.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/14-quick-draw-mcgraw.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"450\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"An animated still of Quick Draw McGraw swinging from a rope going from left to right against a purple gradient background. Andy Clarke\u2019s Toon Titles is displayed above him in cartoon-style typography. A silhouetted building and palm tree are positioned in the bottom-right corner.\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/14-quick-draw-mcgraw.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n View this on my <a href=\"https:\/\/stuffandnonsense.co.uk\/toon-titles\/quick-draw-4b.html\">Toon Titles website<\/a>. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/14-quick-draw-mcgraw.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/stuffandnonsense.co.uk\/toon-titles\/quick-draw-4b.html\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"167\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Three alternative versions of Quick Draw McGraw\u2019s 1959 Toon Title \u201cEl Kabong\u201c\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/15-quick-draw-mcgraw-toon-titles.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Use the colour picker on my <a href=\"https:\/\/stuffandnonsense.co.uk\/toon-titles\/quick-draw-4b.html\">Toon Titles website<\/a> to see this in action. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/15-quick-draw-mcgraw-toon-titles.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>The building and tree in the background are simply different shades of the same foundation colour. For those paths, I needed two additional <code>fill<\/code> colours:<\/p>\n<pre><code class=\"language-css\">.bg-mid {\n fill: oklch(from var(--foundation)\n calc(l - 0.04) calc(c * 0.91) h);\n}\n\n.bg-dark {\n fill: oklch(from var(--foundation)\n calc(l - 0.12) calc(c * 0.64) h);\n}\n<\/code><\/pre>\n<h2 id=\"when-the-foundations-start-to-move\">When The Foundations Start To Move<\/h2>\n<p>So far, everything I\u2019ve shown has been static. Even when someone uses a colour picker to change the foundation colour, that change happens instantly. But animated graphics rarely stand still — the clue is in the name. So, if colour is part of the system, there\u2019s no reason it can\u2019t animate, too.<\/p>\n<p>To animate the foundation colour, I first need to split it into its OKLCH channels — lightness, chroma, and hue. But there\u2019s an important extra step: I need to register those values as <em>typed<\/em> custom properties. But what does that mean?<\/p>\n<p>By default, a browser doesn\u2019t know whether a CSS custom property value represents a colour, length, number, or something else entirely. That often means <a href=\"https:\/\/css-tricks.com\/what-you-need-to-know-about-css-color-interpolation\/\">they can\u2019t be interpolated smoothly during animation<\/a>, and jump from one value to the next.<\/p>\n<p>Registering a custom property tells the browser the type of value it represents and how it should behave over time. In this case, I want the browser to treat my colour channels as numbers so they can be animated smoothly.<\/p>\n<pre><code class=\"language-css\">@property --f-l {\n syntax: \"<number>\";\n inherits: true;\n initial-value: 0.40;\n}\n\n@property --f-c {\n syntax: \"<number>\";\n inherits: true;\n initial-value: 0.11;\n}\n\n@property --f-h {\n syntax: \"<number>\";\n inherits: true;\n initial-value: 305;\n}\n<\/code><\/pre>\n<p>Once registered, these custom properties behave like native CSS. The browser can interpolate them frame-by-frame. I then rebuild the foundation colour from those channels:<\/p>\n<pre><code class=\"language-css\">--foundation: oklch(var(--f-l) var(--f-c) var(--f-h));\n<\/code><\/pre>\n<p>This makes the foundation colour become animatable, just like any other numeric value. Here\u2019s a simple \u201cbreathing\u201d animation that gently shifts lightness over time:<\/p>\n<pre><code class=\"language-css\">@keyframes breathe {\n 0%, 100% { --f-l: 0.36; }\n 50% { --f-l: 0.46; }\n}\n\n.toon-title {\n animation: breathe 10s ease-in-out infinite;\n}\n<\/code><\/pre>\n<p>Because every other colour in fills, gradients, and strokes is derived from <code>--foundation<\/code>, they all animate together, and nothing needs to be updated manually.<\/p>\n<div class=\"partners__lead-place\"><\/div>\n<h2 id=\"one-animated-colour-many-effects\">One Animated Colour, Many Effects<\/h2>\n<p>At the start of this process, I wondered whether CSS relative colour values could offer more possibilities while also making them simpler to implement. I recently added a new gold mine background to my website\u2019s <a href=\"https:\/\/stuffandnonsense.co.uk\/contact\">contact page<\/a>, and the first iteration included oil lamps that glow and swing.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/stuffandnonsense.co.uk\/contact\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"305\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"A group of seven illustrated western characters in an underground gold mine scene.\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/16-gold-mine-scene.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n View this animated SVG on <a href=\"https:\/\/stuffandnonsense.co.uk\/contact\">my website<\/a>. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/16-gold-mine-scene.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>I wanted to explore how animating CSS relative colours could make the mine interior more realistic by tinting it with colours from the lamps. I wanted them to affect the world around them, the way real light does. So, rather than animating multiple colours, I built a tiny lighting system that animates just one colour.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/17-overlay-layer-svg.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"305\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Overlay layer applied to the SVG\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/17-overlay-layer-svg.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Adding an overlay layer to my SVG. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/17-overlay-layer-svg.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>My first task was to slot an overlay layer between the background and my lamps:<\/p>\n<pre><code class=\"language-svg\"><path \n id=\"overlay\"\n fill=\"var(--overlay-tint)\" \n [...] \n style=\"mix-blend-mode: color\"\n\/>\n<\/code><\/pre>\n<p>I used <code>mix-blend-mode: color<\/code> because that tints what\u2019s beneath it while preserving the underlying luminance. As I only want the overlay to be visible when animations are turned on, I made the overlay opt-in:<\/p>\n<pre><code class=\"language-css\">.svg-mine #overlay {\n display: none;\n}\n \n@media (prefers-reduced-motion: no-preference) {\n .svg-mine[data-animations=on] #overlay {\n display: block;\n opacity: 0.5;\n }\n}\n<\/code><\/pre>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/18-overlay-gold-mine-scene.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"305\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"An overlay applied to the gold mine scene illuminates the background, making it brighter than the foreground.\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/18-overlay-gold-mine-scene.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n The overlay layer tints what\u2019s beneath it. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/18-overlay-gold-mine-scene.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>The overlay was in place, but not yet connected to the lamps. I needed a light source. My lamps are simple, and each one contains a <code>circle<\/code> element that I blurred with a filter. The <code>filter<\/code> produces a very soft blur over the entire circle.<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-svg\"><filter id=\"lamp-glow-1\" x=\"-120%\" y=\"-120%\" width=\"340%\" height=\"340%\">\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"56\"\/>\n<\/filter>\n<\/code><\/pre>\n<\/div>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/19-oil-lamps.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"305\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Added oil lamps to the gold mine scene\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/19-oil-lamps.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Adding oil lamps to my scene. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/19-oil-lamps.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>Instead of animating the overlay and lamps separately, I animate a single \u201cflame\u201d colour token and derive everything else from that. First, I register three typed custom properties for OKLCH channels:<\/p>\n<pre><code class=\"language-css\">@property --fl-l {\n syntax: \"<number>\"; \n inherits: true;\n initial-value: 0.86;\n}\n@property --fl-c {\n syntax: \"<number>\";\n inherits: true;\n initial-value: 0.12;\n}\n@property --fl-h {\n syntax: \"<number>\";\n inherits: true;\n initial-value: 95;\n}\n<\/code><\/pre>\n<p>I animated those channels, deliberately pushing a few frames towards orange so the flicker reads clearly as firelight:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-css\">@keyframes flame {\n 0%, 100% { --fl-l: 0.86; --fl-c: 0.12; --fl-h: 95; }\n 6% { --fl-l: 0.91; --fl-c: 0.10; --fl-h: 92; }\n 12% { --fl-l: 0.83; --fl-c: 0.14; --fl-h: 100; }\n 18% { --fl-l: 0.88; --fl-c: 0.11; --fl-h: 94; }\n 24% { --fl-l: 0.82; --fl-c: 0.16; --fl-h: 82; }\n 30% { --fl-l: 0.90; --fl-c: 0.12; --fl-h: 90; }\n 36% { --fl-l: 0.79; --fl-c: 0.17; --fl-h: 76; }\n 44% { --fl-l: 0.87; --fl-c: 0.12; --fl-h: 96; }\n 52% { --fl-l: 0.81; --fl-c: 0.15; --fl-h: 102; }\n 60% { --fl-l: 0.89; --fl-c: 0.11; --fl-h: 93; }\n 68% { --fl-l: 0.83; --fl-c: 0.16; --fl-h: 85; }\n 76% { --fl-l: 0.91; --fl-c: 0.10; --fl-h: 91; }\n 84% { --fl-l: 0.85; --fl-c: 0.14; --fl-h: 98; }\n 92% { --fl-l: 0.80; --fl-c: 0.17; --fl-h: 74; }\n}\n<\/code><\/pre>\n<\/div>\n<p>Then I scoped that animation to the SVG, so the shared variables are available to both the lamps and my overlay:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-css\">@media (prefers-reduced-motion: no-preference) {\n .svg-mine[data-animations=on] {\n animation: flame 3.6s infinite linear;\n isolation: isolate;\n\n \/* Build a flame colour from animated channels *\/\n --flame: oklch(var(--fl-l) var(--fl-c) var(--fl-h));\n\n \/* Lamp colour derived from flame *\/\n --lamp-core: oklch(from var(--flame) calc(l + 0.05) calc(c * 0.70) h);\n \n \/* Overlay tint derived from the same flame *\/\n --overlay-tint: oklch(from var(--flame)\n calc(l + 0.06) calc(c * 0.65) calc(h - 10));\n }\n}\n<\/code><\/pre>\n<\/div>\n<p>Finally, I applied those derived colours to the glowing lamps and the overlay they affect:<\/p>\n<pre><code class=\"language-css\">@media (prefers-reduced-motion: no-preference) {\n .svg-mine[data-animations=on] #mine-lamp-1 > circle,\n .svg-mine[data-animations=on] #mine-lamp-2 > circle {\n fill: var(--lamp-core);\n }\n \n .svg-mine[data-animations=on] #overlay {\n display: block;\n fill: var(--overlay-tint);\n opacity: 0.5;\n }\n}\n<\/code><\/pre>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/20-lamps-overlay-connected.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"305\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"The lamps and overlay are connected.\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/20-lamps-overlay-connected.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n The lamps and overlay are connected. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-8-css-relative-colour\/20-lamps-overlay-connected.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>When the flame shifts toward orange, the lamps warm up, and the scene warms with them. When the flame cools, everything settles together. The best part is that nothing is written manually. If I change the foundation colour or tweak the flame animation ranges, the entire lighting system updates simultaneously.<\/p>\n<p>You can see <a href=\"https:\/\/stuffandnonsense.co.uk\/contact\">the final result on my website<\/a>.<\/p>\n<h2 id=\"reuse-repurpose-revisited\">Reuse, Repurpose, Revisited<\/h2>\n<p>Those Hanna-Barbera animators were forced to repurpose elements out of necessity, but I reuse colours because it makes my work <strong>more consistent<\/strong> and <strong>easier to maintain<\/strong>. CSS relative colour values allow me to:<\/p>\n<ul>\n<li>Define a single foundation colour,<\/li>\n<li>Describe how other colours relate to it,<\/li>\n<li>Reuse those relationships everywhere, and<\/li>\n<li>Animate the system by changing one value.<\/li>\n<\/ul>\n<blockquote class=\"pull-quote\">\n<p>\n <a class=\"pull-quote__link\" aria-label=\"Share on Twitter\" href=\"https:\/\/twitter.com\/share?text=%0aRelative%20colour%20doesn%e2%80%99t%20just%20make%20theming%20easier.%20It%20encourages%20a%20way%20of%20thinking%20where%20colour,%20like%20motion,%20is%20intentional%20%e2%80%94%20and%20where%20changing%20one%20value%20can%20transform%20an%20entire%20scene%20without%20rewriting%20the%20work%20beneath%20it.%0a&url=https:\/\/smashingmagazine.com%2f2026%2f01%2fsmashing-animations-part-8-css-relative-colour%2f\"><\/p>\n<p>Relative colour doesn\u2019t just make theming easier. It encourages a way of thinking where colour, like motion, is intentional \u2014 and where changing one value can transform an entire scene without rewriting the work beneath it.<\/p>\n<p> <\/a>\n <\/p>\n<div class=\"pull-quote__quotation\">\n<div class=\"pull-quote__bg\">\n <span class=\"pull-quote__symbol\">\u201c<\/span><\/div>\n<\/p><\/div>\n<\/blockquote>\n<div class=\"signature\">\n <img src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Smashing Editorial\" width=\"35\" height=\"46\" loading=\"lazy\" class=\"lazyload\" data-src=\"https:\/\/www.smashingmagazine.com\/images\/logo\/logo--red.png\"><br \/>\n <span>(gg, yk)<\/span>\n<\/div>\n<\/article>\n","protected":false},"excerpt":{"rendered":"<p>Smashing Animations Part 8: Theming Animations Using CSS Relative Colour Smashing Animations Part 8: Theming Animations Using CSS Relative Colour Andy Clarke 2026-01-14T10:00:00+00:00 2026-01-15T23:02:56+00:00 I\u2019ve recently refreshed the animated graphics on my website with a new theme and a group of pioneering characters, putting into practice plenty of the techniques I shared in this series….<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[11],"tags":[],"_links":{"self":[{"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/posts\/1146"}],"collection":[{"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/comments?post=1146"}],"version-history":[{"count":1,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/posts\/1146\/revisions"}],"predecessor-version":[{"id":1147,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/posts\/1146\/revisions\/1147"}],"wp:attachment":[{"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/media?parent=1146"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/categories?post=1146"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/tags?post=1146"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}