Sintaxis de colores relativos de CSS

Crea colores nuevos basados en los canales y valores de otro color.

Adam Argyle
Adam Argyle

En Chrome 119, se incluye una función de color muy potente del nivel de color 5 de CSS. La sintaxis de color relativa crea una ruta sin problemas para la manipulación del color en CSS y ofrece formas para que los autores y diseñadores puedan hacer lo siguiente:

Antes de la sintaxis relativa de colores, para modificar la opacidad de un color, debes crear propiedades personalizadas para los canales de un color (por lo general, HSL) y ensamblarlas en un color final y en el color final de la variante. Esto significa gestionar muchas piezas de color, que rápidamente puede volverse una tarea pesada.

:root {
  --brand-hue: 300deg;
  --brand-saturation: 75%;
  --brand-lightness: 50%;

  --brand-hsl:
    var(--brand-hue)
    var(--brand-saturation)
    var(--brand-lightness);

  --brand-color: hsl(var(--brand-hsl));

  /* all this work just so I can set the opacity to 50% in a variant */
  --brand-color-variant: hsl(var(--brand-hsl) / 50%);
}

Después de la sintaxis de color relativo, puedes crear un color de marca con cualquier espacio de color o sintaxis que necesites y crear una variante de opacidad media con mucho menos código. También es mucho más fácil leer la intención de los estilos y el sistema.

:root {
  --brand-color: hsl(300deg 75% 50%);
  --brand-color-variant: hsl(from var(--brand-color) h s l / 50%);
}

Esta publicación te ayudará a aprender la sintaxis y demostrar manipulaciones de color comunes.

Si prefiere utilizar videos, casi todo el artículo siguiente se aborda en este Desafío de la GUI.

Descripción general de la sintaxis

El objetivo de la sintaxis de color relativo es permitir que se derive un color a partir de otro color. El color base se denomina color de origen y es el que viene después de la nueva palabra clave from. El navegador convertirá y dividirá este color de origen, y ofrecerá las partes como variables para usarlas en la nueva definición de color.

Se muestra un diagrama de la sintaxis rgb(de verde r g b / alfa), con una flecha que deja la parte superior verde y se arquea hacia el comienzo de la función RGB, esta se divide en 4 flechas que apuntan a su variable relevante. Las 4 flechas son rojas, verdes, azules y alfa. El rojo y el azul tienen un valor de 0, el verde es 128 y el alfa es del 100%.

En el diagrama anterior, se muestra que el color de origen green se convierte en el espacio de color del color nuevo y se convierte en números individuales representados como variables r, g, b y alpha, que luego se usan directamente como valores de un nuevo color rgb().

Si bien en esta imagen se muestra el desglose, el proceso y las variables, tampoco cambia el color. Las variables se vuelven a colocar en el color sin cambios, lo que da como resultado un color verde aún.

La palabra clave from

La primera parte de la sintaxis que debes aprender es la parte from <color> que se agrega a especificar un color. Va justo antes de que especifiques los valores. Este es un ejemplo de código en el que todo lo que se agregó es from green, justo antes de que se especifiquen los valores para rgb().

.syntax-introduction_same-colors {
  color: green;
  color: rgb(0 128 0);
  color: rgb(from green r g b);    /* result = rgb(0 128 0) */
}

Esa palabra clave from, cuando se ve como el primer parámetro en la notación funcional, convierte la definición del color en un color relativo. Después de la palabra clave from, el CSS espera un color, que inspirará el siguiente color.

Conversión de color

En términos más simples, convierte el verde en los canales r g y b para usarlos en un nuevo color.

rgb(from green r g b)           /* r=0 g=128 b=0 */
rgb(from rgb(0 128 0) r g b);   /* r=0 g=128 b=0 */

Colores de las propiedades personalizadas

