Search code examples
csssasscss-variables

How to create color shades using CSS variables similar to darken() of Sass?


I'm looking a way of modifying a CSS variable as you would in SCSS

Define a color like primary - and automatically I would get shades for focus and actives states. Basically, would like to change one variable in css variables and get 3 shades of the same color.

What Id like to achieve in CSS

$color-primary: #f00;

.button {
    background: $color-primary;

    &:hover,
    &:focus {
        background: darken($color-primary, 5%);
    }

    &:active {
        background: darken($color-primary, 10%);
    }
}

trying to achieve:

:root {
    --color-primary: #f00;
    --color-primary-darker: #f20000  //     var(--color-primary) * 5% darker
    --color-primary-darkest: #e50000 //     var(--color-primary) * 10% darker
}

.button {
    background: var(--color-primary);
}

.button:hover,
.button:focus {
    background: var(--color-primary-darker);
}

.button:active {
    background: var(--color-primary-darkest);
}

Solution

  • The new Specification introduces "relative color syntax" where you can do the following

    :root {
      --color-primary: #f00; /* any format you want here */
      --color-primary-darker: hsl(from var(--color-primary) h s calc(l - 5));
      --color-primary-darkest: hsl(from var(--color-primary) h s calc(l - 10));
      
       background:
        linear-gradient(to right,var(--color-primary) 33%,var(--color-primary-darker) 0 66%,var(--color-primary-darkest) 0);
    
    }

    The idea is to convert the main color to hsl format and using calc() you adjust the lightness.

    You can also use color-mix() and mix the color with black (or white) to create different shades from the same color.

    html {
      --color-primary: #8A9B0F; 
      --color-primary-darker:  color-mix(in srgb,var(--color-primary),#000 15%);
      --color-primary-darkest: color-mix(in srgb,var(--color-primary),#000 30%);
      
      background:
        linear-gradient(to right,var(--color-primary) 33%,var(--color-primary-darker) 0 66%,var(--color-primary-darkest) 0);
    }

    I also wrote about it here : https://css-tip.com/color-shades-color-mix/


    Old Answer

    You can consider hsl() colors and simply control the lightness:

    :root {
        --color:0, 100%; /*the base color*/
        --l:50%; /*the initial lightness*/
        
        --color-primary: hsl(var(--color),var(--l));
        --color-primary-darker: hsl(var(--color),calc(var(--l) - 5%));
        --color-primary-darkest: hsl(var(--color),calc(var(--l) - 10%)); 
    }
    
    .button {
        background: var(--color-primary);
        display:inline-block;
        padding:10px 20px;
        color:#fff;
        cursor:pointer;
    }
    
    .button:hover,
    .button:focus {
        background: var(--color-primary-darker);
    }
    
    .button:active {
        background: var(--color-primary-darkest);
    }
    <span class="button">some text</span>

    As a side note, darken() is also doing the same thing:

    Makes a color darker. Takes a color and a number between 0% and 100%, and returns a color with the lightness decreased by that amount.