ColorDice

What Is a HEX Color Code?

A hex color code is a six-character string that tells a browser, design tool, or image editor exactly which color to display. You have almost certainly seen one: the hash followed by six alphanumeric characters, such as #1E90FF for a vivid sky blue. Once you understand the structure — two characters per color channel, written in base 16 — you can read and reason about any hex value without a color picker. This guide covers the notation from first principles, explains the three-character shorthand, walks through the eight-digit alpha form, and describes where hex codes appear across CSS, design tools, and code.

The Structure: #RRGGBB

Every standard hex color is six characters long, split into three pairs. The first pair (RR) encodes the red channel, the second (GG) encodes green, and the third (BB) encodes blue. Each pair is a two-digit hexadecimal number, meaning it uses the digits 0–9 and the letters A–F, where A equals 10 and F equals 15.

A single hexadecimal digit can represent 16 values (0 through F). Two hexadecimal digits can represent 16 × 16 = 256 values, ranging from 00 (decimal 0) to FF (decimal 255). That maps perfectly onto one byte, which is also 256 possible values. So each color channel is exactly one byte, and the full six-character hex code is three bytes — one for red, one for green, one for blue.

The total number of distinct colors expressible in this format is 256 × 256 × 256 = 16,777,216. That matches the common description of a "24-bit color space" (8 bits per channel, three channels, 24 bits total).

Why Hexadecimal?

Computers store color data as bytes. One byte fits neatly into exactly two hexadecimal digits — no padding, no truncation. Writing the same value in decimal requires up to three digits (0 to 255) and does not group cleanly into equal-width pairs. Compare:

  • Hex: #1E90FF — 6 characters, three equal pairs, each pair is one byte
  • Decimal equivalent: red=30, green=144, blue=255 — 9 to 12 characters, unequal widths, needs delimiters to parse

The compactness of hex also makes it easy to scan visually once you build a little intuition. Values near 00 are dark; values near FF are bright. A pair of identical digits like 88 is in the middle of the range. Designers and developers who work with color daily often develop a rough sense of what a hex string will look like before they ever see a swatch.

Programming languages use the 0x prefix for hexadecimal integer literals (for example 0x1E90FF), but this prefix is not valid in CSS. In stylesheets the # sigil plays that role.

Converting a Hex Code to RGB

Take #1E90FF as a worked example. Split it into three pairs: 1E, 90, FF.

To convert a two-digit hex pair to decimal, multiply the first digit by 16 and add the second:

  • 1E: 1 × 16 + 14 = 30 (E = 14 in decimal)
  • 90: 9 × 16 + 0 = 144
  • FF: 15 × 16 + 15 = 255 (F = 15 in decimal)

So #1E90FF is rgb(30, 144, 255) — a low red value, a medium green value, and a maxed-out blue value, which produces the vivid blue commonly called Dodger Blue. You can verify this in any browser's developer tools by typing the hex value into the color picker.

Going the other direction — from RGB to hex — you divide each decimal value by 16 to get the first digit and take the remainder as the second digit. For 144: 144 ÷ 16 = 9 remainder 0, giving 90. For 30: 30 ÷ 16 = 1 remainder 14 (E), giving 1E.

The Three-Character Shorthand

CSS allows a three-character shorthand when each of the six characters in the full form appears twice in a row. The browser expands each shorthand digit by doubling it. So #ABC becomes #AABBCC, and #F00 becomes #FF0000 — pure red.

The shorthand is only valid when every pair in the full form is a repeated digit. You cannot abbreviate arbitrarily:

  • #AABBCC → shortens to #ABC ✓
  • #1E90FF → pairs are 1E, 90, FF — only the last pair repeats, so no shorthand is possible ✗
  • #336699 → shortens to #369 ✓

Shorthand colors are fully equivalent to their expanded forms in every CSS context. They are not a separate color space or approximation.

Eight-Digit Hex and Alpha Transparency

The CSS Color Level 4 specification added an optional fourth channel — alpha — giving an eight-character form: #RRGGBBAA. The last two digits work exactly like the color pairs: 00 means fully transparent and FF means fully opaque.

For example, #1E90FF80 is the same Dodger Blue at roughly 50% opacity (80 hex = 128 decimal, and 128/255 ≈ 0.50). This is equivalent to rgba(30, 144, 255, 0.50).

A four-character shorthand also exists: #RGBA, which expands to #RRGGBBAA by the same doubling rule. Support for both the 8-digit form and the 4-digit shorthand is solid in modern browsers. If you need to support very old environments, rgba() remains the safer fallback.

