Color
Lección 04 de 37 · 3 min
CSS acepta el mismo color escrito de varias formas. Todas sirven, pero no todas te dejan razonar igual de bien sobre qué tan claro u oscuro se va a ver.
Cuatro formas de escribir un color
Estas son las notaciones que más vas a cruzarte:
- Hexadecimal
#ff0000Rojo, verde y azul, de00aff. Compacto, pero difícil de leer. - RGB
rgb()Los mismos tres canales, de 0 a 255. - HSL
hsl()Tono en grados, saturación y luminosidad en porcentaje. Más fácil de ajustar a mano. - OKLCH
oklch()Luminosidad, croma y tono, pensados según cómo ve el ojo y no según cómo se mezclan los canales.
El mismo rojo, escrito cuatro veces:
La sintaxis moderna separa los valores con espacios. La vieja, con comas (rgb(255, 0, 0)), sigue funcionando, pero oklch() solo acepta espacios.
Por qué la luminosidad de hsl engaña
En hsl(), la luminosidad es el punto medio entre el canal más alto y el más bajo, no lo que percibe el ojo. Con l en 50%, un amarillo y un azul dicen ser igual de claros, y no lo son.
Mové los controles y compará las dos filas: el número naranja debajo de cada muestra es su luminosidad medida en oklch, y la regla del final ubica las doce en un mismo eje.
Azul glaciarL 0.70
oklch(0.7 0.1 h)
- 00.70
- 600.70
- 1200.70
- 1800.70
- 2400.70
- 3000.70
hsl(h 80% 50%)
- 00.59
- 600.89
- 1200.80
- 1800.84
- 2400.43
- 3000.65
.muestra {background: oklch(0.7 0.1 250);}
<div class="bg-[oklch(0.7_0.1_250)]">Aa</div>
Medidos en oklch, hsl(60 80% 50%) tiene una luminosidad de 0.89 y hsl(240 80% 50%), de 0.44: el amarillo tiene el doble de luminosidad. La fila de oklch mantiene la misma luminosidad en los seis tonos, y por eso se ven parejos.
Eso es lo que se llama uniformidad perceptual: si dos colores tienen la misma luminosidad en oklch, se ven aproximadamente igual de claros. Sirve para elegir un texto con contraste parecido sobre cualquier fondo, o para que ningún color de un gráfico grite más que los otros.
oklch en la práctica
Para armar una paleta, dejá fijos la croma y el tono y cambiá solo la luminosidad. Los pasos se ven igual de espaciados:
:root {--azul-300: oklch(0.8 0.08 250);--azul-500: oklch(0.65 0.08 250);--azul-700: oklch(0.5 0.08 250);--azul-900: oklch(0.35 0.08 250);}
La transparencia va después de una barra: oklch(0.7 0.15 250 / 50%). Y para mezclar dos colores, color-mix() deja elegir en qué espacio se mezclan:
.boton:hover {background: color-mix(in oklch, var(--azul-500) 80%, white);}
Si subís mucho la croma, algunos colores quedan fuera de lo que la pantalla puede mostrar. No es un error: el navegador lo lleva al color más cercano que sí puede pintar.
En Tailwind
La paleta de Tailwind v4 ya está definida en oklch: --color-red-500 vale oklch(63.7% 0.237 25.331). Cada color del tema genera utilidades como bg-red-500, text-red-500 o border-red-500. Para un color que no está en el tema, escribilo entre corchetes con guiones bajos en lugar de espacios, o apuntá a una variable con paréntesis:
| CSS | Tailwind |
|---|---|
| background-color: var(--color-red-500) | bg-red-500 |
| color: var(--color-sky-500) | text-sky-500 |
| rojo al 50% de opacidad | bg-red-500/50 |
| background-color: oklch(0.7 0.1 250) | bg-[oklch(0.7_0.1_250)] |
| background-color: var(--mi-color) | bg-(--mi-color) |
Para sumar un color propio al tema, definilo en @theme con el prefijo --color- y Tailwind genera bg-marca, text-marca y el resto:
@import "tailwindcss";@theme {--color-marca: oklch(0.65 0.08 250);}
<button class="bg-marca text-white hover:bg-marca/80">Guardar</button>
Color
Lesson 04 of 37 · 3 min
CSS accepts the same color written in several ways. They all work, but not all of them let you reason equally well about how light or dark it will look.
Four ways to write a color
These are the notations you'll run into most:
- Hexadecimal
#ff0000Red, green and blue, from00toff. Compact, but hard to read. - RGB
rgb()The same three channels, from 0 to 255. - HSL
hsl()Hue in degrees, saturation and lightness in percent. Easier to tweak by hand. - OKLCH
oklch()Lightness, chroma and hue, designed around how the eye sees rather than how the channels mix.
The same red, written four times:
The modern syntax separates values with spaces. The old one, with commas (rgb(255, 0, 0)), still works, but oklch() only accepts spaces.
Why hsl lightness misleads
In hsl(), lightness is the midpoint between the highest and lowest channel, not what the eye perceives. With l at 50%, a yellow and a blue claim to be equally light, and they aren't.
Move the controls and compare the two rows: the orange number under each swatch is its lightness measured in oklch, and the ruler at the end places all twelve on one axis.
Glacier blueL 0.70
oklch(0.7 0.1 h)
- 00.70
- 600.70
- 1200.70
- 1800.70
- 2400.70
- 3000.70
hsl(h 80% 50%)
- 00.59
- 600.89
- 1200.80
- 1800.84
- 2400.43
- 3000.65
.swatch {background: oklch(0.7 0.1 250);}
<div class="bg-[oklch(0.7_0.1_250)]">Aa</div>
Measured in oklch, hsl(60 80% 50%) has a lightness of 0.89 and hsl(240 80% 50%) has 0.44: the yellow has double the lightness. The oklch row keeps the same lightness across all six hues, which is why they look even.
That's called perceptual uniformity: if two colors have the same lightness in oklch, they look roughly equally light. It helps you pick text with similar contrast on any background, or keep any one color in a chart from shouting louder than the rest.
oklch in practice
To build a palette, keep chroma and hue fixed and change only lightness. The steps look evenly spaced:
:root {--blue-300: oklch(0.8 0.08 250);--blue-500: oklch(0.65 0.08 250);--blue-700: oklch(0.5 0.08 250);--blue-900: oklch(0.35 0.08 250);}
Transparency goes after a slash: oklch(0.7 0.15 250 / 50%). And to mix two colors, color-mix() lets you choose the space they mix in:
.button:hover {background: color-mix(in oklch, var(--blue-500) 80%, white);}
If you push chroma high, some colors fall outside what the screen can show. That isn't an error: the browser maps them to the closest color it can paint.
In Tailwind
Tailwind v4's palette is already defined in oklch: --color-red-500 is oklch(63.7% 0.237 25.331). Every theme color generates utilities like bg-red-500, text-red-500 or border-red-500. For a color that isn't in the theme, write it in brackets with underscores instead of spaces, or point at a variable with parentheses:
| CSS | Tailwind |
|---|---|
| background-color: var(--color-red-500) | bg-red-500 |
| color: var(--color-sky-500) | text-sky-500 |
| red at 50% opacity | bg-red-500/50 |
| background-color: oklch(0.7 0.1 250) | bg-[oklch(0.7_0.1_250)] |
| background-color: var(--my-color) | bg-(--my-color) |
To add your own color to the theme, define it in @theme with the --color- prefix and Tailwind generates bg-brand, text-brand and the rest:
@import "tailwindcss";@theme {--color-brand: oklch(0.65 0.08 250);}
<button class="bg-brand text-white hover:bg-brand/80">Save</button>