Primitivos
Espacio de color
Por qué DesignToken101 construye sus escalas de color en oklch y las guarda en sRGB, qué pasa con los colores fuera de gama, qué límites tiene Figma y cómo reproducir las conversiones con el script del repositorio.
Última revisión:
Los colores de DesignToken101 no se eligieron uno a uno en el selector de Figma. Se generaron a partir de un único color de marca, con un método que trabaja en un espacio de color (oklch) y guarda el resultado en otro (sRGB). En esta lección verás cómo se hizo, qué significa cada espacio, por qué los separamos, qué límites tiene Figma y cómo reproducir las conversiones con el script del repositorio.
En esta página
- Cómo se crearon los colores de DesignToken101
- Espacio de color y gama
- Por qué construir en oklch
- Por qué guardar en sRGB
- Colores fuera de gama
- Los límites de Figma
- El contraste se mide sobre lo que se guarda
- En Figma
- Lo que te llevas
Cómo se crearon los colores de DesignToken101
- Elegir el color de marca, Un único color: #33CC99
- Generar las escalas, Script, en oklch: 11 pasos por escala
- Ajustar a sRGB, El script reduce el croma si no cabe
- Copiar los hex a Figma, Variables de la colección Primitives
- Diseñar con tokens semánticos, Alias de esos primitivos
- Exportar y generar el CSS, El mismo hex, sin conversión
- Elegir el color de marca. Es la decisión de partida:
#33CC99, en HSL 160°, 60 %, 50 %. Las demás decisiones estéticas (cuánto tinte llevan los grises, cuánto croma las escalas de estado) son parámetros del método. - Generar las escalas. El script
tools/scales.pyconvierte el color de marca a oklch y calcula once pasos para el acento, once para los neutros y once para cada color de estado. Cómo calcula cada paso lo verás en Escalas de color. - Ajustar a sRGB. Si algún paso calculado no existe en sRGB, el script lo convierte en el más parecido que sí existe. Da como resultado un hex por paso.
- Copiar los hex a Figma. Cada hex se escribe en una variable Color de la colección
Primitives:color/emerald/500=#33CC99. Figma no genera escalas; recibe los valores ya calculados. - Diseñar con tokens semánticos. Al diseñar, nadie aplica un hex ni un primitivo: se aplican tokens semánticos como
color/text/neutral/default, que apuntan a los primitivos. Los verás en el módulo Relaciones. - Exportar y generar el CSS. La exportación de Figma lleva los mismos hex al código, sin conversiones. Lo verás en el módulo De Figma al código.
Y el contraste. El contraste no se usó para generar las escalas. Se calcula después, sobre cada hex, para saber qué pasos sirven para texto, para bordes o para fondos. Con esas cifras se decide a qué paso apunta cada token semántico: por ejemplo, que el texto de los enlaces en Light use emerald/700 y no el color de marca, que no llega a 4,5:1 sobre blanco.
Nota
Si no quieres usar un script, puedes hacer los pasos 2 y 3 con un selector de color que trabaje en oklch y muestre los límites de sRGB, como oklch.com, de Evil Martians. Es más lento y menos exacto, pero el método es el mismo.
Los apartados siguientes explican por qué el proceso es así.
Espacio de color y gama
Un espacio de color es una forma organizada de describir colores con coordenadas, normalmente tres. Cada espacio tiene una gama: el conjunto de colores que puede representar (MDN: Color space).
Tres espacios aparecen en este curso:
| Espacio | Qué es | Coordenadas |
|---|---|---|
| sRGB | El espacio estándar de la web y el más compatible. Su gama es más estrecha que la de Display P3 | Rojo, verde y azul, de 0 a 1 (o un hex como #33CC99) |
| Display P3 | Un espacio de gama más ancha, típico de las pantallas de gama ancha actuales: verdes y rojos más intensos que sRGB | Rojo, verde y azul, de 0 a 1 |
| oklch | Una forma de describir el color según cómo lo percibimos, basada en Oklab | Luminosidad (L), croma (C) y tono (H) |
Las dos primeras definiciones son de MDN (misma fuente). Oklab es un modelo publicado por Björn Ottosson en 2020 para que los cambios de luminosidad, croma y tono se perciban como independientes entre sí (Ottosson: A perceptual color space for image processing). oklch es su forma polar.
Nota
oklch no tiene una gama propia limitada como sRGB: su croma no tiene un máximo teórico, aunque en la práctica no supera 0,5 (MDN: oklch()). Por eso con oklch puedes escribir colores que ninguna pantalla sRGB puede mostrar.
Para entender mejor oklch. Es un concepto difícil de captar solo leyendo. Estos recursos lo muestran de forma visual:
- Vídeo: Thinking on ways to solve color palettes, de Adam Argyle (Chrome for Developers, 2023, unos 24 minutos, en inglés). Compara HSL con LCH y construye paletas en oklch.
- Herramienta: oklch.com, de Evil Martians. Mueve L, C y H y verás dónde termina la gama sRGB.
- Artículo: OKLCH, explained for designers, de Samuel Wong (UX Collective, 2025, en inglés). Es un blog, no documentación oficial.
Por qué construir en oklch
En oklch, L representa la luminosidad tal como la percibimos (MDN: oklch()). En HSL, uno de los modelos del selector de color de Figma, la luminosidad es una cuenta sobre los canales RGB, no una medida de lo que vemos.
Un ejemplo lo muestra. No es una prueba para elegir colores, sino una comparación calculada con el script: tres colores con la misma luminosidad en HSL, 50 %.
| Color en HSL | Hex | L en oklch | Contraste con blanco |
|---|---|---|---|
hsl(60 100% 50%), amarillo | #FFFF00 | 0,968 | 1,07:1 |
hsl(120 100% 50%), verde | #00FF00 | 0,866 | 1,37:1 |
hsl(240 100% 50%), azul | #0000FF | 0,452 | 8,59:1 |
Para HSL los tres son "igual de claros". A la vista, y para el contraste, no se parecen en nada. oklch sí refleja la diferencia.
Para una escala, eso importa por dos motivos:
- Pasos regulares. Si fijas la L de cada paso, el salto visual entre dos pasos es parecido en cualquier tono.
- Claridad comparable. Dos pasos con L muy distinta se ven muy distintos en claridad. El contraste de WCAG, en cambio, se calcula con otra fórmula, así que la cifra hay que calcularla siempre (lo verás abajo).
Recomendación
DesignToken101 construye las escalas en oklch: decide la L y el croma de cada paso y mantiene el tono. Es lo mismo que hace Tailwind CSS, cuya paleta por defecto se define en oklch desde la versión 4 (Tailwind CSS: Colors).
Por qué guardar en sRGB
Lo que dicen las fuentes:
- La importación de variables en formato DTCG de Figma admite color en sRGB y HSL (Figma: Modes for variables).
- Los archivos nuevos de Figma usan el perfil de color sRGB. Se puede cambiar a Display P3 en cualquier plan; al convertir el perfil, los valores de las variables de color no cambian (Figma: Manage color profiles).
- El Color Module de DTCG admite catorce espacios de color, entre ellos
srgb,display-p3yoklch, y unhexopcional de reserva (Color Module 2025.10). - Al exportar las variables de esta web, Figma escribe cada color con
"colorSpace": "srgb"y suhex(comprobado en la exportación).
Recomendación
DesignToken101 guarda los colores en sRGB. Los valores sRGB son la fuente de verdad en Figma, el archivo trabaja con el perfil sRGB y el CSS escribe el mismo valor en hexadecimal, sin conversiones. Así, el color que ves en Figma es el que se exporta y el que llega a la web.
Por qué no Display P3. Daría verdes más intensos en las pantallas que lo admiten. Lo descartamos porque la importación DTCG de Figma no lo admite y porque añade una capa de complejidad al curso. Es una decisión nuestra; no es una norma.
Colores fuera de gama
Construir en oklch y guardar en sRGB tiene una consecuencia: algunas combinaciones de L, C y H no caben en sRGB. Hay que llevarlas a un color que sí quepa.
La propia paleta de Tailwind CSS lo muestra. Desde la versión 4 aprovecha la gama más ancha de las pantallas modernas para que los colores sean más intensos (Tailwind CSS v4.0). Con el script del repositorio comprobamos que green-500, green-600 y green-700 de Tailwind quedan fuera de sRGB: green-500 tiene un croma de 0,219, y en sRGB su máximo con esa L y ese tono es 0,201.
El método de DesignToken101 para llevar un color a sRGB:
- Se conservan L y H. El color sigue siendo igual de claro y del mismo tono.
- Se reduce el croma hasta que el color cabe.
El módulo CSS Color 4 del W3C sigue la misma idea: su algoritmo de mapeo de gama trabaja en OKLCh y reduce el croma (CSS Color 4: Gamut mapping). Es un borrador de recomendación candidata, no una recomendación final.
Nota
En las escalas de DesignToken101 el ajuste no llega a actuar: al multiplicar el croma de Tailwind por 0,66 (lo verás en Escalas de color), todos los pasos caben en sRGB. El ajuste está en el método para que funcione con cualquier color de marca.
Los límites de Figma
- El selector de color acepta oklch. El modelo de color CSS del selector admite
oklch(),oklab()ycolor(display-p3 …), y Figma guarda el valor en el espacio de color en el que lo escribiste, sin convertirlo (Figma: Color models). - La importación DTCG no acepta oklch. Admite sRGB y HSL (Figma: Modes for variables).
- Figma no genera escalas. Puedes escribir un color, pero el método (L por paso, croma, ajuste de gama) lo tienes que aplicar tú o un script.
Recomendación
En DesignToken101 escribimos en Figma el hex en sRGB que da el script, no el valor en oklch. Es el espacio que admite la importación DTCG de Figma y el del perfil de color del archivo, así que lo que guarda Figma es lo que llega al CSS.
El contraste se mide sobre lo que se guarda
WCAG 2.2 calcula el contraste a partir de la luminancia relativa de cada color en sRGB, y pide no redondear: 4,499:1 no cumple el mínimo de 4,5:1 (Understanding 1.4.3).
Recomendación
En DesignToken101 el contraste se calcula siempre sobre el hex guardado, no sobre la L de oklch ni sobre el valor antes de redondear al hex. La L sirve para construir la escala; la cifra que vale para accesibilidad es la de WCAG sobre el color final.
En Figma
- Comprueba que el archivo usa el perfil de color sRGB (Figma: Manage color profiles). Es el valor por defecto.
- Al crear una variable Color, escribe su valor en hex, el que da el script. No hace falta cambiar el modelo de color del selector.
Las variables de color las crearás en Escalas de color.
El script del repositorio no tiene dependencias: funciona con Python 3. Desde la raíz del repositorio, abre Python y carga sus funciones:
import sys; sys.path.insert(0, "tools")
import scales as s
# De hex a oklch: L, C, H
s.rgb_to_oklch(*s.hex_to_rgb("#33CC99"))
# → (0.755, 0.145, 165.4), redondeado
# De oklch a sRGB, con ajuste de gama: devuelve el color y el croma usado
rgb, croma = s.oklch_to_rgb_gamut(0.723, 0.219, 149.6)
s.hexs(rgb), croma
# → ('#00C65A', 0.201): el croma 0.219 no cabía y se reduce a 0.201
# Contraste WCAG entre dos colores guardados
s.contrast(s.hex_to_rgb("#1A7D5C"), [1, 1, 1])
# → 5.082…Las fórmulas de conversión son las de Ottosson. oklch_to_rgb_gamut busca el croma máximo que cabe en sRGB con la L y el tono que le das.
Lo que te llevas
- Las escalas se construyen en oklch, porque su L representa la luminosidad tal como la percibimos.
- Los colores se guardan en sRGB, que es lo que Figma importa y exporta sin conversiones.
- El contraste se mide sobre el hex guardado, no sobre los valores con los que se calculó.
Fuentes
- MDN: Color space
- MDN: oklch()
- Björn Ottosson: A perceptual color space for image processing (blog del autor de Oklab)
- Design Tokens Color Module 2025.10
- Figma: Modes for variables
- Figma: Manage color profiles in design files
- Figma: Color models in Figma Design
- oklch.com (herramienta de Evil Martians)
- Adam Argyle, Thinking on ways to solve color palettes (vídeo, Chrome for Developers, 2023)
- Samuel Wong, OKLCH, explained for designers (blog, UX Collective, 2025)
- CSS Color Module Level 4: Gamut mapping
- Tailwind CSS: Colors
- Tailwind CSS v4.0 (blog oficial)
- WCAG 2.2: Understanding 1.4.3 Contrast (Minimum)