Case Sensitivity and Prefix Rules

CSS hex color values are case-insensitive. The browser treats #1e90ff, #1E90FF, and #1E90fF as identical. Pick one convention for your codebase — most linters enforce all-lowercase or all-uppercase — and apply it consistently.

The 0x prefix used in C, JavaScript, and most other programming languages for hex integer literals is not valid in CSS. Writing color: 0x1E90FF will cause the property to be silently ignored. In JavaScript you can write 0x1E90FF as a numeric value when an API accepts integers, but when assigning to element.style.color you must pass the CSS string '#1E90FF'.

Where Hex Colors Are Used

Hex codes appear anywhere a color value needs to be expressed as a single, copyable token. The most common contexts are:

  • CSS stylesheets — color, background-color, border-color, box-shadow color stops, SVG fill and stroke attributes, and gradient definitions all accept hex values.
  • Design tools — Figma, Sketch, and Adobe XD display hex values in their fill and style panels and export design tokens as hex strings. Copying a color from a design file and pasting it into CSS is the most common way hex values travel from design to code.
  • Brand guidelines — style guides typically specify primary and secondary palette colors as hex codes because they are unambiguous across print and digital workflows and can be verified without a color picker.
  • Charting and data visualization libraries — Chart.js, D3, Recharts, and others accept hex strings as series colors in their configuration objects.
  • Terminal and editor themes — themes for VS Code, iTerm, and similar tools are defined almost entirely in hex values in JSON or YAML configuration files.

If you need to generate a random color or explore combinations, tools that output hex codes make it easy to copy values directly into your stylesheet or design file.

Common Mistakes to Avoid

