Frontend Masters Boost RSS Feed https://frontendmasters.com/blog Helping Your Journey to Senior Developer Wed, 14 Aug 2024 17:25:38 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.1 225069128 Relative Color Syntax — Basic Use Cases https://frontendmasters.com/blog/relative-color-syntax-basic-use-cases/ https://frontendmasters.com/blog/relative-color-syntax-basic-use-cases/#comments Mon, 12 Aug 2024 18:38:35 +0000 https://frontendmasters.com/blog/?p=3448 As of last month, Firefox 128’s support of the relative color syntax means we’ve now got support across the board. I’m excited about that as it’s an extremely powerful way to manipulate colors in CSS. Plus it was part of Interop this year so that is further proof that is trucking along nicely.

The syntax with generic names looks like this:

color-function(from origin-color channel1 channel2 channel3 / alpha)

Here’s how it works in my head:

Add Opacity to a Color you Already Have

It’s common to have CSS custom properties set up for colors on a project.

html {
  --color-yellow: oklch(80% 0.15 94);
  --color-green:  oklch(70% 0.25 140);

  ...
}

Now you want to use that yellow, but at about 50% opacity. How do you do that? There are actually a couple of ways to add transparency to an existing color, but in my opinion the relative color syntax is the nicest.

In the past, I’ve split out the color values like this:

html {
  --color-yellow-lch: 80% 0.15 94;
  --color-yellow: oklch(var(--color-yellow-lch);

  ...
}

That way I could either use the color all together, or use the split out values to apply opacity:

.box {
  background: var(--color-yellow);
  border-color: oklch(var(--color-yellow-lch) / 50%);
}

But that can get out of hand! You could also split each color into L, C, and H, the combine those, giving you five variables for every color. Too much.

With the relative color syntax, breaking down colors isn’t necessary. You apply alpha (and other transformations) on demand, leaving the original single color as the only variable (token) you need.

.box {
  background: var(--color-yellow);
  border-color: oklch(from var(--color-yellow) l c h / 50%); 
}

I much prefer the idea of keeping the main colors tokenized as custom properties, then tweaking them as needed on demand.

Darken a Color you Already Have

In the above example, we had --color-yellow and I ended by saying I prefer doing one-off tweaks on demand rather than making a whole new variable. If you have a ton of usage of a slightly-darker version of a color, then sure, make a new variable and stay consistent. But if it’s more of a one-off, relative color syntax is awesome:

.box {
  background: var(--gray-5);

  h2 {
    color: var(--color-yellow);
    /* Darkened version of yellow */
    border-bottom: 2px solid oklch(from var(--color-yellow) calc(l - 0.4) c h);
  }
}

Lighten a Color you Already Have

Same deal here. I’m using OKLCH because I like it, particularly the “uniform brightness” characteristic. Meaning when doing this darkening and lightening across different colors, it feels like it lightens/darkens the same amount. Which feels weird to write, but it’s true. Other color spaces do not lighten and darken consistently.

.box {
  background: var(--gray-5);

  h2 {
    color: var(--color-orange);
    /* Darkened version of orange */
    border-bottom: 2px solid oklch(from var(--color-orange) calc(l + 0.4) c h);
  }
}

Easy Variations

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’s useful to have them.

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.

html {
  --base-gray: oklch(12.94% 0.02 159);
  
  --gray-1: var(--base-gray);
  --gray-2: oklch(from var(--base-gray) calc(l + 0.1) c h);
  --gray-3: oklch(from var(--base-gray) calc(l + 0.2) c h);
  --gray-4: oklch(from var(--base-gray) calc(l + 0.3) c h);
  --gray-5: oklch(from var(--base-gray) calc(l + 0.4) c h);
  --gray-6: oklch(from var(--base-gray) calc(l + 0.5) c h);
  --gray-7: oklch(from var(--base-gray) calc(l + 0.6) c h);
  --gray-8: oklch(from var(--base-gray) calc(l + 0.7) c h);
}

The fact that you can start with any color, use any color function, and manipulate any part of the color is incredibly powerful. The above use cases are pretty basic. I’m sure more talented designers or developers who deeply know color will be able to do much more interesting things!

]]>
https://frontendmasters.com/blog/relative-color-syntax-basic-use-cases/feed/ 1 3448