Custom Properties + HSL gives you superpowers.

As a Sass user, I do a lot just with Sass. In the beginning when I came by CSS Custom Properties I actually didn’t care that much about it. Why would I? Sass has variables too, and these are even “dumber”.

But that’s not true. They are a completely different thing. Custom Properties aren’t better than Sass Variables or the other way around. Together they are awesome!

A big problem which I had with custom properties and especially colors in custom properties, was the fact that its hard to manipulate these colors. But actually, it’s not even that hard!

A simple example, I have a few sections with classes. These classes define on which color the section will be. But I want to give the button in this section, a color based on the background. Also the text should be either black or white, based on the background color.

<section class="background--green">
   <h3>Title of section</h3>
   <h4>Subtitle</h4>
   <p>Some context</p>
   <button>This is a button</button>
<section>
<section class="background--blue">
   <h3>Title of section</h3>
   <h4>Subtitle</h4>
   <p>Some context</p>
   <button>This is a button</button>
<section>

I could of §§§§§§§§§§course add a lot more classes. But why would I? I can do it with this.

This is what I would have done without custom properties. Just use sass.
Given is the fact that I have a list of colors. This for instance I get directly from “Guyn”

/* So I create all the classes for the colors. I get a $guyn-colors with all colors.  */
@for $color-name, $color-value in $guyn-colors{
   /* I do a to-lower-case to make sure there are not capital letters in the classes, this makes it only less readable and more annoying to use. */
   .background--#{to-lower-case($color-name)} {
      background-color: #{$color-value}; 
      color: contra($color-value); /* The contra function comes from 'Henri's', it just checks the lightness of the color and returns either black or white; */
      .button {
         background-color: darken($color-value,10%);
         color: contra(darken($color-value,10%));
      }
   }
}

This is awesome! But what if… you do Not know the colors you can get thrown at you. In that case I cant prepare all the classes upfront for every situation.
The only thing you want to get is 3 properties per color. Unfortunately I get that this isn’t always possible, but if so… You could do this:

In this case I want to use the guyn colors again, but i want to have HSL values.

@for $color-name, $color-value in $guyn-colors{
   .background--#{to-lower-case($color-name)} {
      --section-color: #{$color-value}; // Yes, you do need to use the thingies around the variables, otherwise sass will just pass back the variable instead of its value. 
      --section-color-hue: #{hue($color-value)}; 
      --section-color-saturation: #{saturation($color-value)}; 
      --section-color-lightness: #{lightness($color-value)}; 
   }
}

So I don’t give back any actual variables. I only give css custom properties. Also I do not define a button. I can just put the styling of the button anywhere I want.

The CSS for the section will now look as following, I only have to do this once and not for every color, this saves also a lot of data.

section {
   background-color: var(--section-color);
  --contrast: calc((var(--section-color-lightness) - 50% * -100%);
   color: hsl(var(--section-color-hue), var(--section-color-saturation), calc(var(--section-color-lightness) + 5%));
}
section .button{
   background-color: hsl(var(--section-color-hue), var(--section-color-saturation), calc(var(--section-color-lightness) + 5%));
}

See what I did there?

  • In the section, for the text color I calculated a darkness depending on the color and throw that at the color. In that case if the “lightness” of a color is more than 50% (a light color), the text will be black. If less, it returns white as the color. Of course this 50% you can also adjust and even make a custom property out of.
  • I used a calc in the background color which just add 5% extra darkness to the color. In that case the button will be always 5% darker than the section background.