Leer rgb from green es muy claro y fácil de entender. Es por eso que las propiedades personalizadas y la sintaxis de color relativa son una buena coincidencia, ya que puedes olvidar el misterio del color from. Por lo general, tampoco es necesario que conozcas el formato del color de la propiedad personalizada, ya que crearás un color nuevo en el formato que elijas.

rgb(from rgb(255 105 180) r g b) /* ????? */
rgb(from var(--hotpink) r g b)   /* clear */

Trabaja con tu espacio de color preferido

Puedes elegir el espacio de color con la notación de colores funcional que prefieras.

rgb(from hsl(120 100% 25%) r g b)     /*  r=0   g=128  b=0    */
hsl(from hsl(120 100% 25%) h s l)     /*  h=120 s=100% l=25%  */
hwb(from hsl(120 100% 25%) h w b)     /*  h=120 w=0%   b=50%  */
lch(from hsl(120 100% 25%) l c h)     /*  l=46  c=68   h=134  */

La sintaxis de color relativo tiene ese paso de conversión. El color después de from se convierte en el espacio de color, como se especificó al comienzo del color relativo. No es necesario que la entrada y la salida coincidan, lo cual es muy liberador.

La capacidad de elegir un espacio de color también es estimulante, ya que elegir un espacio de color tiende a centrarse más en el tipo de alternancia de color que en una preferencia. La preferencia está en los resultados, no en el formato de color ni los tipos de canal. Esto será mucho más claro en las secciones que muestran casos de uso, ya que los diferentes espacios de color se destacan en diferentes tareas.

Mezcla, haz coincidir, omite y repite las variables

Algo extraño, pero emocionante sobre esta sintaxis, las variables no tienen que volver a ordenarse y se pueden repetir.

rgb(from green g g g)    /* rgb(128 128 128) */
rgb(from green b r g)    /* rgb(0 0 128) */
rgb(from green 0 0 g)    /* rgb(0 0 128) */

Opacidad como variable

La sintaxis también proporciona la opacidad como una variable llamada alpha. Es opcional y va después de / en la notación de colores funcional.

