name: oklch-palette-formula description: Construye o migra la paleta neutra de una interfaz (fondos, superficies, líneas, texto/tinta) como una fórmula OKLCH impulsada por pocas entradas en lugar de docenas de valores hexadecimales elegidos manualmente, con temas claro y oscuro, anulaciones por escalón, un script de ajuste que reproduce colores existentes y una auditoría de contraste en navegador. Útil al crear un tema, añadir modo oscuro, retintear un producto, auditar contraste de texto o consolidar paletas de varias aplicaciones. Se activa con: paleta, neutros, rampa de grises, modo oscuro, tokens de tema, oklch, retinte, tono, auditoría de contraste, tokens de diseño, colores Tailwind @theme. license: MIT
Fórmula de paleta OKLCH
Los neutros de un producto (fondo de página, superficie de tarjeta, campos, líneas finas, cuatro niveles de texto) suelen ser de 15 a 30 valores hexadecimales por tema, elegidos a ojo. Estos valores derivan, el modo oscuro es un segundo conjunto elegido manualmente y nadie sabe qué pares todavía pasan el contraste. Reemplázalos con una fórmula:
token tipo superficie: L = papel + profundidad × n(token) croma = tinte tono = tono
token tipo tinta: L = tinta + paso × n(token) croma = tinte-tinta tono = tono
n(token) es la posición del token en una escalera, una escalera por tema.
Mueve una entrada y toda la rampa se mueve junta, así que los espacios entre escalones,
donde vive el contraste, sobreviven a un retinte. Retintear un producto es una línea (--hue).
Tres perillas (--hue, --lightness, --chroma o --contrast) guían cada
color.
Archivos
references/palette.css: reglas listas para usar con entradas y escaleras predeterminadas.scripts/fit_palette.py: ajusta las entradas a una paleta hexadecimal existente e imprime ΔE por token.scripts/ladders.json: las escaleras predeterminadas (claro, oscuro).scripts/palette-audit.mjs: resuelve cada token en un navegador real en ambos temas y falla en contraste.scripts/oklch.py: conversiones y helpers de ΔE / WCAG.
Procedimiento
-
Nombra los tokens por su función, no por su valor. Los valores predeterminados:
- Fondos:
ground(página),panel(barras, rieles),surface(tarjetas, menús),surface-2(campos),surface-3(chips, filas hover),field. - Líneas:
line,line-2,line-3(líneas finas, de más claras a más oscuras), másfield-line, el borde de un control, que debe superar 3:1. - Tinta:
ink,ink-2,ink-3,ink-4(texto, de más oscuro a más claro). Cada paso de tinta es texto, así que cada uno debe superar 4.5:1.
- Fondos:
-
Ajusta, no vuelvas a elegir. Para un producto existente, ejecuta
python3 scripts/fit_palette.py theme.css. Lee las declaraciones--color-*hexadecimales (claro y luego la regla[data-theme="dark"]), ajusta las entradas contra la escalera predeterminada e imprime ΔE por token. Menos de 2 es visualmente idéntico. -
Anula pasos de la escalera donde el diseño los espacie de forma diferente, nunca el color. Evalúa candidatos con
fit_palette.py theme.css light '<inputs>' '<overrides>'hasta que el peor ΔE esté por debajo de ~2. Anulaciones típicas:field: 0(los campos son la cara de la tarjeta), unline-3más ancho, un mayor espacio entreinkeink-2. -
Escribe las reglas (ver
references/palette.css):- Coloca las entradas y las fórmulas
--color-*en el elemento que lleva el atributo del tema. - Vuelve a declarar cada entrada que cambies en la regla oscura. Una regla oscura escrita para los valores predeterminados del kit, de lo contrario, gana con sus valores.
- Con Tailwind v4, mantén los nombres de los tokens en
@themepara que las utilidades existan; las declaraciones en tiempo de ejecución las anulan.
- Coloca las entradas y las fórmulas
-
Audita en un navegador real:
node scripts/palette-audit.mjs <url>. Pinta cada token, lee el sRGB de vuelta y verifica:- cada paso de tinta a 4.5:1 contra cada fondo;
field-lineyringa 3:1.
Corrige un FALLO moviendo el paso de la escalera de ese token, no poniendo una excepción de color. Espera FALLOS en paletas existentes: en una migración de 17 aplicaciones la auditoría encontró valores de
ink-4ofield-lineque fallaban en más de la mitad, todos ellos publicados anteriormente.
Trampas
var()dentro de una propiedad personalizada se resuelve donde se declara.- Declara las fórmulas en
:rooty establece las entradas en un hijo: el hijo nunca se recolorea. - Los tokens alias (
--color-heading: var(--color-ink)) también deben declararse en el mismo elemento temático.
- Declara las fórmulas en
- Los valores de
@themede Tailwind v4 viven en:root. Un tema con ámbito en la raíz de una aplicación ([data-app]) debe declarar la fórmula allí, no en@theme. - Cualquier cosa que pase colores a un lienzo o biblioteca de mapas
(
getComputedStyle(...).getPropertyValue('--color-x')) ahora recibe una cadenaoklch(calc(...))sin resolver. Resuélvela primero: pinta un elemento de prueba y lee un lienzo de 1px, de la misma manera que lo hace la auditoría. - Un solo tono para fondos y tintas. Si el diseño de las tintas tiene un tono
diferente al de los fondos, mantén
--ink-tintbajo; en L 0.98 cualquier croma se lee como un matiz de color. - Los colores de marca, estado y gráficos quedan fuera de la fórmula. Deriva
variantes de texto sobre tinte (por ejemplo
brand-text) a partir del mismo tono con una luminosidad fija en lugar de elegirlos por separado. - Las paletas de tono mixto, solo claras, muestreadas de composiciones pueden no ajustarse a ~2 ΔE. Omítelas en lugar de distorsionar el diseño. La auditoría sigue aplicándose.