DÍA 3 / 2020

El color en CSS

Con CSS actualmente solo podemos acceder al perfil de color sRGB, pero esto va a cambiar pronto con la llegada de las funciones Lab y Lch, preparadas para acceder a todos los colores que ya soportan nuestras pantallas hoy en día.


En 1996 llegaba el color a la web con CSS. Podemos, desde ese momento, definir colores en CSS con keywords, en formato hexadecimal o con las funciones RGB() o HSL().

Estas formas de usar colores en CSS cubren el gamut, o rango de color, definido por el perfil sRGB, más que suficiente durante muchos años, pero no hoy en día, pues el nivel de calidad de las pantallas que usamos actualmente suele cubrir rangos de color muchísimo más amplios, cercanos al P3. Es decir, hoy en día con CSS no podemos usar todos colores que es capaz de mostrar nuestra pantalla.

Pero esto será por poco tiempo.

En la actualidad

Aunque, sorprendentemente para mí, creo que no es el más usado, yo soy muy fan de la función HSL y es la que uso casi siempre por defecto para establecer colores en CSS. Las siglas de HSL(A) significan Hue, Saturation y Lightness, y un parámetro opcional de Alpha.

  • Hue : Es la rueda de color. Un número entre 0 y 360
  • Saturation : Saturación. Entre 0% y 100%
  • Lightness : Luminosidad. Entre 0% y 100%
  • Alpha : Es opcional, indica la opacidad. Entre 0 (transparente) y 1 (opaco)
Rueda de color o Hue
Rueda de color o Hue

Con este formato tan intuitivo es muy sencillo hacer cambios tocando manualmente el código e intuir lo que estás tocando. Algo que no pasa con RGB o con Hexadecimal.

Por ejemplo, es muy fácil crear una escala de grises creado saltos de 10% de lightness, o definir un color a raíz de otro cambiando solo un poco el porcentaje de saturation pero asegurándonos de que el hue no cambia. La función HSL es muy versátil, y si la mezclamos con el uso de las custom properties podemos hacer maravillas con muy poco código.

Si usáis HSL estoy seguro de que, como a mí, al poco tiempo se os iluminó la bombilla y pensasteis: «Si este color, con esta saturation y este lightness contrasta perfectamente con mi texto. Si solo cambio el hue, todos los colores contrastarán bien.» Y ¡Bumm! nos encontramos con que nada más lejos de la realidad. Con los mismos parámetros, solo cambiando el hue, unos colores contrastarán bien y pasarán los test de accesibilidad y otros no.

Esto se debe a que HSL (y RGB) no está pensado para funcionar de la misma forma a cómo funciona el ojo humano, ya que este no ve todos los colores por igual.

Ejemplo, con valores aproximados, de como cambiando solo el hue cambia totalmente el contraste al ojo humano.
Ejemplo, con valores aproximados, de como cambiando solo el hue cambia totalmente el contraste al ojo humano.

El futuro próximo

Pero resulta que desde hace muchos años existe el espacio de color CIELAB, diseñado precisamente para aproximarse lo máximo posible a la visión humana y a todo el rango de colores que podemos ver, y en el CSS Working Group están trabajando en la forma de que podamos usar ese perfil de color en CSS con las nuevas funciones Lab() y LCH(), definidas en CSS Color 4

Aunque al final os dejaré más enlaces, uno de los más recomendados para saber más acerca de estas nuevas funciones es el que escribió Lea Verou en su sitio web titulado: LCH colors in CSS: what, why, and how?.

Estas nuevas formas de usar color nos traen bastantes mejoras y nos soluciona, entre otros, los problemas que comentamos anteriormente (No podíamos acceder a todos los colores que muestra nuestra pantalla y as funciones no son muy human friendly). Con estas nuevas fórmulas podremos acceder a aproximadamente un 50% más de colores porque, como comentamos, muchas pantallas modernas llegan ya al perfil de color P3.

Gamut del perfil de color P3 en comparación con sRGB
Gamut del perfil de color P3 en comparación con sRGB

LAB

La función Lab es menos intuitiva y no nos pararemos mucho en ella. Para definir colores con la función Lab debemos tener en cuenta que los parámetros significan lo siguiente:

  • L: Lightness
    A y B son canales de color que modificaremos con valores numéricos negativos o positivos.
  • A: Verde (-) y rojo (+)
  • B: Azul (-) y amarillo (+)

Ejemplo de color definido con la función LAB.

div {
   color: lab(57% -10.9 16.5);
}

LCH

La que es más intuitiva y por extensión a la que dedicaremos más atención es la función LCH, cuyos parámetros significan lo siguiente: L, lightness; C, chroma y H, hue

