Saltar al contenido
AldeaCode Logo
Convertidor de Color / Hex a RGB Desarrollador 100% local

Convertir Hex a RGB: la matemática, las trampas y el snippet

Hex y RGB son dos notaciones para el mismo trío de bytes. Convertir entre ambas es un cambio de base y una regex, pero todo equipo acaba metiendo un bug en algún punto del camino. Aquí va la matemática, las esquinas que muerden, y un snippet que sobrevive a las esquinas.

La matemática debajo del hex

Un color hex tipo #ff8800 son tres pares de dígitos hexadecimales. Cada par es un byte, y cada byte es un entero de 0 a 255. ff es 255, 88 es 136, 00 es 0. Lees los pares de izquierda a derecha y sale rojo, verde, azul.

Esa es la conversión completa. #ff8800 se convierte en rgb(255, 136, 0). No hay redondeo, ni curva gamma, ni sorpresa de espacio de color. Las dos notaciones son equivalentes byte a byte.

La forma corta #fff es la misma lógica con un dígito por canal, duplicado para llenar el byte. #fff es #ffffff, #abc es #aabbcc. La forma corta es cómoda para números redondos e inútil para cualquier color afinado. Un diseñador que te manda #a3c o quiere decir #aa33cc exacto o no ha terminado de afinar el color. Pregunta antes de asumir.

El alpha es el cuarto par

Los navegadores modernos aceptan hex de ocho dígitos con el alpha como cuarto par. #ff880080 es el mismo naranja al 50 por ciento de opacidad (80 es 128, la mitad de 256). El CSS equivalente es rgba(255, 136, 0, 0.5) o rgb(255 136 0 / 0.5) en la nueva sintaxis con espacios.

El par alpha confunde porque es un byte de 0 a 255 en hex pero un float de 0 a 1 en la llamada rgba(). 80 no es 0.8, es 0.502. Si escribes rgba(255, 136, 0, 0.8) esperando que coincida con #ff8800cc te quedas un tres por ciento desviado y no lo verás nunca a ojo.

La forma corta de cuatro dígitos también existe. #f80c expande a #ff8800cc. Mismo atajo que la versión de tres dígitos, mismo aviso sobre precisión.

Hacerlo en código

El patrón en JavaScript es quitar la almohadilla inicial, expandir la forma corta de tres o cuatro dígitos, y parsear de dos en dos con parseInt(par, 16). La regex /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i captura los tres pares en un único match. Cualquier otra cosa (espacios extra, almohadilla ausente con regex que la requiere, string de ocho dígitos pasado a regex de seis) devuelve null y el resto de la función te da NaN. Esa es la cadena de bugs.

Dos modos de fallo aparecen en producción. El primero es olvidar que la almohadilla es opcional, así ff8800 y #ff8800 van por caminos distintos. El segundo es pasar #abc a una regex que exige seis dígitos y producir undefined en silencio. Usa un parser permisivo que acepte ambos largos, con y sin almohadilla, y mayúsculas o minúsculas. La librería estándar no cubre esto en el navegador, así que el snippet de abajo es la versión canónica.

Cuándo el conversor visual gana al snippet

Para un caso puntual (un diseñador pega #3a86ff en Slack y necesitas el rgba para un box-shadow CSS) abrir consola y teclear parseInt('3a', 16) tres veces son seis pasos de más. Pégalo en un conversor que corre en tu navegador, copia el resultado, sigues. Mete el snippet cuando la conversión vive dentro de un build o un generador de temas.

Ejemplo completo

javascript
// Hex a RGB. Acepta 3, 4, 6 u 8 dígitos.
// Devuelve { r, g, b, a } con a entre 0 y 1, o null si la entrada es mala.
function hexToRgb(hex) {
  if (typeof hex !== "string") return null;
  let h = hex.trim().replace(/^#/, "").toLowerCase();

  // Expandir forma corta de 3 o 4 dígitos a 6 u 8.
  if (h.length === 3 || h.length === 4) {
    h = h.split("").map((c) => c + c).join("");
  }

  if (!/^[0-9a-f]{6}([0-9a-f]{2})?$/.test(h)) return null;

  const r = parseInt(h.slice(0, 2), 16);
  const g = parseInt(h.slice(2, 4), 16);
  const b = parseInt(h.slice(4, 6), 16);
  const a = h.length === 8 ? parseInt(h.slice(6, 8), 16) / 255 : 1;

  return { r, g, b, a: Math.round(a * 1000) / 1000 };
}

// hexToRgb("#ff8800")    -> { r: 255, g: 136, b: 0, a: 1 }
// hexToRgb("#ff880080")  -> { r: 255, g: 136, b: 0, a: 0.502 }
// hexToRgb("#abc")       -> { r: 170, g: 187, b: 204, a: 1 }
// hexToRgb("no es hex")  -> null

¿Solo necesitas el resultado?

Pega el hex en el convertidor de color en aldeacode.com y el RGB, el rgba con alpha, el HSL y el OKLCH equivalentes salen en un click. Sin consola, sin snippet, la matemática sale bien al primer intento y la página nunca manda un byte a ningún servidor.

Abrir Convertidor de Color (Hex / RGB / HSL) →

Preguntas frecuentes

¿#FFF es lo mismo que #FFFFFF?

Sí. La forma corta de tres dígitos duplica cada carácter, así #fff expande a #ffffff y #abc a #aabbcc. Las dos renderizan igual. La forma corta solo funciona cuando cada par es un dígito duplicado, si no, hay que usar los seis completos.

¿Cómo se convierte el alpha hex de ocho dígitos al float de rgba?

Divide el byte alpha entre 255, no entre 256. Así #ff880080 se vuelve rgba(255, 136, 0, 0.502). Bug clásico: la gente pone 0.5 pensando que 80 es la mitad exacta, no lo es.

¿Almohadilla o sin almohadilla?

Siempre con almohadilla en CSS y atributos HTML. En código que acepta strings hex, acepta ambas formas. La almohadilla es opcional en la mayoría de parsers pero obligatoria en CSS, normalizar en la entrada te evita una clase entera de bugs.