How to Convert HEX to RGB to HSL (And When to Use Each)

· Lion Dada

How to Convert HEX to RGB to HSL (And When to Use Each)

The Day I Shipped the Wrong Purple

True story: I once spent three hours debugging why my button looked wrong in production. The design spec said "Coloracci Purple: #7241FF" but my button was displaying a sad, washed-out lavender.

The culprit? I'd accidentally typed rgb(114, 65, 250) instead of rgb(114, 65, 255)—a single digit off on the blue channel. Five units. That's all it took to make our brand color look like it had given up on life.

That's when I realized: understanding color formats isn't just academic—it's the difference between "pixel perfect" and "please fire me."

This guide will give you everything I wish I knew that day. We'll cover the three major web color formats, when to use each one, the actual math behind conversions, and the mistakes that make designers cry.

Color formats family diagram

The Color Format Family Tree

Before we dive into conversions, let's understand what we're working with. Think of color formats as different languages describing the same thing—a specific color.

The Three Main Players

  1. HEX (Hexadecimal) - The web's original color language
  2. RGB (Red, Green, Blue) - The additive color model
  3. HSL (Hue, Saturation, Lightness) - The human-friendly format

Each has its strengths, weaknesses, and ideal use cases. Understanding all three makes you a more effective designer and developer.

For a deep dive into CSS variables that use these formats, check out our CSS Color Variables guide.

Understanding HEX: The Web's Color Shorthand

HEX is probably the format you encounter most often. That #FF5733 in your CSS? That's HEX.

What Those Characters Mean

A HEX color is just RGB values in disguise, written in base-16 (hexadecimal) notation:

#RRGGBB
  │ │ └── Blue (00-FF)
  │ └──── Green (00-FF)
  └────── Red (00-FF)

Each pair represents a value from 0-255, but using hexadecimal digits (0-9 and A-F):

So #FF0000 means: Red=255, Green=0, Blue=0 → Pure red.

HEX Shorthand

When each pair has identical characters, you can use shorthand:

This only works when each channel's digits are the same. #F5A321 has no shorthand form.

When to Use HEX

Best for:

Not ideal for:

For help selecting the right colors, try our AI Color Picker which shows colors in all formats.

Understanding RGB: The Light Model

RGB represents colors as combinations of red, green, and blue light—the same way your screen actually creates colors.

The RGB Model

rgb(red, green, blue)
    │     │      └── Blue intensity (0-255)
    │     └──────── Green intensity (0-255)
    └────────────── Red intensity (0-255)

Each value ranges from 0 (none) to 255 (full intensity):

RGBA: Adding Transparency

RGB's superpower is the alpha channel:

rgba(114, 65, 255, 0.5)
                   └── Alpha (0-1, where 1 is fully opaque)

This is essential for overlays, shadows, and layered designs. You can't do this with HEX (well, you can with 8-digit HEX, but browser support was historically spotty).

When to Use RGB

Best for:

Not ideal for:

Learn more about using RGB in dark mode design and accessibility guidelines.

HSL cylinder visualization

Understanding HSL: The Designer's Dream

HSL changed my life. Not exaggerating. Once you understand it, you'll wonder why we ever used anything else.

The HSL Model

hsl(hue, saturation%, lightness%)
    │        │           └── How light/dark (0-100%)
    │        └────────────── How vivid (0-100%)
    └─────────────────────── Position on color wheel (0-360°)

Hue (0-360°): Think of a color wheel. 0° is red, 120° is green, 240° is blue, and back to red at 360°.

Saturation (0-100%): How vivid the color is. 100% is pure color, 0% is gray.

Lightness (0-100%): 0% is black, 50% is the "true" color, 100% is white.

Why Designers Love HSL

Here's where HSL shines: creating color variations is intuitive.

Want a darker version of your brand color? Just reduce lightness:

/* Original */
hsl(262, 100%, 63%)

/* Darker hover state */
hsl(262, 100%, 53%)  /* Just -10% lightness */

Want a muted version? Reduce saturation:

/* Original */
hsl(262, 100%, 63%)

/* Muted for backgrounds */
hsl(262, 30%, 63%)  /* Same hue, less saturated */

Try this impossible with RGB or HEX without a calculator.

HSLA: Transparency in HSL

Same pattern as RGBA:

hsla(262, 100%, 63%, 0.5)  /* 50% transparent */

When to Use HSL

Best for:

Not ideal for:

For building complete color systems, explore our Color Hierarchy tool and Light/Dark Mode Generator.

The Math Behind Conversions

Let's get into the actual formulas. Understanding these helps you debug color issues and write conversion functions.

HEX to RGB