En LAB y en LCH, Lightness sí funciona como cabría esperar, es decir, que si no alteramos su valor y solo cambiamos el hue, todos los colores los veremos con la misma luminosidad al ojo humano. Lea Verou habla en su artículo de Uniformidad perceptual. Su valor es un porcentaje de 0% a 100% pero pudiendo superar el límite superior, llegando incluso al 400%.

En estas nuevas funciones, a diferencia de RGB o HSL, los cambios numéricos en los distintos parámetros producen un cambio predecible en el color.

Chroma podría ser considerado como la intensidad o vivacidad. Es algo parecido a Saturation en HSL. Pero a diferencia de este, que aceptaba un valor numérico entre 0-100, el valor numérico de Chroma es, en teoría, ilimitado, lo que puede resultar algo confuso al principio.

Esto se debe a que en LCH funciona de forma parecida a como el ser humano ve los colores, que son más de los que una pantalla puede mostrar, por lo tanto, el límite dependerá de cada pantalla. Además, el valor máximo también es distinto para cada color.

Pero entonces, ¿Qué pasa si una pantalla no puede mostrar un determinado color? Pues ningún problema, este se escala y se muestra el más cercano que la pantalla sí es capaz de mostrar.

Hue. Es la rueda de color, con un valor numérico correspondiente al ángulo de 0 a 360, Igual que en HSL, aunque los colores no se corresponden exactamente.

Ejemplo de color definido con la función LCH.

div {
    background-color: lch(65% 50 32)
}

Function color()

Realmente hay otra función nueva en CSS Color 4 que ya nos permite acceder a más colores de nuestra pantalla. Es la función color() , que nos permite definir un color especificando un espacio de color concreto. Una función más avanzada que creo que puede llegar a ser muy útil en algunas ocasiones.

Safari ya tiene soporte para el espacio de color display-p3, por lo que en este navegador ya podemos usar muchos más colores que en con sRGB.

Aquí tenéis un ejemplo. Funciona en Safari, donde veréis un color verde muy intenso definido con la función color(). Si el navegador no lo soporta, se muestra el color rojo.

Y aquí el sitio web Playdate, que también utiliza el perfil de color display-p3 con la función color() en producción.

El selector de color de Safari nos muestra los colores que están fuera del rango de sRGB
El selector de color de Safari nos muestra los colores que están fuera del rango de sRGB

Ejemplo de color definido con la función color().


div {
    color(display-p3 0.8633 0.5115 0.4607)
}

Apuntes de la sintaxis

Cualquiera de las funciones tienen otro parámetro opcional para definir la opacidad.

div {
   color: lch(65% 50 32 / 50%)
   color: lab(57% -10.9 16.5 / 50%)
   color: color(sRGB 0 0.5 1 / 50%)
}

Fíjate también que ninguna de las nuevas funciones tiene comas para separar los valores. Desde hace un tiempo, y con el fin de unificar esta sintaxis, también las funciones RGB y HSL se pueden definir sin comas y además el parámetro opcional de opacidad funciona directamente con la función RGB o HSL (sin la a al final), pero ten en cuenta que esta nueva sintaxis funciona en casi todos los navegadores excepto en el ya vetusto Internet Explorer.

En el artículo de CSS-Tricks titulado No-Comma Color Functions in CSS tenéis más información y ejemplos acerca de esta nueva sintaxis.

Ejemplo de la función HSL con la nueva sintaxis definiendo una opacidad del 50%,

div {
   color: hsl(190deg 30% 50% / 50%)
}

Fallbacks

Para empezar a usar estas funciones podemos usar fallbacks mientras no es soportado en los principales navegadores o para cuando una pantalla no puede mostrar exactamente el color que queremos.

Para asegurarnos del soporte del navegador podemos hacer algo tan simple como en el siguiente ejemplo. Si soporta LCH sobrescribirá a RGB:

div {
    background-color: rgb(72% 36% 32%);
    background-color: lch(51% 44 32);
}

O también podemos usar un fallback para definir específicamente otro color si no soporta exactamente el que queremos:

@supports (color: color(display-p3 0 1 0)) {
  .Element {
    --brightest-green: color(display-p3 0 1 0);
  }
}

.Element {
  color: var(--brightest-green, lightgreen);
}

Soporte actual navegadores:

Todos los grandes navegadores están trabajando en implementarlo, y espero que a corto plazo podamos empezar a utilizar estas nuevas funciones.

A octubre de 2020 el estado actual es el siguiente:

¿Dónde obtener más información?

Iván Barcia

Diseñador y desarrollador web interesado en los estándares web, HTML, CSS, JavaScript, usabilidad, diseño y todo lo que tenga que ver con el front. Actualmente soy desarrollador frontend en OpositaTest.