Reputation: 1155
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);
}
Upvotes: 76
Views: 82317
Reputation: 273031
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.
Upvotes: 162
Reputation:
Expanding on Temanis answer: I use a gradient - from black to a dynamic color to white - and expand the background 100 times. Now its only a question of positioning the background.
In the CSS
.dynamic-color {
--lighten: 80%;
--darken: 45%;
--original-color: 50%;
--color-intensity: var(--original-color);
--color-variable: blue;
background-image: linear-gradient(90deg,black, var(--color-variable),white);
background-repeat: no-repeat;
background-size: 10000% 100%;
background-position-x: var(--color-intensity);
}
.dynamic-color:hover{
--color-intensity: var(--lighten);
}
.dynamic-color.active{
--color-intensity: var(--darken);
}
And in the HTML
<btn class="dynamic-color" style="--color-variable: green">Hover me</btn>
Upvotes: 1
Reputation: 1829
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%);
}
Upvotes: 6
Reputation: 85
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 */
}
Upvotes: 0