Working with hex colors is straightforward once you understand the format, but a few patterns cause repeated confusion:

  • Wrong number of digits. Only 3, 4, 6, and 8 digits are valid. A 5-digit or 7-digit value is silently invalid; the property will be ignored with no error in the browser console by default.
  • Concatenating decimal RGB values as if they were hex. If you have rgb(30, 144, 255) and naively concatenate the numbers you get #30144255 — an 8-digit string that the browser interprets as blue with a non-255 alpha, which is a completely different color from the intended one. You must convert each decimal value to its two-digit hex representation first.
  • Assuming named colors and hex values are interchangeable approximations. CSS named colors like dodgerblue do map to exact hex values (dodgerblue = #1E90FF), but the mapping is a specification commitment, not a fuzzy match. Other named colors like rebeccapurple have precise hex equivalents (#663399) that may differ from what you would guess.
  • Using hex where a color function is needed. CSS gradients, filter functions, and some JavaScript APIs may expect an rgb() or hsl() value rather than a hex string, or require the alpha channel as a separate argument. Check the specification for the property you are targeting before assuming hex will work everywhere.

For a quick way to explore how hex codes look in practice, try the hex color generator or use the random RGB color tool to see both representations side by side.

Hex vs. Other Color Notations

CSS supports several color notations and each has a context where it shines. Hex is not always the right choice:

  • rgb() and rgba() — useful when you need to compute channel values in JavaScript or when you want inline transparency without the 8-digit hex syntax. The functional form is also more readable to people who are not yet fluent in hex.
  • hsl() and hsla() — expresses color as hue (0–360 degrees), saturation, and lightness. Easier to reason about perceptual relationships: to make a color lighter, increase the L value; to desaturate, reduce S. Hex gives no such intuition directly.
  • oklch() and color() — newer CSS Color Level 4 functions that operate in perceptually uniform spaces. They support wide-gamut displays (P3, Rec.2020) that can show colors outside the sRGB hex range.

Hex remains the dominant notation for static values in CSS and design tools because it is compact, universally supported, and easy to copy as a single opaque token. For dynamic generation — such as picking a random hue for a chart series — functional notations are usually more ergonomic. You can also pick a random colour and inspect its hex value to see how it compares to hsl and rgb representations.

Manipulating Hex Colors in JavaScript

JavaScript does not have a built-in hex color type, but the string format maps cleanly onto integer arithmetic using parseInt and toString(16). A six-character hex code is just three pairs of two base-16 digits — once you parse it as a number, bitwise operations let you extract or modify individual channels.

Extracting channels from a hex string:

function hexToRgb(hex) {
  const n = parseInt(hex.replace('#', ''), 16); // e.g. 0x1E90FF = 2007295
  return {
    r: (n >> 16) & 0xff, // 30
    g: (n >> 8)  & 0xff, // 144
    b:  n        & 0xff, // 255
  };
}

The right-shift operators move the target byte into the lowest 8 bits, and the bitmask 0xff (decimal 255) isolates it. For #1E90FF, the integer value is 2,007,295. Shifting right by 16 bits gives 30 (red); shifting right by 8 bits and masking gives 144 (green); masking without a shift gives 255 (blue).

Building a hex string from RGB values:

function rgbToHex(r, g, b) {
  return '#' + [r, g, b]
    .map(v => v.toString(16).padStart(2, '0'))
    .join('');
}
// rgbToHex(30, 144, 255) → '#1e90ff'

The padStart(2, '0') call is essential: without it, values below 16 produce a single-digit string (for example, decimal 9 → hex '9'), resulting in a five-character hex code that is silently invalid in CSS. Padding ensures every channel is always exactly two hex digits.

Lightening a hex color by a fixed percentage:

function lighten(hex, pct) {
  const { r, g, b } = hexToRgb(hex);
  const bump = v => Math.min(255, Math.round(v + (255 - v) * pct));
  return rgbToHex(bump(r), bump(g), bump(b));
}
// lighten('#1E90FF', 0.3) → '#63afff'

This approach moves each channel 30 % of the remaining distance toward 255, which is a linear interpolation toward white. The result for #1E90FF is #63AFFF — red channel rises from 30 to 99 (30 + (255−30)×0.3 = 97.5 ≈ 98, so the actual output depends on rounding), green from 144 to 177, blue stays at 255 because it is already at the ceiling. Clamping with Math.min(255, …) prevents overflow for channels that are already at or near FF.

Hex Colors and CSS Custom Properties

CSS custom properties (commonly called CSS variables) are the standard way to maintain a consistent color palette across a stylesheet. Storing hex values in custom properties gives you a single source of truth: change the value in one place on :root and every element that references it updates immediately.

:root {
  --color-brand:    #1E90FF; /* Dodger Blue */
  --color-surface:  #F8F9FA;
  --color-on-brand: #FFFFFF;
}

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

.button-primary:hover {
  background-color: #1678d4; /* 15% darker version of #1E90FF */
}

One practical limitation is that you cannot use a partial hex value inside rgb() by splitting a stored hex string — custom properties hold the complete token, not individual channel numbers. If you need to reuse a color at different opacities, the standard approach is to store the RGB channels as a comma-separated triple:

:root {
  --color-brand-rgb: 30, 144, 255; /* same as #1E90FF */
}

.overlay {
  background-color: rgb(var(--color-brand-rgb));        /* fully opaque */
  border-color:     rgba(var(--color-brand-rgb), 0.25); /* 25% opacity  */
}

This pattern is especially useful in component libraries where a button, card, or alert might need its base color at full opacity for backgrounds and a lighter tint for hover or focus rings. The trade-off is that you maintain two representations of the same color — the hex literal in design files and the channel triple in CSS — so a comment linking them prevents drift. Alternatively, modern CSS supports the color-mix() function (baseline 2023) which can dilute a hex color with transparent in a single declaration without splitting channels: color-mix(in srgb, #1E90FF 25%, transparent).

When switching between light and dark themes, custom properties let you redefine the same variable name under a @media (prefers-color-scheme: dark) block or a [data-theme="dark"] selector, swapping hex values without touching any component styles. A minimal two-theme palette might define 6–12 hex tokens on :root and override all of them in the dark selector — every component inherits the correct value automatically.

Frequently Asked Questions

How do I darken a hex color by a specific percentage in JavaScript?+

The cleanest approach is to parse the hex string into its three numeric channels, multiply each by a factor less than 1, clamp the result to 0–255, then reassemble. For example, to darken #1E90FF by 20%: extract R=30, G=144, B=255; multiply each by 0.8 to get R=24, G=115, B=204; then pad each to two hex digits and join: #1873CC. The key detail is the padStart(2, '0') call — without it, values below 16 produce single-digit hex strings and the output is an invalid five-character code. If you need perceptually uniform darkening (where equal percentage steps look equal to the eye), convert to the OKLch color space first, reduce the L channel, then convert back — the sRGB approach can make some hues shift slightly as they darken.

Can I store a hex color in a CSS custom property and use it at different opacities?+

Not directly, because a CSS custom property stores the complete hex token and you cannot split it into channel numbers inside an rgba() call. The established workaround is to store the RGB channels as a comma-separated triple — for example, --color-brand-rgb: 30, 144, 255 — and then reference it as rgba(var(--color-brand-rgb), 0.5) for 50% opacity. A newer alternative is the color-mix() function (supported in all major browsers since 2023): color-mix(in srgb, #1E90FF 50%, transparent) achieves the same result in a single declaration without maintaining a second variable. For a design system managing 10–20 brand tokens, both patterns work; color-mix() is simpler to maintain because you keep only the hex value, while the RGB-triple pattern has better compatibility with older projects that cannot use Color Level 4 features.

What does the # symbol mean in a hex color?+

The hash character is simply a CSS sigil that tells the browser the value that follows is a hexadecimal color literal rather than a named color or a function like rgb(). It carries no numeric meaning of its own. In other contexts, such as JavaScript object literals or design-tool APIs, you may pass the six-character string without the hash, but in CSS stylesheets and HTML attributes the # is required for the value to be recognized. Omitting it causes the declaration to be silently ignored, which can be a hard-to-spot bug when you are copying values from a spreadsheet or design export.

Can I use hex colors in SVG files?+

Yes. SVG attributes like fill, stroke, and stop-color all accept hex color notation exactly as CSS does. You can write fill="#1E90FF" directly on a path element, and the same shorthand rules apply: #ABC expands to #AABBCC. If the SVG is inlined in HTML, you can also target those elements with CSS custom properties, which makes it straightforward to switch a whole illustration between color themes without editing the SVG source. The 8-digit form with alpha (#RRGGBBAA) is supported in modern browsers for SVG attributes too, though older SVG tools may export it as fill-opacity instead.

Is #000000 the same as black and #FFFFFF the same as white?+

Yes. #000000 means red=0, green=0, blue=0, which produces no light at all — pure black on a screen. #FFFFFF means red=255, green=255, blue=255, which is the maximum intensity of all three channels combined — pure white. These are mathematical limits of the 8-bit-per-channel space. Named colors black and white map to exactly these hex values in every CSS specification, so they are precisely equivalent, not just approximate. You can use either form freely; the browser computes the same rendered pixel either way.

Why do some tools show hex in uppercase and others in lowercase?+

CSS is case-insensitive for hex color literals, so #1e90ff and #1E90FF produce identical results. The choice is purely stylistic. Many design tools default to uppercase because it looks more distinct from the letter O versus the digit 0. Code formatters like Prettier typically enforce lowercase for consistency. What matters most is picking one convention for your codebase and sticking to it — mixed case within a single file makes values harder to compare at a glance and can trip up naive string-matching in scripts that process your styles.

What is the difference between a hex color and an RGB color?+

They describe the same color model — red, green, blue channels each on a 0-to-255 scale — but use different syntax. rgb(30, 144, 255) and #1E90FF are two representations of the same color: decimal versus hexadecimal encoding of the same three bytes. Hex is more compact (seven characters including the hash versus roughly fifteen for the rgb() form) and easier to copy as a single token, which is why it dominates in CSS, design tools, and brand guidelines. The rgb() form is useful when you need to compute channel values arithmetically in JavaScript or when you want to set transparency with rgba() in older codebases. Modern CSS also supports hex alpha (#RRGGBBAA), so the transparency argument for rgb/rgba is less compelling today.

Can I animate hex colors in CSS?+

Yes, but with a caveat. CSS transitions and animations can interpolate between two hex color values, and the browser will smoothly blend through intermediate colors. However, the interpolation space matters: by default the browser uses the sRGB color space, so the midpoint between two saturated colors may look slightly muddy. The CSS Color Level 4 specification introduces the color-mix() function and the color() function with explicit color-space arguments (such as display-p3 or oklch), giving you more control over how blending behaves. For simple use cases like hover state changes, plain hex transitions work well and require no extra syntax.

How do I convert a hex color to HSL?+

The conversion goes through RGB as an intermediate step. First convert the hex pairs to decimal: for #1E90FF you get R=30, G=144, B=255. Normalize each to 0-1 by dividing by 255: R=0.118, G=0.565, B=1.0. Find the maximum and minimum of those three values. Lightness is (max + min) / 2. Saturation depends on whether lightness is above or below 0.5 and involves dividing the max-min range by 1 minus the absolute value of (2 * lightness - 1). Hue is derived from which channel is the maximum and the ratio between the others. The arithmetic is deterministic and reversible. Most programming languages have a built-in or a one-liner library function for this; understanding the steps helps you diagnose why two visually similar colors can have very different HSL values.