This is the simplest conversion—just parsing hexadecimal:

function hexToRgb(hex) {
  // Remove # if present
  hex = hex.replace('#', '');
  
  // Handle shorthand (#F00 → #FF0000)
  if (hex.length === 3) {
    hex = hex.split('').map(c => c + c).join('');
  }
  
  // Parse each channel
  const r = parseInt(hex.substring(0, 2), 16);
  const g = parseInt(hex.substring(2, 4), 16);
  const b = parseInt(hex.substring(4, 6), 16);
  
  return { r, g, b };
}

// Example: hexToRgb("#7241FF")
// Result: { r: 114, g: 65, b: 255 }

RGB to HEX

The reverse—convert decimal to hexadecimal:

function rgbToHex(r, g, b) {
  return '#' + [r, g, b]
    .map(c => c.toString(16).padStart(2, '0'))
    .join('')
    .toUpperCase();
}

// Example: rgbToHex(114, 65, 255)
// Result: "#7241FF"

Color conversion flowchart

RGB to HSL

This is where it gets interesting. The algorithm:

function rgbToHsl(r, g, b) {
  // Normalize to 0-1 range
  r /= 255;
  g /= 255;
  b /= 255;
  
  const max = Math.max(r, g, b);
  const min = Math.min(r, g, b);
  const diff = max - min;
  
  // Lightness
  const l = (max + min) / 2;
  
  // Saturation
  let s = 0;
  if (diff !== 0) {
    s = l > 0.5 
      ? diff / (2 - max - min) 
      : diff / (max + min);
  }
  
  // Hue
  let h = 0;
  if (diff !== 0) {
    switch (max) {
      case r:
        h = ((g - b) / diff + (g < b ? 6 : 0)) / 6;
        break;
      case g:
        h = ((b - r) / diff + 2) / 6;
        break;
      case b:
        h = ((r - g) / diff + 4) / 6;
        break;
    }
  }
  
  return {
    h: Math.round(h * 360),
    s: Math.round(s * 100),
    l: Math.round(l * 100)
  };
}

// Example: rgbToHsl(114, 65, 255)
// Result: { h: 255, s: 100, l: 63 }

HSL to RGB

And the reverse for completeness:

function hslToRgb(h, s, l) {
  h /= 360;
  s /= 100;
  l /= 100;
  
  let r, g, b;
  
  if (s === 0) {
    r = g = b = l; // Achromatic (gray)
  } else {
    const hue2rgb = (p, q, t) => {
      if (t < 0) t += 1;
      if (t > 1) t -= 1;
      if (t < 1/6) return p + (q - p) * 6 * t;
      if (t < 1/2) return q;
      if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
      return p;
    };
    
    const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
    const p = 2 * l - q;
    
    r = hue2rgb(p, q, h + 1/3);
    g = hue2rgb(p, q, h);
    b = hue2rgb(p, q, h - 1/3);
  }
  
  return {
    r: Math.round(r * 255),
    g: Math.round(g * 255),
    b: Math.round(b * 255)
  };
}

When to Use Which Format: A Decision Tree

Here's my mental model for choosing formats:

Use HEX When:

  • Defining colors in CSS stylesheets
  • Copying colors from/to design tools
  • Documentation and style guides
  • Brand guidelines

Use RGB/RGBA When:

  • You need transparency
  • Manipulating colors in JavaScript
  • Calculating interpolated colors
  • Working with color blending

Use HSL/HSLA When:

  • Creating hover/active states
  • Building color palettes programmatically
  • Working with CSS custom properties
  • Making intuitive color adjustments

For a practical application of these decisions, see how we approach color proportions in branding.

Common color format mistakes

Common Mistakes (And How to Avoid Them)

After years of working with colors, I've seen (and made) every mistake possible.

Mistake 1: RGB Colors for Print

RGB is for screens. CMYK is for print. Never use RGB values in print materials—the colors will shift, often dramatically.

The Fix: Always convert to CMYK for print. Better yet, use Pantone spot colors for brand consistency.

Mistake 2: Forgetting Alpha Notation

rgba(255, 0, 0, 1) is red. rgba(255, 0, 0) is... also red, but some older parsers might choke on it.

The Fix: Always include the alpha value, even if it's 1:

/* Explicit is better */
rgba(255, 0, 0, 1)
hsla(0, 100%, 50%, 1)

Mistake 3: HSL Rounding Errors

Converting from RGB to HSL and back can introduce tiny variations due to rounding.

The Fix: Keep your "source of truth" in one format. If you're doing programmatic manipulation, work in HSL, then convert only when outputting final values.

Mistake 4: Shorthand HEX Confusion