rgb(from #00800080 r g b / alpha)             /* alpha=50% */
rgb(from rgba(0,128,0,.5) r g b / alpha)      /* alpha=50% */
rgb(from rgb(0 128 0 / 50%) r g b / alpha)    /* alpha=50% */

Utiliza calc() u otras funciones de CSS en las variables.

Hasta ahora, hemos creado el color verde una y otra vez. Aprender la sintaxis, familiarizarte con los pasos de conversión y desestructuración. Ahora es momento de modificar las variables, modifica el resultado para que no sea el mismo que la entrada.

green                              /*  h=120 s=100% l=25%  */
hsl(from green calc(h * 2) s l)    /*  h=240 s=100% l=25%  */

¡Es la marina ahora! Se duplicó el matiz; se tomó un tono de 120 y se convirtió en 240, lo que alteró completamente el color. Esto hizo rotar el matiz a lo largo de la rueda de colores, un ingenioso truco muy simple con espacios de color cilíndricos como HSL, HWB, LCH y OKLCH.

Para ver visualmente los valores de los canales, de modo que puedas realizar los cálculos correctamente sin tener que adivinar ni memorizar las especificaciones, prueba esta herramienta de valores de canal de sintaxis de color relativo. Revela cada valor de canal según la sintaxis que especifiques, lo que te permite saber exactamente los valores que tienes disponibles para experimentar.

Cómo verificar la compatibilidad con el navegador

@supports (color: rgb(from white r g b)) {
  /* safe to use relative color syntax */
}

Casos de uso y demostraciones

Los siguientes ejemplos y casos de uso tienen muchas sintaxis alternativas para lograr resultados similares o los mismos. Las variaciones provienen de los espacios de color y los canales que ofrecen.

Además, muchos ejemplos mostrarán ajustes de color con el verbo de by y to. Un by de color modificado es un cambio de color relativo, es decir, un cambio que usa el valor de la variable y realiza un ajuste en función de su valor actual. Un to de color cambiado es un cambio de color absoluto; es un cambio que no usa el valor de la variable y, en su lugar, especifica un valor completamente nuevo.

Puedes encontrar todas las demostraciones en esta colección de CodePen.

Aclarar un color

Los espacios de color de OKLCH, OKLAB, XYZ o sRGB proporcionan los resultados más predecibles cuando se aclaran los colores.

Aclarar en cierta cantidad

En el siguiente .lighten-by-25 de ejemplo, se toma el color blue y se lo convierte en OKLCH, luego se aclara el azul aumentando el canal l (luz) multiplicando el valor actual por 1.25. Esto empuja la luz azul hacia el blanco un 25%.

.lighten-by-25 {
  background: oklch(from blue calc(l * 1.25) c h);
}
.

Aclarar hasta un valor específico

En el siguiente ejemplo de .lighten-to-75, no se usa el canal l para aclarar blue, sino que reemplaza por completo el valor con 75%.

.lighten-to-75 {
  background: oklch(from blue 75% c h);
}
.

Oscurecer un color

Los mismos espacios de color eficaces para aclarar un color también son excelentes para oscurecer el color.

Oscurecer por una cantidad

El siguiente .darken-by-25 de ejemplo toma el color azul y lo convierte en OKLCH, luego oscurece el azul disminuyendo el canal l (luz) en un 25% multiplicando el valor por .75. Esto empuja el color azul hacia el negro un 25%.

.darken-by-25 {
  background: oklch(from blue calc(l * .75) c h);
}

Oscurecer un valor especificado

En el siguiente ejemplo de .darken-to-25, no se usa el canal l para oscurecer blue, sino que reemplaza por completo el valor con 25%.

.darken-to-25 {
  background: oklch(from blue 25% c h);
}

Satura un color

Saturar en una cantidad

En el siguiente ejemplo, .saturate-by-50 usa s de hsl() para aumentar la vitalidad de orchid en un 50% relativo.

.saturate-by-50 {
  background: hsl(from orchid h calc(s * 1.5) l);
}

Saturar en una cantidad específica

En el siguiente ejemplo, .saturate-to-100 no usa el canal s de hsl(); en su lugar, especifica un valor de saturación deseado. En este ejemplo, la saturación se aumenta a 100%.

.saturate-to-100 {
  background: hsl(from orchid h 100% l);
}

Desaturar un color

Desaturar en cierta cantidad

En el siguiente ejemplo de .desaturate-by-half, se usa el s de hsl() para disminuir la saturación de indigo a la mitad.

.desaturate-by-half {
  background: hsl(from indigo h calc(s / 2) l);
}

Desaturar en un valor específico

En lugar de reducir la saturación por una determinada cantidad, puedes reducir la saturación hasta alcanzar un valor deseado específico. En el siguiente ejemplo de .desaturate-to-25, se crea un color nuevo basado en indigo, pero se establece la saturación en un 25%.

.desaturate-to-25 {
  background: hsl(from indigo h 25% l);
}

Amplifica el croma de un color

Este efecto es similar a la saturación de un color, pero es diferente en varias maneras. En primer lugar, es un cambio de chroma y no de saturation, y esto se debe a que los espacios de color que pueden aumentarse a un rango dinámico alto no usan la saturación. Los espacios de color que tienen chroma admiten un alto rango dinámico, lo que permite a los autores aumentar la intensidad del color aún más que la saturación.

.increase-chroma {
  background: oklch(from orange l calc(c + .1) h);
}

Ajusta la opacidad de un color

Crear una variante semitransparente de un color es uno de los ajustes de color más comunes que se realizan en los sistemas de diseño. Si no pudiste ver el ejemplo de la introducción de este artículo, describe muy bien el espacio del problema.

Ajustar la opacidad en una cantidad

.decrease-opacity-by-25 {
  background: rgb(from lime r g b / calc(alpha / 2));
}
.

Ajusta la opacidad a un valor específico

.decrease-opacity-to-25 {
  background: rgb(from lime r g b / 25%);
}

Invertir un color

La inversión de color es una función común de ajuste de color que se encuentra en las bibliotecas de colores. Una forma de lograrlo es convertir un color a RGB y, luego, restarle el valor de cada canal a 1.

.invert-each-rgb-channel {
  background: rgb(from yellow calc(255 - r) calc(255 - g) calc(255 - b));
}
.

Complementa un color

Si tu objetivo no es invertir un color, sino complementarlo, es probable que la rotación de matiz sea lo que estás buscando. Elige un espacio de color que ofrezca el tono como un ángulo y, luego, usa calc() para rotar el tono según la cantidad que desees. Para encontrar el complemento de un color, se debe rotar medio turno. En este caso, puedes sumar o restar del canal h en 180 para lograr el resultado.

.complementary-color {
  background: hsl(from blue calc(h + 180) s l);
}

Contrastar un color

Como método para lograr relaciones de contraste de color accesibles, considera L&midast; (Lstar). Se usa el canal de luminosidad uniforme (L) (aproximadamente) perceptualmente de LCH y OKLCH, en un calc(). Dependiendo de si orientas tu app a un contraste bajo, medio o alto, el delta de L&midast es aproximadamente 40, 50 o 60.

Esta técnica funciona bien en cualquier tono de LCH u OKLCH.

Contrastar un color más oscuro

La clase .well-contrasting-darker-color demuestra L* con un delta de 60. Dado que el color de origen es un color oscuro (valor bajo de luminosidad), se agrega un 60% (0.6) al canal de luminosidad. Esta técnica se usa para encontrar un color de texto oscuro, de la misma tonal y bien contrastado sobre un fondo claro.

.well-contrasting-darker-color {
  background: darkred;
  color: oklch(from darkred calc(l + .60) c h);
}

Contrastar un color más claro

La clase .well-contrasting-lighter-color también muestra L* con un delta del 60%. Dado que el color de origen es un color claro (luminosidad de alto valor), 0.60 se resta del canal de luminosidad.

.well-contrasting-lighter-color {
  background: lightpink;
  color: oklch(from lightpink calc(l - .60) c h);
}

Paletas de colores

La sintaxis de color relativo es muy buena para crear paletas de colores. Es especialmente útil y potente debido a la cantidad de espacios de color disponibles. En los siguientes ejemplos, se usa OKLCH porque el canal de luminosidad es confiable y el canal de matiz se puede rotar sin efectos secundarios. En el ejemplo final, se muestra una combinación de ajustes de luminosidad y rotación de matiz para lograr un resultado más interesante.

Abre el código fuente de ejemplo y cambia --base-color para ver qué tan dinámicas son estas paletas. ¡Es divertido!

Si te gustan los videos, puedo brindarte información detallada sobre la creación de paletas de colores en CSS con OKLCH en YouTube.

Paletas monocromáticas

Para crear una paleta monocromática es crear una paleta del mismo tono, pero con variaciones de luminosidad y oscuridad. El color medio es el de origen de la paleta, en el que dos variantes más claras y dos más oscuras se colocan a cada lado.

:root {
  --base-color: deeppink;

  --color-0: oklch(from var(--base-color) calc(l + .20) c h); /* lightest */
  --color-1: oklch(from var(--base-color) calc(l + .10) c h);
  --color-2: var(--base-color);
  --color-3: oklch(from var(--base-color) calc(l - .10) c h);
  --color-4: oklch(from var(--base-color) calc(l - .20) c h); /* darkest */
}
Probar un montón de paletas hechas con sintaxis de color relativa y OKLCH

Open Props, una biblioteca de variables de CSS gratuitas, ofrece paletas de colores compiladas con esta estrategia y las hace fáciles de usar con una importación. También se crean a partir de un color que puedes personalizar, solo le agregas un color y sale una paleta.

Paletas análogas

Dado que la rotación de matiz es muy sencilla con OKLCH y HSL, no es sencillo crear una paleta de colores análoga. Rota el matiz según la cantidad que te guste para los resultados y cambia el color de base, y observa que el navegador crea nuevas paletas.

:root {
  --base-color: blue;

  --primary:   var(--base-color);
  --secondary: oklch(from var(--base-color) l c calc(h - 45));
  --tertiary:  oklch(from var(--base-color) l c calc(h + 45));
}

Paletas triádicas

De manera similar a los colores complementarios, las paletas de colores triádicas son rotaciones de tonos opuestas pero armoniosas a partir de un color de base. Cuando un color complementario se encuentra en el lado opuesto de un color, como una línea recta dibujada a través del medio de la rueda de colores, las paletas triádicas son como un triángulo de líneas, en el que se encuentran 2 colores rotados igualmente desde un color base. Para lograrlo, rota el matiz 120deg.

Esta es una leve simplificación de la teoría del color, pero basta para ponerte en marcha con las paletas triádicas más complejas si te interesa.

:root {
  --base-color: yellow;
  --triad-1: oklch(from var(--base-color) l c calc(h - 120));
  --triad-2: oklch(from var(--base-color) l c calc(h + 120));
}

Paletas tetrádicas

Las paletas tetrádicas son cuatro colores divididos uniformemente alrededor de la rueda de colores, lo que crea una paleta sin un valor dominante claro. Podrías pensar en ello también, como dos pares de colores complementarios. Si se usa con prudencia, puede tener mucha importancia.

Esta es una leve simplificación de la teoría del color, pero basta para ponerte en marcha con las paletas tetrádicas más complejas si te interesa.

:root {
  --base-color: lime;

  --color-1: var(--base-color);
  --color-2: oklch(from var(--base-color) l c calc(h + 90));
  --color-3: oklch(from var(--base-color) l c calc(h + 180));
  --color-4: oklch(from var(--base-color) l c calc(h + 270));
}

Monocromático con una leve rotación de matiz

Muchos expertos en color llevan este truco bajo la manga. El problema es que una escala de colores monocromática puede ser bastante aburrida. La solución es agregar una rotación de matiz menor o mayor a cada color nuevo a medida que se modifica la luminosidad.

En el siguiente ejemplo, se reduce la luminosidad en un 10% de cada muestra y también se rota el matiz 10 grados. El resultado es una paleta de color rosa a índigo que parece combinarse sin problemas como lo haría un gradiente.

:root {
  --base-color: deeppink;

  --color-1: var(--base-color);
  --color-2: oklch(from var(--base-color) calc(l - .10) c calc(h - 10));
  --color-3: oklch(from var(--base-color) calc(l - .20) c calc(h - 20));
  --color-4: oklch(from var(--base-color) calc(l - .30) c calc(h - 30));
  --color-5: oklch(from var(--base-color) calc(l - .40) c calc(h - 40));
}
Prueba esta tabla de clasificación creada con OKLCH y rotación de matiz

La siguiente interfaz de la tabla de clasificación usa esta estrategia de rotación de matiz. Cada elemento de la lista realiza un seguimiento de su índice en el documento como una variable llamada --i. Este índice se usa para ajustar la croma, la luminosidad y el tono. El ajuste es solo de un 5% o 5 grados, mucho más sutil que el ejemplo anterior con el color rosa profundo, por lo que se necesita una buena atención para notar el motivo por el que esta tabla de clasificación puede tener cualquier tono con tanta elegancia.

Asegúrate de cambiar el matiz en el control deslizante que se encuentra debajo de la tabla de clasificación y observa la sintaxis de color relativa para crear momentos de color atractivos.

li {
  --_bg: oklch(
    /* decrease lightness as list grows */
    calc(75% - (var(--i) * 5%))

    /* decrease chroma as list grows */
    calc(.2 - (var(--i) * .01))

    /* lightly rotate the hue as the list grows */
    calc(var(--hue) - (var(--i) + 5))
  );
}