CSS color-mix(): Mezcla Colores Nativamente en el Navegador
Durante años, generar variantes de color en CSS requería codificar en duro cada tono a mano o recurrir a JavaScript y una biblioteca de manipulación de colores como chroma.js o tinycolor2. La función CSS color-mix() cambia esto. Es una función CSS nativa, ahora soportada en todos los navegadores principales, que mezcla dos colores juntos en una proporción especificada — directamente en tu hoja de estilos, sin JavaScript, sin preprocesamiento.
Este artículo cubre la sintaxis completa, explica por qué la elección del espacio de color lo cambia todo, recorre los casos de uso prácticos que hacen que color-mix() sea genuinamente útil, y aborda el soporte de navegadores y las estrategias de fallback.
¿Qué Es color-mix()?
color-mix() es una función de CSS Color Level 5 que toma dos valores de color y una proporción de mezcla, y devuelve el color mezclado resultante. Es el equivalente CSS de mezclar dos pinturas juntas, pero con un parámetro extra crítico: el espacio de color en el que ocurre la mezcla.
El caso de uso más simple es crear tintes y sombras a partir de un color base. En lugar de definir cada variante de sombra de tu azul de marca a mano, puedes derivarlas dinámicamente:
:root {
--brand-blue: #2563EB;
/* Tintes — mezclar con blanco */
--brand-blue-light: color-mix(in oklch, var(--brand-blue) 60%, white);
--brand-blue-lighter: color-mix(in oklch, var(--brand-blue) 30%, white);
/* Sombras — mezclar con negro */
--brand-blue-dark: color-mix(in oklch, var(--brand-blue) 80%, black);
--brand-blue-darker: color-mix(in oklch, var(--brand-blue) 50%, black);
}
El azul base #2563EB se define una vez. Los tintes y sombras se derivan de él. Si el color de marca cambia, todas las variantes se actualizan automáticamente.
Sintaxis y Parámetros
La sintaxis completa de color-mix() es:
color-mix(in <color-space>, <color1> [<percentage>]?, <color2> [<percentage>]?)
El Parámetro de Espacio de Color
El primer argumento, in <color-space>, es requerido y especifica dónde ocurre la mezcla. Las opciones válidas incluyen:
srgb— mezcla en RGB estándar (el más familiar, pero propenso a puntos medios lodosos)hsl— mezcla siguiendo el cilindro HSLhwb— mezcla en HWB (Tono, Blancura, Negrura)lab— mezcla en CIE Lab (perceptualmente uniforme)oklab— mezcla en Oklab (mejor uniformidad que CIE Lab)lch— mezcla en LCH (CIE Lab cilíndrico)oklch— mezcla en OKLCH (Oklab cilíndrico, recomendado para la mayoría de usos)display-p3— mezcla en gama amplia Display P3xyz— mezcla en CIE XYZ
Para la mayoría del trabajo de diseño, oklch produce los resultados más perceptualmente naturales. Más sobre esto en la siguiente sección.
Los Argumentos de Color
Los dos valores de color pueden ser cualquier color CSS válido: códigos hex, rgb(), hsl(), oklch(), colores con nombre o propiedades personalizadas CSS. Cada uno puede opcionalmente tener un porcentaje que indica cuánto de ese color contribuye a la mezcla:
/* Mezcla 50/50 (predeterminado cuando no se dan porcentajes) */
color-mix(in oklch, #FF5733, #3498DB)
/* 70% primer color, 30% segundo */
color-mix(in oklch, #FF5733 70%, #3498DB 30%)
/* 80% primer color — el porcentaje del segundo color se infiere como 20% */
color-mix(in oklch, #FF5733 80%, #3498DB)
Si los porcentajes suman menos del 100%, el resultado es parcialmente transparente. Si superan el 100%, los porcentajes se normalizan. Si no se especifica ningún porcentaje, la mezcla es 50/50.
/* Estas son equivalentes */
color-mix(in srgb, blue, red)
color-mix(in srgb, blue 50%, red 50%)
color-mix(in srgb, blue 50%, red)
Mezclar en Diferentes Espacios de Color
La elección del espacio de color no es cosmética — cambia fundamentalmente el color producido. Los mismos dos colores mezclados en diferentes espacios producen resultados dramáticamente diferentes.
Mezclar en sRGB
La mezcla sRGB funciona interpolando los canales Rojo, Verde y Azul linealmente. Para muchos pares de colores esto produce resultados aceptables, pero los colores complementarios (los que están en lados opuestos de la rueda de color) a menudo producen un punto medio desaturado y grisáceo.
/* Mezclar naranja-rojo y azul en sRGB */
color-mix(in srgb, #FF5733 50%, #3498DB 50%)
/* Resultado: un morado apagado, algo marrón — rango [#9A77B7] */
El problema es que los canales RGB de los colores complementarios se cancelan entre sí cuando se promedian. Rojo [255, 87, 51] y Azul [52, 152, 219] producen un punto medio de [154, 120, 135] — un resultado desaturado y apagado.
Mezclar en HSL
La mezcla HSL interpola a lo largo de la rueda de tonos, lo que puede causar un problema diferente: rotación de tono a través de colores intermedios inesperados.
/* Naranja (tono ~15°) mezclado con azul (tono ~210°) en HSL */
color-mix(in hsl, #FF5733 50%, #3498DB 50%)
/* El tono interpola a través de ~112° — obtienes un intermedio verdoso */
Cuando dos colores están muy separados en la rueda de tonos, el camino más corto entre ellos en HSL puede pasar por el verde u otros tonos inesperados. HSL también comparte el problema de no uniformidad perceptual de hsl() en general — la luminosidad del punto medio puede no parecer a mitad de camino entre las dos luminosidades de origen.
Mezclar en OKLCH
La mezcla OKLCH es el enfoque recomendado para la mayoría de los casos de uso prácticos. Interpola en un espacio perceptualmente uniforme, lo que significa que los colores intermedios parecen puntos medios visuales naturales — vívidos, equilibrados y sin deriva inesperada del tono.
/* Naranja-rojo mezclado con azul en OKLCH */
color-mix(in oklch, #FF5733 50%, #3498DB 50%)
/* Resultado: un magenta-morado vívido — perceptualmente a mitad de camino */
#FF5733 (un naranja-rojo cálido) y #3498DB (un azul brillante) mezclados 50/50 en OKLCH produce un intermedio vibrante y saturado. El tono interpola directamente a través del rango morado — exactamente lo que un diseñador esperaría cuando se le pide "dividir la diferencia" entre naranja y azul.
Mezclar en Oklab (Caminos de Tono Más Cortos / Más Largos)
Para la interpolación de tono, también puedes especificar si tomar el arco más corto o más largo alrededor de la rueda de color:
/* Camino de tono más corto (predeterminado) */
color-mix(in oklch shorter hue, red, blue)
/* Camino de tono más largo — va por el otro lado de la rueda */
color-mix(in oklch longer hue, red, blue)
/* Tono creciente */
color-mix(in oklch increasing hue, red, blue)
Este control es útil cuando deliberadamente quieres una interpolación que pase por tonos intermedios específicos — por ejemplo, un degradado que va de rojo a través del amarillo hasta el azul en lugar de a través del morado.
Tabla Comparativa
| Espacio de color | Punto medio Naranja + Azul | Carácter visual |
|---|---|---|
srgb |
Morado grisáceo apagado | Desaturado, lodoso |
hsl |
Verdoso | Desplazamiento inesperado del tono |
lab |
Morado, menos vívido | Más natural que sRGB |
oklch |
Magenta-morado vívido | El más perceptualmente natural |
Usa el Conversor de Color para explorar los valores OKLCH de tus colores específicos y predecir cómo se mezclarán.
Casos de Uso Prácticos
Creando Estados de Hover y Active
Una de las aplicaciones más inmediatamente útiles es generar estados interactivos sin definir variables separadas para cada uno:
:root {
--btn-bg: oklch(0.55 0.22 250); /* Tu azul de marca */
}
.btn {
background-color: var(--btn-bg);
}
.btn:hover {
/* Oscurecer un 15% mezclando con negro */
background-color: color-mix(in oklch, var(--btn-bg) 85%, black);
}
.btn:active {
/* Oscurecer más para el estado presionado */
background-color: color-mix(in oklch, var(--btn-bg) 70%, black);
}
.btn:disabled {
/* Desaturar y aclarar para el estado deshabilitado */
background-color: color-mix(in oklch, var(--btn-bg) 40%, white);
opacity: 0.6;
}
Esto elimina la necesidad de elegir tres sombras separadas en una herramienta de diseño y codificarlas en duro. Los colores de hover y active se derivan matemáticamente de la base, manteniendo la relación consistente incluso si el color de marca cambia.
Construyendo Escalas de Color Semánticas
Los sistemas de diseño necesitan colores semánticos — éxito, advertencia, peligro — que armonicen con la paleta de marca. color-mix() te permite derivarlos del color de marca en lugar de elegirlos de forma independiente:
:root {
--brand: oklch(0.55 0.22 250); /* Azul de marca */
/* Éxito: mezclar marca con verde puro para retener un toque de identidad de marca */
--success: color-mix(in oklch, oklch(0.65 0.22 145) 85%, var(--brand) 15%);
/* Advertencia: ámbar puro — no se necesita mezcla aquí */
--warning: oklch(0.75 0.18 70);
/* Peligro: rojo puro */
--danger: oklch(0.62 0.24 25);
/* Fondos con tinte para cada estado */
--success-bg: color-mix(in oklch, var(--success) 12%, white);
--warning-bg: color-mix(in oklch, var(--warning) 12%, white);
--danger-bg: color-mix(in oklch, var(--danger) 12%, white);
}
El --success-bg es un tinte muy claro del verde de éxito, derivado automáticamente. Úsalos para banners de notificación, cajas de alerta y estados de error en campos de formulario.
Generando Escalas de Sombra Completas Dinámicamente
Aunque el Generador de Sombras es la herramienta adecuada para crear una escala completa 50–950 con pasos perceptuales precisos, color-mix() puede generar una aproximación utilizable en línea para componentes que necesitan un puñado de variantes:
:root {
--primary: oklch(0.58 0.20 250);
--primary-50: color-mix(in oklch, var(--primary) 8%, white);
--primary-100: color-mix(in oklch, var(--primary) 15%, white);
--primary-200: color-mix(in oklch, var(--primary) 30%, white);
--primary-300: color-mix(in oklch, var(--primary) 50%, white);
--primary-400: color-mix(in oklch, var(--primary) 70%, white);
--primary-500: var(--primary);
--primary-600: color-mix(in oklch, var(--primary) 85%, black);
--primary-700: color-mix(in oklch, var(--primary) 70%, black);
--primary-800: color-mix(in oklch, var(--primary) 55%, black);
--primary-900: color-mix(in oklch, var(--primary) 35%, black);
--primary-950: color-mix(in oklch, var(--primary) 20%, black);
}
Derivación de Color en Modo Oscuro
color-mix() es particularmente valioso para derivar sistemáticamente los colores de superficie en modo oscuro:
@media (prefers-color-scheme: dark) {
:root {
--surface-base: #09090b;
--surface-elevated: color-mix(in oklch, var(--brand) 8%, #09090b);
--surface-overlay: color-mix(in oklch, var(--brand) 12%, #09090b);
}
}
Mezclar una pequeña cantidad del color de marca en superficies oscuras crea un tinte sutil — una técnica usada por macOS de Apple y muchos sistemas de diseño modernos para hacer que el modo oscuro se sienta menos estéril que las superficies neutras puras.
Comportamiento del Canal Alfa
Cuando los porcentajes no suman 100%, el resultado es parcialmente transparente. Esto se puede usar deliberadamente para crear variantes translúcidas:
/* 30% azul sobre base transparente — equivalente a rgba al 30% de opacidad */
color-mix(in srgb, blue 30%, transparent)
/* También válido: transparencia nombrada desde el otro lado */
color-mix(in oklch, #3B82F6 25%, transparent)
Esto reemplaza el patrón de usar rgba() con un alfa fijo. La ventaja es que la relación de opacidad es explícita en el porcentaje de mezcla, y puedes mezclar con cualquier color — no solo con transparencia pura.
Soporte de Navegadores y Fallbacks
A partir de 2026, color-mix() está completamente soportado en:
- Chrome/Edge: desde la versión 111 (marzo de 2023)
- Firefox: desde la versión 113 (mayo de 2023)
- Safari: desde la versión 16.2 (diciembre de 2022)
El soporte global supera el 90%. Los usuarios que no pueden ver los resultados de color-mix() son aquellos con navegadores móviles muy antiguos o entornos empresariales con versiones de navegador bloqueadas.
Fallback de Mejora Progresiva
Las declaraciones de propiedades personalizadas CSS se aplican en cascada. Si el navegador no soporta color-mix(), se usa el fallback de la línea anterior:
:root {
/* Fallback para navegadores sin color-mix() */
--btn-hover: #1D4ED8;
/* Sobrescribir con valor calculado para navegadores modernos */
--btn-hover: color-mix(in oklch, var(--btn-bg) 85%, black);
}
Dado que las propiedades personalizadas re-declaran la misma variable, esto funciona como un patrón de mejora progresiva. Los navegadores que no soportan color-mix() usarán el color de fallback explícito; los navegadores modernos usarán el valor derivado.
Alternativamente, usa @supports:
.btn:hover {
background-color: #1D4ED8; /* Fallback */
}
@supports (color: color-mix(in oklch, red, blue)) {
.btn:hover {
background-color: color-mix(in oklch, var(--btn-bg) 85%, black);
}
}
El enfoque @supports es más explícito y más fácil de limpiar cuando eventualmente abandones el soporte de navegadores antiguos.
Conclusiones Clave
color-mix()mezcla dos colores nativamente en CSS, eliminando la necesidad de JavaScript o tablas de sombras pre-generadas para muchos casos de uso.- El argumento
in <color-space>controla dónde ocurre la mezcla y afecta dramáticamente el resultado. Usaoklchpara la mayoría del trabajo — produce puntos medios perceptualmente naturales sin desaturación lodosa (problema de sRGB) ni desplazamientos inesperados de tono (problema de HSL). - Los casos de uso más prácticos son: estados interactivos (hover, active, disabled), derivación de color semántico, tinte de superficies en modo oscuro y generación de pequeñas escalas de sombra a partir de una sola variable base.
- Cuando los porcentajes suman menos del 100%, la salida es parcialmente transparente — útil para crear variantes de opacidad sin
rgba(). - El soporte de navegadores cubre todos los navegadores modernos desde principios de 2023. Proporciona un valor de fallback codificado en duro en la declaración CSS anterior o dentro de un bloque
@supportspara entornos más antiguos. - Usa el Conversor de Color para convertir tus colores de marca existentes a OKLCH antes de usarlos en
color-mix(), y el Generador de Paletas para ver relaciones de color armoniosas antes de escribir CSS.