Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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);
}
like image 773
Daniel Avatar asked Mar 25 '19 00:03

Daniel


People also ask

How do you darken colors in sass?

Using lighten() and darken() in SASS As the names suggest, given a colour and percentage, these functions will return a colour lighter or darker respectively.

Can you use CSS variables with sass?

SASS is a CSS extension that lends superpower and elegance to this formal simple style language. SASS gives you the ability to use variables, nested rules, mixins, inline imports, and more, all with fully CSS-compliant syntax.

How do I darken a color in CSS?

To darken a color in CSS, you can use the color's hue, saturation, and lightness values. For example, if you want to darken a color by 10%, you would use the following code: hsl(0, 0%, 90%); This would make the color 10% darker.


3 Answers

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%)); 
}

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

There is still no support for this to date so consider the below solution.


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.

like image 59
Temani Afif Avatar answered Oct 13 '22 09:10

Temani Afif


How about this (pure sass/scss):

First, we need to split a color into hsla values and save each one in a separate custom property. Luckily sass has some functions to do the job.

@mixin define-color($title, $color) {
    --#{$title}-h: #{hue($color)};
    --#{$title}-l: #{lightness($color)};
    --#{$title}-s: #{saturation($color)};
    --#{$title}-a: #{alpha($color)};
}

Now we can put it back together, making some adjustments on the way.

@function color($title, $hue: 0deg, $lightness: 0%, $saturation: 0%, $alpha: 0) {
    @return hsla(
        calc(var(--#{$title}-h) + #{$hue}), 
        calc(var(--#{$title}-s) + #{$saturation}),
        calc(var(--#{$title}-l) + #{$lightness}),
        calc(var(--#{$title}-a) + #{$alpha}),
    );
}

Now we are ready to define some color variables...

:root {
    @include define-color("primary", #696969);
    @include define-color("secondary", blue);
}

override them (to dynamically switch between themes for example)...

:root.theme-light {
    @include define-color("primary", #424242);
    @include define-color("secondary", red);
}

use and adjust them!

.example-class {
    color: color("primary");
    background: color("secondary", $lightness: +20%, $alpha: -0.3);
    border: 1px solid color("primary", $hue: -30deg, $saturation: 5%);
}
like image 3
Romalex Avatar answered Oct 13 '22 11:10

Romalex


If you are willing to take a different approach to your problem, using masks with the pseudo ":before" element would solve your problem. Although if you use this, i would advice you to put any content in the button inside a span or something, to give it a "z-index:1", so the content is not behind the mask.

:root {
    --color-primary: #f00;
}

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

    &:before {
        content:'';
        position:absolute;
        width:100%;
        height:100%;
        top:0;
        left:0;
    }
}

.button:hover:before,
.button:focus:before {
    background:rgba(0,0,0,0.05) /* black mask with 5% opacity */
}

.button:active:before {
    background:rgba(0,0,0,0.1) /* black mask with 10% opacity */
}
like image 1
Miguel Santo Avatar answered Oct 13 '22 11:10

Miguel Santo