¿Cómo crear tonos de color usando variables CSS similares a darken() de Sass?

Resuelto Daniel asked hace 5 años • 4 respuestas

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);
}
Daniel avatar Mar 25 '19 07:03 Daniel
Aceptado

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 hslformato 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);
}
Expandir fragmento

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>
Expandir fragmento

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.

Temani Afif avatar Mar 25 '2019 01:03 Temani Afif

¿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%);
}
Romalex avatar Feb 16 '2022 22:02 Romalex

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 */
}
Miguel Santo avatar May 11 '2021 17:05 Miguel Santo

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>
 avatar Sep 09 '2022 10:09