Tutoriales

Sintaxis de Color Relativo CSS: Transforma Cualquier Color Dinámicamente

9 min de lectura

CSS ha podido almacenar colores durante mucho tiempo, pero manipularlos requería JavaScript, funciones de Sass o un paso de compilación. La sintaxis de color relativo CSS cambia esto. Te permite tomar un color existente — de una variable, una palabra clave o cualquier valor de color — y transformar canales específicos de él directamente en tu hoja de estilos. Puedes aclararlo, desplazar su tono, reducir su croma o ajustar su transparencia, todo en CSS puro, en tiempo de ejecución.

Esta característica llegó en Chrome 119, Firefox 128 y Safari 16.4, con una penetración de navegadores suficientemente alta para uso en producción en 2026. Funciona con todas las funciones de color CSS modernas: rgb(), hsl(), oklch(), lab(), lch() y más.

¿Qué Es la Sintaxis de Color Relativo?

La sintaxis de color relativo extiende cualquier función de color CSS con una cláusula from <color> al principio. Esto le dice al navegador que descomponga el color de origen en sus canales, luego recomponga un nuevo color usando esos canales — posiblemente con modificaciones.

El ejemplo más básico usa la palabra clave from para pasar un color sin cambios:

/* Esto es una no-operación — produce el mismo color que la entrada */
color: oklch(from #3B82F6 l c h);

No es muy útil por sí solo, pero el poder real llega cuando modificas los valores de canal extraídos:

/* Aclarar aumentando L (luminosidad) */
color: oklch(from #3B82F6 calc(l + 0.15) c h);

/* Desplazar el tono 30 grados */
color: oklch(from #3B82F6 l c calc(h + 30));

/* Desaturar reduciendo el croma */
color: oklch(from #3B82F6 l calc(c * 0.5) h);

/* Hacer semitransparente */
color: oklch(from #3B82F6 l c h / 0.5);

Cada una de estas transforma un solo canal mientras mantiene los demás intactos — algo que antes era imposible en CSS puro sin un preprocesador.

La Palabra Clave from

La palabra clave from es el corazón sintáctico de la sintaxis de color relativo. Aparece inmediatamente después del paréntesis de apertura de la función de color y antes de los valores de canal:

color-function(from <origin-color> <channel1> <channel2> <channel3> [/ <alpha>])

El <origin-color> puede ser cualquier valor de color CSS válido:

/* Desde un código hex */
oklch(from #FF5733 l c h)

/* Desde un color con nombre */
oklch(from tomato l c h)

/* Desde una propiedad personalizada CSS */
oklch(from var(--brand-color) l c h)

/* Desde otra función de color */
oklch(from rgb(59, 130, 246) l c h)

/* Desde currentColor */
oklch(from currentColor l c h)

La variante from currentColor es particularmente poderosa — permite que un componente transforme el color de texto heredado sin conocer su valor exacto.

Nombres de Canal por Función de Color

Cada función de color expone sus canales bajo nombres específicos después de la palabra clave from:

Función Canal 1 Canal 2 Canal 3 Alfa
oklch() l c h alpha
oklab() l a b alpha
hsl() h s l alpha
rgb() r g b alpha
lab() l a b alpha
lch() l c h alpha

Ten en cuenta que en hsl(), el orden de canal en la descomposición from refleja la firma de la función: h, s, l. En oklch(), es l, c, h. Siempre verifica el orden de canal para la función que estás usando.

Conversión Entre Funciones

El color de origen no necesita coincidir con la función de salida. El navegador convierte automáticamente:

/* La entrada es hex, la salida es oklch — el navegador convierte primero, luego descompone */
oklch(from #FF5733 calc(l + 0.1) c h)

/* La entrada es hsl, la salida es rgb */
rgb(from hsl(200, 80%, 50%) calc(r * 0.9) g b)

Esta conversión entre funciones significa que puedes almacenar tus tokens de diseño en cualquier formato y producir salidas en cualquier formato que prefieras para la manipulación.

Ajustando Canales Individuales

Las operaciones más comunes en colores relativos involucran calc() para modificar los valores de canal extraídos.

Ajustes de Luminosidad (OKLCH)

Con OKLCH, el canal l va de 0 (negro) a 1 (blanco). Añadir o restar un valor fijo produce un resultado predeciblemente más claro o más oscuro, porque la luminosidad OKLCH es perceptualmente uniforme:

:root {
  --base: oklch(0.58 0.20 250);
}

.lighter  { color: oklch(from var(--base) calc(l + 0.15) c h); }
.lightest { color: oklch(from var(--base) calc(l + 0.30) c h); }
.darker   { color: oklch(from var(--base) calc(l - 0.15) c h); }
.darkest  { color: oklch(from var(--base) calc(l - 0.30) c h); }

Debido a que la luminosidad OKLCH está calibrada perceptualmente, añadir 0.15 a l produce un salto de brillo percibido de igual tamaño independientemente del tono del color — a diferencia de HSL, donde el mismo incremento se ve diferente dependiendo de si el color es amarillo o azul.

Ajustes de Croma

El canal c controla la intensidad del color. Establecerlo en 0 produce un gris neutro con la misma luminosidad. Reducirlo desatura sin apagarse completamente:

/* Variante atenuada — 50% menos de croma */
color: oklch(from var(--brand) l calc(c * 0.5) h);

/* Gris completamente desaturado con la misma luminosidad */
color: oklch(from var(--brand) l 0 h);

/* Más vívido — 30% más de croma (puede salirse de la gama sRGB en algunos tonos) */
color: oklch(from var(--brand) l calc(c * 1.3) h);

Desplazamientos de Tono

El canal h es un valor de grado de 0 a 360. Añadir o restar desplaza el tono alrededor de la rueda de color:

/* Color complementario — lado opuesto de la rueda */
color: oklch(from var(--brand) l c calc(h + 180));

/* Análogo +30° */
color: oklch(from var(--brand) l c calc(h + 30));

/* Análogo -30° */
color: oklch(from var(--brand) l c calc(h - 30));

Combinar múltiples ajustes de canal crea transformaciones complejas en una sola declaración:

/* Más claro, más atenuado y ligeramente diferente tono — una variante tonal */
color: oklch(from var(--brand) calc(l + 0.12) calc(c * 0.6) calc(h + 15));

Canal Alfa

Usa la sintaxis de barra para modificar la transparencia:

/* Versión al 50% de opacidad del color de marca */
background: oklch(from var(--brand) l c h / 0.5);

/* Versión completamente opaca de un color que puede tener transparencia */
color: oklch(from var(--text-muted) l c h / 1);

/* Escalar el alfa existente — si el origen tiene 0.8 de opacidad, reducir a ~0.4 */
background: oklch(from var(--overlay) l c h / calc(alpha * 0.5));

Creando Tintes y Sombras en CSS Puro

El enfoque tradicional para las escalas de color requiere pre-calcular cada sombra y almacenarla como una variable. Con la sintaxis de color relativo, puedes generar una escala completa a partir de una sola variable base:

:root {
  --primary: oklch(0.58 0.20 250);

  /* Escala — no se necesita pre-cálculo */
  --primary-50:  oklch(from var(--primary) 0.97 calc(c * 0.1) h);
  --primary-100: oklch(from var(--primary) 0.94 calc(c * 0.2) h);
  --primary-200: oklch(from var(--primary) 0.88 calc(c * 0.4) h);
  --primary-300: oklch(from var(--primary) 0.78 calc(c * 0.6) h);
  --primary-400: oklch(from var(--primary) 0.68 calc(c * 0.8) h);
  --primary-500: var(--primary);
  --primary-600: oklch(from var(--primary) calc(l - 0.08) c h);
  --primary-700: oklch(from var(--primary) calc(l - 0.16) c h);
  --primary-800: oklch(from var(--primary) calc(l - 0.24) c h);
  --primary-900: oklch(from var(--primary) calc(l - 0.32) c h);
  --primary-950: oklch(from var(--primary) calc(l - 0.38) c h);
}

Cambia --primary a cualquier color y toda la escala de 11 pasos se regenera automáticamente en el navegador. Sin paso de compilación, sin JavaScript, sin Sass.

Para sistemas de diseño en producción que requieren pasos perceptuales muy precisos, el Generador de Sombras proporciona escalas 50–950 ajustadas a mano. El enfoque de color relativo es ideal para componentes de menor escala o para prototipado rápido donde la precisión exacta importa menos que la flexibilidad.

Tintes Accesibles para Fondos

Un patrón común es crear fondos con tinte muy claros para banners de notificación y cajas de alerta:

:root {
  --success: oklch(0.65 0.20 145);  /* Un verde vívido */
  --warning: oklch(0.75 0.18 70);   /* Un ámbar cálido */
  --danger:  oklch(0.62 0.24 25);   /* Un rojo fuerte */
}

.alert-success {
  background: oklch(from var(--success) 0.96 0.04 h);
  border-left: 3px solid var(--success);
  color: oklch(from var(--success) 0.30 0.14 h);
}

.alert-warning {
  background: oklch(from var(--warning) 0.97 0.04 h);
  border-left: 3px solid var(--warning);
  color: oklch(from var(--warning) 0.35 0.14 h);
}

.alert-danger {
  background: oklch(from var(--danger) 0.96 0.04 h);
  border-left: 3px solid var(--danger);
  color: oklch(from var(--danger) 0.32 0.14 h);
}

El fondo es una versión de muy alta luminosidad y bajo croma del color de alerta. El texto usa una versión muy oscura y moderadamente saturada. El tono (h) se preserva del color de origen en todos los casos — todo permanece en el mismo tono automáticamente.

Ejemplos del Mundo Real con OKLCH

Estados de Hover Adaptativos al Tema

.card {
  --card-accent: oklch(0.60 0.18 260);
  background: var(--card-accent);
  transition: background-color 150ms ease;
}

.card:hover {
  /* Oscurecer ligeramente al pasar el cursor — funciona independientemente de cuál sea el acento */
  background: oklch(from var(--card-accent) calc(l - 0.06) c h);
}

Este patrón es particularmente poderoso en bibliotecas de componentes donde el color de acento se pasa como una prop o propiedad personalizada. El estado de hover siempre es contextualmente apropiado sin requerir colores de hover separados para cada variante.

Texto sobre Fondos de Color

.chip {
  --chip-color: oklch(0.62 0.20 260);

  /* Fondo: tinte muy claro */
  background: oklch(from var(--chip-color) 0.94 0.06 h);

  /* Texto: versión muy oscura del mismo tono */
  color: oklch(from var(--chip-color) 0.28 0.16 h);

  /* Borde: versión medio-claro */
  border: 1px solid oklch(from var(--chip-color) 0.78 0.12 h);
}

Esto produce una etiqueta de color donde el fondo, el texto y el borde son todos armoniosos porque comparten el mismo tono. Cambia --chip-color y todo el conjunto se actualiza.

Adaptación al Modo Oscuro Usando from currentColor

.icon-wrapper {
  /* El color del ícono hereda del contexto de texto */
  color: var(--color-text-primary);
}

.icon-wrapper:hover {
  /* Versión ligeramente más oscura de cualquier color que sea el ícono actualmente */
  color: oklch(from currentColor calc(l - 0.08) c h);
}

.icon-wrapper .background-glow {
  /* Versión semitransparente del color del ícono, para un efecto de brillo */
  background: oklch(from currentColor l c h / 0.15);
}

El origen currentColor significa que este componente funciona correctamente en cualquier contexto de color de texto, incluyendo el modo oscuro, sin necesitar conocer el valor de color específico.

Generando un Acento Complementario

Para diseños que necesitan un color de acento complementario derivado del color de marca principal:

:root {
  --brand: oklch(0.60 0.20 250);   /* Azul */

  /* Complemento: tono opuesto, misma luminosidad y croma */
  --accent: oklch(from var(--brand) l c calc(h + 180));
  /* Resultado: aproximadamente naranja en tono ~70° */

  /* Complemento más suave para fondos */
  --accent-bg: oklch(from var(--brand) 0.95 0.06 calc(h + 180));
}

Esto produce un color matemáticamente complementario. Para un esquema de complemento dividido más sofisticado, desplaza ±150° o ±160° en lugar de 180°.

Soporte de Navegadores y Fallbacks

La sintaxis de color relativo está soportada en:

  • Chrome/Edge: desde la versión 119 (noviembre de 2023)
  • Firefox: desde la versión 128 (julio de 2024)
  • Safari: desde la versión 16.4 (marzo de 2023) — Safari fue el primero

El soporte global es alrededor del 85–88% a principios de 2026. Para mayor cobertura, proporciona fallbacks:

.btn-hover {
  /* Fallback: hex pre-calculado para navegadores más antiguos */
  background-color: #1D4ED8;
}

@supports (color: oklch(from red l c h)) {
  .btn-hover {
    /* Moderno: derivado dinámicamente de la base */
    background-color: oklch(from var(--btn-bg) calc(l - 0.08) c h);
  }
}

La prueba @supports (color: oklch(from red l c h)) verifica específicamente el soporte de la sintaxis de color relativo, no solo el soporte de OKLCH, lo cual es importante ya que OKLCH y la sintaxis de color relativo se enviaron en diferentes versiones de navegador.

Conclusiones Clave

  • La sintaxis de color relativo usa from <origin-color> dentro de cualquier función de color CSS para descomponer ese color en sus canales, que luego pueden modificarse con calc() y recomponerse en un nuevo color.
  • OKLCH es la mejor función para usar en la manipulación de color relativo porque sus canales (luminosidad, croma, tono) se mapean estrechamente a la intención de diseño, y la luminosidad es perceptualmente uniforme — incrementos iguales producen cambios de apariencia iguales.
  • Puedes ajustar cualquier canal individual de forma independiente: añadir a l para aclarar, multiplicar c para desaturar, añadir a h para desplazar el tono, o modificar alpha para cambiar la transparencia.
  • El origen from currentColor crea componentes auto-adaptativos que derivan sus colores del color de texto heredado, haciéndolos automáticamente correctos en cualquier contexto, incluyendo el modo oscuro.
  • El soporte de navegadores cubre todos los navegadores modernos desde finales de 2023 / mediados de 2024. Usa @supports (color: oklch(from red l c h)) para detectar el soporte específicamente para la sintaxis de color relativo.
  • Usa el Generador de Sombras para escalas 50–950 precisas y ajustadas a mano en sistemas de diseño de producción. Usa la sintaxis de color relativo para variantes dinámicas derivadas en tiempo de ejecución en componentes.
  • Usa el Conversor de Color para traducir tus colores de marca hex existentes a valores OKLCH para entender sus canales l, c y h antes de escribir expresiones de color relativo.

Colores relacionados

Marcas relacionadas

Herramientas relacionadas