¿Cómo crear tonos de color usando variables CSS similares a darken() de Sass?
Estoy buscando una forma de modificar una variable CSS como lo harías en SCSS
Defina un color como primario y automáticamente obtendría sombras para los estados de enfoque y activos. Básicamente, me gustaría cambiar una variable en las variables CSS y obtener 3 tonos del mismo color.
Lo que me gustaría lograr en CSS
$color-primary: #f00;
.button {
background: $color-primary;
&:hover,
&:focus {
background: darken($color-primary, 5%);
}
&:active {
background: darken($color-primary, 10%);
}
}
tratando de lograr:
: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);
}
La nueva especificación introduce la "sintaxis de color relativa" donde puede hacer lo siguiente
: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%));
}
La idea es convertir el color principal a hsl
formato y utilizarlo calc()
para ajustar la luminosidad.
La compatibilidad con esta función aún no es buena, así que considere la siguiente solución.
Puedes usar color-mix()
y mezclar el color con negro (o blanco) para crear diferentes tonos a partir del mismo 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);
}
Relacionado: https://css-tip.com/color-shades-color-mix/
Antigua respuesta
Puedes considerar hsl()
colores y simplemente controlar la luminosidad:
: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>
Como nota al margen, darken()
también está haciendo lo mismo:
Hace que un color sea más oscuro. Toma un color y un número entre 0% y 100% y devuelve un color con la luminosidad disminuida en esa cantidad.
¿Qué tal esto (puro descaro/scss)?
Primero, necesitamos dividir un color en valores hsla y guardar cada uno en una propiedad personalizada separada. Afortunadamente, sass tiene algunas funciones para hacer el trabajo.
@mixin define-color($title, $color) {
--#{$title}-h: #{hue($color)};
--#{$title}-l: #{lightness($color)};
--#{$title}-s: #{saturation($color)};
--#{$title}-a: #{alpha($color)};
}
Ahora podemos volver a armarlo, haciendo algunos ajustes en el camino.
@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}),
);
}
Ahora estamos listos para definir algunas variables de color...
:root {
@include define-color("primary", #696969);
@include define-color("secondary", blue);
}
anularlos (para cambiar dinámicamente entre temas, por ejemplo)...
:root.theme-light {
@include define-color("primary", #424242);
@include define-color("secondary", red);
}
¡Utilízalos y ajústalos!
.example-class {
color: color("primary");
background: color("secondary", $lightness: +20%, $alpha: -0.3);
border: 1px solid color("primary", $hue: -30deg, $saturation: 5%);
}
Si está dispuesto a adoptar un enfoque diferente para su problema, usar máscaras con el elemento pseudo ":before" resolvería su problema. Aunque si usas esto, te recomendaría que coloques cualquier contenido en el botón dentro de un lapso o algo así, para darle un "índice z:1", de modo que el contenido no esté detrás de la máscara.
: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 */
}
Ampliando la respuesta de Temanis: uso un degradado, desde negro hasta un color dinámico y luego blanco, y amplío el fondo 100 veces. Ahora sólo es cuestión de posicionar el fondo.
en el 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);
}
Y en el HTML
<btn class="dynamic-color" style="--color-variable: green">Hover me</btn>