Hex vs RGB vs HSL: Qué representa cada formato
El debate hex vs rgb vs hsl no se trata de cuál es "mejor" — son tres formas de escribir el mismo color. #FF6B35 y rgb(255, 107, 53) y hsl(16, 100%, 60%) son idénticos. La diferencia está en cómo descomponen el color en componentes, lo que afecta qué tan fácil es leer, modificar y generar colores programáticamente.
Hex (#RRGGBB) empaqueta rojo, verde y azul en 6 dígitos hexadecimales. Cada par va de 00 (nada) a FF (máximo). Es compacto y universal — cada navegador, herramienta de diseño y API entiende hex. La desventaja: no es legible para humanos. ¿Puedes decir que #2E86AB es un azul medio solo con mirarlo? La mayoría no puede. Hex es para almacenamiento y comunicación, no para pensar sobre color.
RGB (rojo, verde, azul) es lo mismo que hex pero en decimal (0-255 por canal). rgb(46, 134, 171) es ligeramente más legible que #2E86AB — puedes ver que el azul (171) domina, el verde (134) es moderado y el rojo (46) es bajo. Pero sigue siendo difícil responder preguntas como "hazlo 20% más claro" o "muévelo hacia naranja" porque la luminosidad y el tono no son explícitos en RGB.
HSL (tono, saturación, luminosidad) separa el color en tres dimensiones intuitivas. El tono es la posición en la rueda de color (0°=rojo, 120°=verde, 240°=azul). La saturación es la intensidad (0%=gris, 100%=vívido). La luminosidad es el brillo (0%=negro, 50%=color puro, 100%=blanco). ¿Quieres una versión más clara? Aumenta L. ¿Una versión apagada? Reduce S. ¿Un color complementario? Suma 180° a H. Por eso HSL gana para manipulación programática de colores.
Cuándo usar cada formato (reglas prácticas)
Usa hex para: variables CSS, tokens de diseño, definiciones de colores de marca, respuestas de API, almacenamiento en base de datos. Es la representación de texto más compacta (6-8 caracteres) y tiene soporte universal. Cuando un diseñador te pasa una especificación de color, será en hex. Cuando almacenes colores en un archivo de configuración, usa hex.
Usa RGB para: operaciones de canvas, WebGL, procesamiento de imágenes y cualquier contexto donde manipules canales de color individuales. La API de Canvas trabaja en RGB. Mezclar dos colores es directo en RGB (promedia cada canal). Las fórmulas de composición alfa usan valores RGB. Si estás haciendo trabajo a nivel de píxel, piensa en RGB.
Usa HSL para: generar paletas de colores, crear estados hover/active, construir temas y cualquier UI donde los usuarios elijan colores. "10% más oscuro" es trivial en HSL (resta 10 de L). "Mismo color pero apagado" es trivial (reduce S). Generar 5 colores equidistantes es trivial (divide 360° entre 5 y usa esos tonos). Nuestra herramienta color-picker muestra los tres formatos simultáneamente para que veas las relaciones.
Usa OKLCH para: manipulación de color perceptualmente uniforme (nuevo en CSS Color Level 4). HSL tiene un defecto — hsl(60, 100%, 50%) (amarillo) se ve mucho más brillante que hsl(240, 100%, 50%) (azul) aunque tienen el mismo valor de L. OKLCH corrige esto con luminosidad perceptualmente uniforme. Si estás construyendo un sistema de diseño en 2026 y necesitas brillo percibido consistente entre tonos, OKLCH es la elección correcta. La sintaxis es oklch(lightness chroma hue) donde lightness es 0-1, chroma es 0-0.4 (aproximadamente) y hue es 0-360°.
/* Same color in different formats */
.button {
/* All identical: a warm orange */
color: #FF6B35;
color: rgb(255, 107, 53);
color: hsl(16, 100%, 60%);
color: oklch(0.7 0.18 45);
}
/* HSL makes variations trivial */
.button:hover {
/* 10% darker: just reduce lightness */
background: hsl(16, 100%, 50%);
}
.button:active {
/* 20% darker */
background: hsl(16, 100%, 40%);
}
.button--muted {
/* Same hue, less saturated */
background: hsl(16, 40%, 60%);
}
/* Generating a palette with HSL */
:root {
--primary: hsl(220, 70%, 50%);
--primary-light: hsl(220, 70%, 70%);
--primary-dark: hsl(220, 70%, 30%);
--complement: hsl(40, 70%, 50%); /* +180° hue */
}Manipulación de color en código
Oscurecer/aclarar: En HSL, resta/suma al valor L. hsl(200, 80%, 50%) oscurecido un 20% se convierte en hsl(200, 80%, 30%). En hex/RGB, necesitarías convertir a HSL primero, modificar y luego convertir de vuelta. Por eso cada librería CSS-in-JS (styled-components, emotion) provee helpers darken() y lighten() que trabajan en HSL internamente.
Opacidad/transparencia: Agrega un canal alfa. Hex usa 8 dígitos (#FF6B3580 = 50% opacidad). RGB se convierte en rgba(255, 107, 53, 0.5). HSL se convierte en hsla(16, 100%, 60%, 0.5). El valor alfa va de 0 (totalmente transparente) a 1 (totalmente opaco). Nota: hex de 8 dígitos no es soportado en IE11 (si todavía te importa), pero rgba() funciona en todos lados.
Mezcla de colores: El enfoque más simple es interpolación lineal en RGB. Mezclar 50% rojo y 50% azul: r=(255+0)/2=128, g=(0+0)/2=0, b=(0+255)/2=128 → rgb(128, 0, 128) = púrpura. CSS ahora tiene color-mix(): color-mix(in srgb, red 50%, blue) hace esto nativamente. Para una mezcla perceptualmente mejor, interpola en espacio OKLCH — la mezcla RGB puede producir colores intermedios turbios.
Generar pares de colores accesibles: Calcula la relación de contraste WCAG entre primer plano y fondo. La fórmula usa luminancia relativa: L = 0.2126×R + 0.7152×G + 0.0722×B (donde R, G, B están linearizados desde sRGB). Relación de contraste = (L1 + 0.05) / (L2 + 0.05) donde L1 > L2. WCAG AA requiere 4.5:1 para texto normal, 3:1 para texto grande. Nuestra herramienta color-picker calcula esto automáticamente.
Funciones de color CSS (enfoques modernos)
Colores relativos CSS (2024+): color: hsl(from var(--brand) h s calc(l - 20%)) crea una versión más oscura de tu color de marca sin JavaScript. La palabra clave "from" desestructura el color fuente en sus componentes, que luego puedes modificar con calc(). Esto elimina la necesidad de funciones de color de preprocesadores en muchos casos.
color-mix() (soportado desde 2023): color-mix(in oklch, var(--primary) 70%, white) mezcla 70% de tu color primario con 30% blanco, produciendo un tinte. La parte "in oklch" especifica el espacio de color para la interpolación — oklch produce mezclas más naturales que srgb para la mayoría de combinaciones de colores.
La función oklch(): oklch(0.7 0.15 250) especifica luminosidad (0-1), croma (0-0.4 aprox., qué tan colorido) y tono (0-360°). A diferencia de HSL, valores iguales de luminosidad en OKLCH realmente se ven igual de brillantes para los ojos humanos. Esto importa para visualización de datos — si necesitas 5 colores que sean igualmente prominentes, OKLCH con el mismo valor de L lo logra mientras que HSL no.
Tip práctico: define tus tokens de diseño en hex (para compatibilidad y entrega al diseñador), pero usa HSL u OKLCH en tu CSS para colores derivados (estados hover, estados disabled, anillos de focus). Esto te da lo mejor de ambos mundos: colores de referencia estables que los diseñadores reconocen, más variaciones programáticas fáciles sin JavaScript.
Accesibilidad y relaciones de contraste
Requisitos de contraste WCAG 2.1: 4.5:1 para texto normal (menor a 18px o menor a 14px bold), 3:1 para texto grande (18px+ o 14px+ bold), 3:1 para componentes de UI y objetos gráficos. Estos no son sugerencias — son requisitos legales en muchas jurisdicciones (ADA en EE.UU., EN 301 549 en la UE). Fallar en contraste significa que algunos usuarios literalmente no pueden leer tu contenido.
Fallas comunes: texto gris claro sobre blanco (#999 sobre #fff = 2.85:1, falla AA), texto placeholder demasiado tenue, texto de botón deshabilitado ilegible, enlaces de color que no contrastan con el texto circundante. La solución suele ser simple — oscurece el texto o aclara el fondo hasta alcanzar 4.5:1. Nuestra herramienta color-picker muestra la relación de contraste mientras ajustas colores.
Trampa del modo oscuro: invertir colores no preserva las relaciones de contraste. #333 sobre #fff (12.6:1) invertido a #ccc sobre #000 es solo 13.1:1 — bien. Pero #666 sobre #fff (5.7:1) invertido a #999 sobre #000 es solo 5.1:1 — todavía pasa pero apenas. Y algunas combinaciones de color que pasan en modo claro fallan en modo oscuro después de la inversión. Siempre verifica las relaciones de contraste por separado para cada modo.
Más allá de WCAG: aproximadamente el 8% de los hombres y el 0.5% de las mujeres tienen alguna forma de deficiencia en la visión del color. No dependas solo del color para transmitir información (rojo/verde para error/éxito es la falla clásica). Usa íconos, patrones o etiquetas de texto junto con el color. Prueba tu UI con un simulador de daltonismo — Chrome DevTools tiene uno integrado (panel Rendering → Emulate vision deficiencies).
Espacios de color más allá de sRGB
sRGB es el espacio de color por defecto para la web. Cubre aproximadamente el 35% de los colores visibles. Las pantallas modernas (P3, usado en iPhones desde 2016 y MacBooks desde 2015) pueden mostrar aproximadamente 25% más colores que sRGB. Si solo usas hex/rgb, estás limitado a sRGB. Para acceder a la gama más amplia, usa color(display-p3 1 0.5 0) en CSS.
Cuándo importa la gama amplia: fotografía vibrante, colores de marca que se ven "planos" en sRGB (especialmente rojos y verdes saturados), y cualquier diseño donde quieras que los colores "resalten" en pantallas capaces. Cuándo no importa: texto, chrome de UI, fondos y cualquier cosa donde las diferencias sutiles de color no son importantes.
Estrategia de fallback: usa @supports (color: color(display-p3 1 0 0)) para detectar soporte P3, y provee un fallback sRGB. O usa la función color() con fallback: color: #ff6b35; color: color(display-p3 1 0.45 0.2); — los navegadores que no entienden display-p3 ignoran la segunda declaración y usan el valor hex.
Para desarrolladores que no son diseñadores: probablemente no necesitas pensar en colores de gama amplia. sRGB cubre todos los colores del diseño de UI típico. La gama amplia es relevante para sitios de fotografía, imágenes de productos de e-commerce y páginas de marketing con mucha marca. Si tu diseñador no ha mencionado colores P3, quédate con hex/rgb/hsl en sRGB y enfócate en tener las relaciones de contraste correctas. El costo de rendimiento de la gama amplia es cero — es solo una declaración de espacio de color diferente en CSS, no una sobrecarga de renderizado.
Errores comunes de color en desarrollo web
Error 1: Hardcodear colores en vez de usar custom properties de CSS. Si tu azul de marca aparece en 47 lugares y el diseñador lo cambia, estás haciendo 47 operaciones de buscar-y-reemplazar. Define colores una vez como --color-primary: hsl(220, 70%, 50%) y referéncialos en todos lados. Esto también hace el modo oscuro trivial — solo redefine las custom properties bajo una clase .dark o media query.
Error 2: Usar opacidad para estados hover en vez de luminosidad HSL. Poner opacity: 0.8 en un botón de color hace que el fondo se transparente, creando un color impredecible. En su lugar, usa una versión ligeramente más oscura/clara del mismo color: background: hsl(220, 70%, 45%) para hover (5% más oscuro). Esto da resultados consistentes sin importar qué hay detrás del elemento.
Error 3: No probar colores en diferentes monitores. Un color que se ve vibrante en tu MacBook Pro (gama P3, alto brillo) puede verse deslavado en un monitor de oficina barato (sRGB, bajo contraste). Siempre prueba en al menos una pantalla no premium. Los colores que sobreviven esta prueba son los que tus usuarios realmente verán.
Error 4: Ignorar el color en modo oscuro. Simplemente invertir colores o intercambiar fondos blanco/negro produce interfaces duras y cansadas para la vista. Un buen modo oscuro usa colores ligeramente desaturados (reduce S un 10-20% en HSL), superficies elevadas con diferencias sutiles de gris (no negro puro), y contraste reducido para áreas de texto grandes (blanco puro sobre negro puro es demasiado duro — usa #e0e0e0 sobre #1a1a1a en su lugar).