#F00 and #FF0000 are the same. But #FA0 expands to #FFAA00, not #FA0000.

The Fix: When in doubt, use the full 6-digit HEX. It's unambiguous.

Mistake 5: Ignoring Color Space Differences

Technically, there are multiple RGB color spaces (sRGB, Adobe RGB, Display P3). Most web work assumes sRGB.

The Fix: For standard web work, don't worry about it. For high-end design or photography, be aware of your color space settings.

For accessibility considerations, check out our WCAG accessibility guide and Color Contrast Checker.

Practical color format use cases

Practical Examples: Real-World Applications

Let's look at how these formats work in actual projects.

Example 1: Hover States with HSL

:root {
  --primary: hsl(262, 100%, 63%);
  --primary-hover: hsl(262, 100%, 53%);  /* 10% darker */
  --primary-active: hsl(262, 100%, 43%); /* 20% darker */
}

.button {
  background: var(--primary);
}

.button:hover {
  background: var(--primary-hover);
}

.button:active {
  background: var(--primary-active);
}

Example 2: Accessible Contrast Checking

// Calculate relative luminance (WCAG formula)
function getLuminance(r, g, b) {
  const [rs, gs, bs] = [r, g, b].map(c => {
    c /= 255;
    return c <= 0.03928 
      ? c / 12.92 
      : Math.pow((c + 0.055) / 1.055, 2.4);
  });
  return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
}

// Check contrast ratio
function getContrastRatio(color1, color2) {
  const lum1 = getLuminance(...hexToRgb(color1));
  const lum2 = getLuminance(...hexToRgb(color2));
  const lighter = Math.max(lum1, lum2);
  const darker = Math.min(lum1, lum2);
  return (lighter + 0.05) / (darker + 0.05);
}

// WCAG requires 4.5:1 for normal text
getContrastRatio("#7241FF", "#FFFFFF"); // ~5.2:1 ✓

Example 3: Generating a Monochromatic Palette

function generatePalette(baseHsl, steps = 5) {
  const { h, s } = baseHsl;
  const palette = [];
  
  for (let i = 0; i < steps; i++) {
    // Spread lightness from 20% to 80%
    const l = 20 + (i * (60 / (steps - 1)));
    palette.push(`hsl(${h}, ${s}%, ${Math.round(l)}%)`);
  }
  
  return palette;
}

generatePalette({ h: 262, s: 100 });
// ["hsl(262, 100%, 20%)", "hsl(262, 100%, 35%)", ...]

For more on palette creation, explore our Monochromatic Color Schemes guide and Color Harmony Series.

Beyond RGB and HSL: Other Formats

The color world is larger than just these three. Here's a quick overview:

CMYK (Cyan, Magenta, Yellow, Key/Black)

Used for print. Subtractive color model—opposite of RGB's additive approach.

LAB (Lightness, A, B)

Device-independent color space. L is lightness, A is green-to-red, B is blue-to-yellow. Great for perceptually uniform gradients.

OKLCH (Lightness, Chroma, Hue)

The new kid on the block. Perceptually uniform and designed for modern displays. CSS Color Level 4 supports it.

Pantone

Standardized spot colors for print consistency. Essential for brand colors that must match exactly.

For Pantone matching, try our Pantone Color Finder.

Tools for Color Conversion

Rather than manually converting, use tools designed for the job:

Our Color Picker

Our AI Color Picker shows all formats simultaneously. Pick a color, get HEX, RGB, and HSL instantly.

Chrome Extension

Need to grab colors from existing websites? Our free Chrome Extension extracts CSS color values in any format—no manual conversion needed.

Light/Dark Mode Generator

Building a design system? Our Light/Dark Mode Generator handles the complex conversions for you, outputting accessible color pairs in multiple formats.

Summary: Your Color Format Cheat Sheet

Format Syntax Best For Watch Out For
HEX #RRGGBB CSS, design handoffs No transparency
RGB rgb(R, G, B) JavaScript, calculations Hard to tweak manually
RGBA rgba(R, G, B, A) Overlays, shadows Alpha is 0-1, not 0-255
HSL hsl(H, S%, L%) Color variations, palettes H is degrees (0-360)
HSLA hsla(H, S%, L%, A) Transparent variations Same as RGBA

The key insight: there's no "best" format—only the right format for your context. Master all three, and you'll never ship the wrong purple again.


Ready to put these skills to use? Try our Color Format Converter to instantly convert between HEX, RGB, and HSL. Or grab our Chrome Extension to extract color values from any website in your preferred format.

For more color theory fundamentals, explore our guides on complementary colors, analogous colors, and color psychology.