{"id":3448,"date":"2024-08-12T13:38:35","date_gmt":"2024-08-12T18:38:35","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=3448"},"modified":"2024-08-14T12:25:38","modified_gmt":"2024-08-14T17:25:38","slug":"relative-color-syntax-basic-use-cases","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/relative-color-syntax-basic-use-cases\/","title":{"rendered":"Relative Color Syntax \u2014 Basic Use Cases"},"content":{"rendered":"\n<p>As of last month, Firefox 128&#8217;s support of the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/CSS_colors\/Relative_colors\">relative color syntax<\/a> means we&#8217;ve now got <a href=\"https:\/\/caniuse.com\/?search=relative%20color\">support across the board<\/a>. I&#8217;m excited about that as it&#8217;s an extremely powerful way to manipulate colors in CSS. Plus it was <a href=\"https:\/\/frontendmasters.com\/blog\/comparing-interop-2024-choices-to-the-popular-vote\/\">part of Interop<\/a> this year so that is further proof that is trucking along nicely.<\/p>\n\n\n\n<p>The syntax with generic names looks like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">color-function<\/span>(<span class=\"hljs-selector-tag\">from<\/span> <span class=\"hljs-selector-tag\">origin-color<\/span> <span class=\"hljs-selector-tag\">channel1<\/span> <span class=\"hljs-selector-tag\">channel2<\/span> <span class=\"hljs-selector-tag\">channel3<\/span> \/ <span class=\"hljs-selector-tag\">alpha<\/span>)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Here&#8217;s how it works in my head:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"597\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/08\/relative-color-syntax.png?resize=1024%2C597&#038;ssl=1\" alt=\"\" class=\"wp-image-3450\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/08\/relative-color-syntax.png?resize=1024%2C597&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/08\/relative-color-syntax.png?resize=300%2C175&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/08\/relative-color-syntax.png?resize=768%2C448&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/08\/relative-color-syntax.png?w=1417&amp;ssl=1 1417w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Add Opacity to a Color you Already Have<\/h2>\n\n\n\n<p>It&#8217;s common to have CSS custom properties set up for colors on a project. <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">html<\/span> {\n  <span class=\"hljs-attribute\">--color-yellow<\/span>: <span class=\"hljs-built_in\">oklch<\/span>(<span class=\"hljs-number\">80%<\/span> <span class=\"hljs-number\">0.15<\/span> <span class=\"hljs-number\">94<\/span>);\n  <span class=\"hljs-attribute\">--color-green<\/span>:  <span class=\"hljs-built_in\">oklch<\/span>(<span class=\"hljs-number\">70%<\/span> <span class=\"hljs-number\">0.25<\/span> <span class=\"hljs-number\">140<\/span>);\n\n  ...\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now you want to use that yellow, but at about 50% opacity. How do you do that? There are actually <a href=\"https:\/\/chriscoyier.net\/2023\/05\/12\/add-opacity-to-an-existing-color\/\">a couple of ways to add transparency to an existing color<\/a>, but in my opinion the relative color syntax is the nicest. <\/p>\n\n\n\n<p>In the past, I&#8217;ve split out the color values like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">html {\n  --color-yellow-lch: <span class=\"hljs-number\">80<\/span>% <span class=\"hljs-number\">0.15<\/span> <span class=\"hljs-number\">94<\/span>;\n  --color-yellow: oklch(<span class=\"hljs-keyword\">var<\/span>(--color-yellow-lch);\n\n  ...\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>That way I could either use the color all together, or use the split out values to apply opacity:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-selector-class\">.box<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-built_in\">var<\/span>(--color-yellow);\n<\/span><\/span><mark class='shcb-loc'><span>  <span class=\"hljs-attribute\">border-color<\/span>: <span class=\"hljs-built_in\">oklch<\/span>(var(--color-yellow-lch) \/ <span class=\"hljs-number\">50%<\/span>);\n<\/span><\/mark><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>But that can get out of hand! You could also split each color into L, C, and H, the combine those, giving you <em>five<\/em> variables for every color. Too much.<\/p>\n\n\n\n<p>With the relative color syntax, breaking down colors isn&#8217;t necessary. You apply alpha (and other transformations) on demand, leaving the original single color as the only variable (token) you need.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-selector-class\">.box<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-built_in\">var<\/span>(--color-yellow);\n<\/span><\/span><mark class='shcb-loc'><span>  <span class=\"hljs-attribute\">border-color<\/span>: <span class=\"hljs-built_in\">oklch<\/span>(from var(--color-yellow) l c h \/ <span class=\"hljs-number\">50%<\/span>); \n<\/span><\/mark><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>I much prefer the idea of keeping the main colors tokenized as custom properties, then tweaking them as needed on demand.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Darken a Color you Already Have<\/h2>\n\n\n\n<p>In the above example, we had <code>--color-yellow<\/code> and I ended by saying I prefer doing one-off tweaks on demand rather than making a whole new variable. If you have a <em>ton<\/em> of usage of a slightly-darker version of a color, then sure, make a new variable and stay consistent. But if it&#8217;s more of a one-off, relative color syntax is awesome:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table\"><span class='shcb-loc'><span>.box {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">background<\/span>: <span class=\"hljs-keyword\">var<\/span>(--gray<span class=\"hljs-number\">-5<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  h2 {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">color<\/span>: <span class=\"hljs-keyword\">var<\/span>(--color-yellow);\n<\/span><\/span><mark class='shcb-loc'><span>    <span class=\"hljs-comment\">\/* Darkened version of yellow *\/<\/span>\n<\/span><\/mark><mark class='shcb-loc'><span>    border-bottom: <span class=\"hljs-number\">2<\/span>px solid oklch(<span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-keyword\">var<\/span>(--color-yellow) calc(l - <span class=\"hljs-number\">0.4<\/span>) c h);\n<\/span><\/mark><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Lighten a Color you Already Have<\/h2>\n\n\n\n<p>Same deal here. I&#8217;m <a href=\"https:\/\/chriscoyier.net\/2023\/01\/22\/ok-oklch-%F0%9F%91%91\/\">using OKLCH because I like it<\/a>, particularly the &#8220;uniform brightness&#8221; characteristic. Meaning when doing this darkening and lightening across different colors,<em> it feels like it lightens\/darkens the same amount<\/em>. Which feels weird to write, but it&#8217;s true. Other color spaces do not lighten and darken consistently. <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">.box {\n  <span class=\"hljs-attr\">background<\/span>: <span class=\"hljs-keyword\">var<\/span>(--gray<span class=\"hljs-number\">-5<\/span>);\n\n  h2 {\n    <span class=\"hljs-attr\">color<\/span>: <span class=\"hljs-keyword\">var<\/span>(--color-orange);\n    <span class=\"hljs-comment\">\/* Darkened version of orange *\/<\/span>\n    border-bottom: <span class=\"hljs-number\">2<\/span>px solid oklch(<span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-keyword\">var<\/span>(--color-orange) calc(l + <span class=\"hljs-number\">0.4<\/span>) c h);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_MWMOWdQ\" src=\"\/\/codepen.io\/anon\/embed\/MWMOWdQ?height=450&amp;theme-id=47434&amp;slug-hash=MWMOWdQ&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed MWMOWdQ\" title=\"CodePen Embed MWMOWdQ\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Easy Variations<\/h2>\n\n\n\n<p>Avoiding making too many variables is a nice consequence of the relative color syntax, but you can still use the relative color syntax to make variables if it&#8217;s useful to have them.<\/p>\n\n\n\n<p>I like the idea of starting with a base color, perhaps a slightly tinted gray, and then making the official variations with the relative color syntax. <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">html<\/span> {\n  <span class=\"hljs-attribute\">--base-gray<\/span>: <span class=\"hljs-built_in\">oklch<\/span>(<span class=\"hljs-number\">12.94%<\/span> <span class=\"hljs-number\">0.02<\/span> <span class=\"hljs-number\">159<\/span>);\n  \n  <span class=\"hljs-attribute\">--gray-1<\/span>: <span class=\"hljs-built_in\">var<\/span>(--base-gray);\n  <span class=\"hljs-attribute\">--gray-2<\/span>: <span class=\"hljs-built_in\">oklch<\/span>(from var(--base-gray) <span class=\"hljs-built_in\">calc<\/span>(l + <span class=\"hljs-number\">0.1<\/span>) c h);\n  <span class=\"hljs-attribute\">--gray-3<\/span>: <span class=\"hljs-built_in\">oklch<\/span>(from var(--base-gray) <span class=\"hljs-built_in\">calc<\/span>(l + <span class=\"hljs-number\">0.2<\/span>) c h);\n  <span class=\"hljs-attribute\">--gray-4<\/span>: <span class=\"hljs-built_in\">oklch<\/span>(from var(--base-gray) <span class=\"hljs-built_in\">calc<\/span>(l + <span class=\"hljs-number\">0.3<\/span>) c h);\n  <span class=\"hljs-attribute\">--gray-5<\/span>: <span class=\"hljs-built_in\">oklch<\/span>(from var(--base-gray) <span class=\"hljs-built_in\">calc<\/span>(l + <span class=\"hljs-number\">0.4<\/span>) c h);\n  <span class=\"hljs-attribute\">--gray-6<\/span>: <span class=\"hljs-built_in\">oklch<\/span>(from var(--base-gray) <span class=\"hljs-built_in\">calc<\/span>(l + <span class=\"hljs-number\">0.5<\/span>) c h);\n  <span class=\"hljs-attribute\">--gray-7<\/span>: <span class=\"hljs-built_in\">oklch<\/span>(from var(--base-gray) <span class=\"hljs-built_in\">calc<\/span>(l + <span class=\"hljs-number\">0.6<\/span>) c h);\n  <span class=\"hljs-attribute\">--gray-8<\/span>: <span class=\"hljs-built_in\">oklch<\/span>(from var(--base-gray) <span class=\"hljs-built_in\">calc<\/span>(l + <span class=\"hljs-number\">0.7<\/span>) c h);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_ExBbaxO\" src=\"\/\/codepen.io\/anon\/embed\/ExBbaxO?height=450&amp;theme-id=47434&amp;slug-hash=ExBbaxO&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed ExBbaxO\" title=\"CodePen Embed ExBbaxO\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>The fact that you can <em>start<\/em> with any color, use <em>any color function<\/em>, and manipulate <em>any part<\/em> of the color is incredibly powerful. The above use cases are pretty basic. I&#8217;m sure more talented designers or developers who deeply know color will be able to do much more interesting things! <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Support for the relative color syntax in CSS is across the board now (go interop!), so here we look at some basic (and still very useful) use cases, like applying alpha to a color you have on hand.<\/p>\n","protected":false},"author":1,"featured_media":3456,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[81,7,225],"class_list":["post-3448","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-color","tag-css","tag-relative-color-syntax"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-12-at-11.26.14%E2%80%AFAM.png?fit=980%2C974&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3448","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=3448"}],"version-history":[{"count":8,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3448\/revisions"}],"predecessor-version":[{"id":3489,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3448\/revisions\/3489"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/3456"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=3448"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=3448"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=3448"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}