Colores
Un sistema de color es un conjunto pequeño de rampas, nombradas por rol y verificadas contra los fondos sobre los que realmente se renderizan. La mayoría de los errores de color son errores de sistema. Un valor elegido de forma aislada, un token prestado porque parecía correcto, un par que nadie midió.
Nunca reportes un valor de contraste que no hayas medido, y nunca estimes un color que puedas calcular. Los colores son una de las pocas preocupaciones de la interfaz que tienen una respuesta exacta, así que proporciona la respuesta exacta.
Los requisitos de contraste pertenecen a hr-better-accessibility. Las superficies, sombras y el color de los iconos quedan fuera de este skill.
Adaptarse al sistema de color del proyecto
Reutiliza los tokens y la notación del proyecto. Una segunda representación añadida para corregir un valor hace que la paleta sea más difícil de razonar. Un sistema hex consistente supera a hex con oklch() disperso por todas partes.
Una vez que los tokens existen, refuérzalos con una regla de lint o una prueba de guardia que falle ante un literal de color fuera de los archivos de tokens, con una lista blanca corta para los lugares que necesitan valores brutos por diseño. Una regla "usa tokens" por escrito sin una verificación detrás se desvía.
Para un sistema nuevo, oklch() es el mejor valor por defecto, porque sus números se comportan como describen las reglas de rampa a continuación. En cualquier otro caso, una biblioteca de color produce la misma rampa en la notación propia del proyecto (color-formats.md).
Un sistema son rampas, no colores
Una rampa neutral, una rampa de acento y solo las rampas de estado que el producto realmente renderiza. Una rampa warning que nada importa es mantenimiento para cero píxeles. Un segundo tono de acento se gana su lugar solo cuando dos cosas deben ser distinguibles de un vistazo.
Cada paso tiene un trabajo
Una rampa no es un degradado del que elegir a ojo. Cada paso existe porque un rol lo necesita: fondo de página, hover de componente, borde, relleno sólido, texto del cuerpo. No generes un paso que ningún rol consuma. Tanto las convenciones 50–950 de Tailwind como 1–12 de Radix se asignan a esos roles (palette-structure.md).
Nombra los primitivos por tono, los semánticos por rol
Los primitivos nombran un valor (--blue-500) y nunca se aplican en un componente. Los tokens semánticos nombran un trabajo (--color-text-secondary), apuntan a un primitivo y son el único nivel al que los componentes hacen referencia.
Esa separación es lo que hace posible la tematización. Sin ella, el modo oscuro implica auditar cada uso para determinar cuál significaba "el acento" y cuál solo quería azul (token-naming.md).
Usa un token solo en su rol
Nunca tomes prestado un token porque su valor es correcto hoy. Un separador usado como color de texto funciona hasta que los bordes se aclaren, y entonces el texto se va con ellos. Si un rol no tiene token, añade el token.
Mantén el tono constante a lo largo de la rampa
Cuatro propiedades definen una rampa bien formada:
- Los pasos siguen una progresión deliberada de luminosidad percibida (palette-generation.md).
- El tono se mantiene constante de extremo a extremo.
- La viveza alcanza su punto máximo a mitad de la rampa y disminuye en ambos extremos.
- Los pasos están más densos en el extremo claro que en el extremo oscuro.
Ambos extremos se detienen antes del blanco y negro puros, que no pueden transportar ningún tono. Usa una biblioteca de color en lugar de hacerlo a ojo (palette-generation.md).
Un color, un significado
Usa un color para un solo propósito en toda la interfaz, tratando cualquier cosa dentro de 15° de tono como el mismo color. Si el acento significa interactivo, ese tono en texto estático indica a los usuarios que hagan clic en algo que no es cliqueable, y un elemento interactivo renderizado en neutral engaña igual de mal. El color nunca es el único portador de significado, lo cual es responsabilidad de hr-better-accessibility.
Rellena exactamente una acción por vista
Cuando el color relleno codifica el énfasis principal, una acción principal lo recibe y los pares permanecen neutrales. Pon el color en el fondo, no en la etiqueta. Un botón relleno se lee como principal desde el otro lado de la habitación; texto de color acento sobre un botón neutral se lee como un enlace.
Varios fondos de color están bien cuando codifican estados o categorías distintas en lugar de competir como pares.
Mide el par renderizado, luego reporta
Mide un primer plano contra el fondo sobre el que realmente se renderiza, no contra el fondo de la página. Cuando un par falla, reporta el par, su valor medido y el umbral que no alcanza, luego deja los colores como están. Son una decisión de diseño. Cámbialos solo cuando te lo pidan, y vuelve a medir después (contrast.md).
Elige un espacio de interpolación para el degradado
El espacio es una apariencia, no una configuración de corrección.
in oklabes el mejor valor por defecto: brillo uniforme, sin sorpresas de tono.in oklchviaja alrededor de la rueda cromática en lugar de pasar por el medio, manteniéndose vívido y barriendo todos los tonos entre los puntos de parada. Úsalo cuando un degradado de dos tonos se vuelva gris en el medio.- El valor por defecto sRGB oscurece y amortigua el punto medio. Es lo que la mayoría de las interfaces ya tienen, porque es lo que obtienes sin preguntar.
Consulta color-usage.md.
Antes de terminar
| Error | Corrección |
|---|---|
| Un valor bruto donde el proyecto tiene un token | Reutiliza o añade el token de rol, en la notación del proyecto |
Un valor oklch() aislado insertado en una base de código hex | Mantén la notación establecida a menos que una migración esté en el alcance |
Un primitivo como --blue-500 usado directamente en un componente | Apunta un token semántico hacia él |
Token nombrado por su apariencia (--color-blue-button) o primer uso (--color-sidebar-gray) | Nómbralo por su rol: --color-accent-solid, --color-bg-surface |
--color-primary significando la marca y --color-text-primary significando texto del cuerpo | Reserva accent para la marca; deja que primary signifique "el más prominente de su grupo" |
| Token semántico usado fuera de su rol (separador como texto) | Añade un token para el rol faltante; nunca tomes prestado por valor |
| Rampa construida variando la luminosidad HSL | Reconstruye contra la luminosidad percibida con un tono constante |
| Rampa espaciada uniformemente en todo el rango | Aprieta el extremo claro hasta que 50 y 100 se lean como dos superficies |
| Mismo número de saturación reutilizado entre tonos | Iguala la proporción del máximo de cada tono, no el valor bruto |
| Tono de estado que choca con el tono de acento | Muévelo hasta que destructivo y principal se lean distinto lado a lado |
| Modo oscuro hecho invirtiendo mecánicamente la paleta clara | Invierte como punto de partida, luego reduce viveza, ensancha el extremo oscuro y vuelve a verificar cada par |
prefers-color-scheme estableciendo algunos tokens y una clase .dark estableciendo otros | Elige un mecanismo de conmutación y úsalo en todas partes |
| Contraste corregido cambiando el tono | Cambia la luminosidad, el canal al que responde el contraste |
| Color P3 sin fallback sRGB | Declara el valor sRGB primero, luego sobrescribe dentro de @media (color-gamut: p3) |
Reporte
Severidad. HIGH hace que el contenido sea ilegible o asigna un color semántico engañoso. MEDIUM es un fallo notable de tema, token o gama. LOW es un retoque aislado.
Verificación. Sin navegador: valores de tokens, la gama de cada color declarado, ambos bloques de tema presentes y contraste calculado a partir del par de tokens declarado. Con uno: el fondo realmente renderizado detrás del texto, incluyendo opacidad y cualquier imagen debajo, medido tanto en modo claro como oscuro. Un par que falla se reporta, no se vuelve a pintar. Reporta cada verificación que no pudiste ejecutar como No verificado.
Formato. Agrupa los hallazgos bajo el principio que violan, ordenados por severidad, una fila por causa raíz listando cada ubicación en la que aparece:
| Severidad | Ubicación | Antes | Después | Por qué |
|---|
Ubicación es ruta/al/archivo:línea. Por qué nombra el principio y el impacto en el usuario.
Reporta Bloqueado cuando quede algún HIGH, Aprobado en caso contrario, dejando el resto en la tabla como trabajo pendiente. Nunca Aprobado una cobertura que no inspeccionaste. Si no hay nada que reportar, indica "No se encontraron hallazgos de color procesables" y reporta verificación.