HEX and RGB Color Codes: How to Read, Convert and Check Contrast

#e63946 and rgb(230, 57, 70) are the same red written two ways. Learn to read HEX at a glance, convert between HEX, RGB and HSL, and check whether a text color clears the WCAG contrast thresholds.

9 min read ToolsBasic
HEX and RGB Color Codes: How to Read, Convert and Check Contrast

Color codes are numeric descriptions of a color that browsers, design tools and stylesheets all understand. The two you will meet most often on the web are HEX, written like #e63946, and RGB, written like rgb(230, 57, 70). Both describe the same thing: how much red, green and blue light to mix, on a scale of 0 to 255 per channel. HEX writes those three numbers in base 16, RGB writes them in base 10, and HSL describes the very same value again as hue, saturation and lightness.

The color picker shows the HEX and RGB values of any shade you choose, side by side. When you need to find values buried in a production stylesheet, the CSS beautifier spreads minified CSS back out so you can scan it. The CSS to SCSS converter nests existing rules so you can start introducing variables by hand, and the SCSS to CSS compiler turns functions like darken() and rgba() into plain values.

Reading HEX color codes at a glance

A HEX code is a hash sign followed by three pairs of hexadecimal digits: #RRGGBB. Hexadecimal uses 0–9 and then a–f for ten to fifteen, so each pair runs from 00 (0) to ff (255). With 256 possible values per channel, the format can express 256³, or 16,777,216, distinct values.

Take #e63946, a typical brand red. Split it into e6, 39 and 46. The first pair is high and the other two are low, so before converting anything you already know it is a red. With a little practice most codes can be read this way:

CodePatternWhat you see
#ffffffAll channels fully onWhite
#808080All three equalA neutral gray
#e63946Red pair dominantWarm red
#0066ccNo red, some green, strong blueClassic link blue
#ffcc00Red and green high, blue offYellow
#1a1a1aAll equal and very lowNear-black

Equal channels always produce a gray. Red plus green produces yellow because screens mix light, not paint, which is the one intuition from art class you have to unlearn.

Shorthand HEX

When both digits in every pair match, the code can be written with three digits and the browser doubles each one. #fc0 is #ffcc00, #06c is #0066cc, #333 is #333333. A code like #e63946 cannot be shortened, and trying gives you something else entirely: #e34 expands to #ee3344. Letter case does not matter to the browser, but picking one convention makes searching a codebase far more reliable.

Eight-digit HEX for transparency

CSS Color Module Level 4 added an optional fourth pair for alpha: #RRGGBBAA, where ff is fully opaque and 00 fully transparent. #0066cc80 is that link blue at roughly 50% opacity, since 128 divided by 255 is about 0.5. A four-digit shorthand exists too, so #06c8 means #0066cc88. Every current browser supports it, though the percentage in an rgb() value is easier for a colleague to read.

RGB and RGBA notation

RGB writes the same three channels in decimal. Older CSS uses commas and a separate function for transparency, while the modern syntax uses spaces and accepts alpha after a slash:

color: rgb(230, 57, 70);
color: rgba(230, 57, 70, 0.6);
color: rgb(230 57 70 / 60%);

All three are valid in current browsers, and in modern CSS rgba() is simply an alias of rgb(). Stick to the comma form if you still support very old browsers. The practical advantage of RGB over HEX is arithmetic: lightening, darkening or adding transparency is easier to reason about in decimal.

HSL: the designer-friendly notation

HSL answers three questions a person would actually ask. Hue is a position on the color wheel in degrees, with 0 for red, 120 for green and 240 for blue. Saturation is how vivid the shade is, from gray at 0% to fully saturated at 100%. Lightness runs from black at 0% through the pure hue at 50% to white at 100%. Our red, #e63946, is hsl(355, 78%, 56%).

Where HSL shines is in generating related shades. Keep hue and saturation fixed, move lightness, and you get hover, active and disabled states that clearly belong together. Sass's darken() and lighten() do exactly that, shifting HSL lightness by the amount you pass:

$brand: #e63946;
.btn:hover { color: lighten($brand, 15%); background: darken($brand, 8%); }

Compiled, that becomes color: #ef7d85; and background: #db1c2a;. Same hue, same saturation, different lightness.

Converting between color codes by hand

Conversion between these notations is lossless in principle; they are three spellings of one value. The color picker gives you HEX and RGB together. If you want to understand the math, do it by hand once:

  1. Split the HEX code into pairs: #0066cc becomes 00, 66 and cc.
  2. Convert each pair: first digit times 16, plus the second digit. 66 is 6 × 16 + 6 = 102 and cc is 12 × 16 + 12 = 204.
  3. Write the RGB value: rgb(0, 102, 204).
  4. To go back, divide each number by 16: the quotient is the first digit and the remainder the second. 204 / 16 is 12 remainder 12, which is cc.
  5. For HSL, scale each channel to 0–1 and find the highest and lowest. Lightness is their average; saturation and hue follow from the gap between them and which channel leads. Here that gives hsl(210, 100%, 40%).
NameHEXRGBHSL
Brand red#e63946rgb(230, 57, 70)hsl(355, 78%, 56%)
Link blue#0066ccrgb(0, 102, 204)hsl(210, 100%, 40%)
Signal yellow#ffcc00rgb(255, 204, 0)hsl(48, 100%, 50%)
Near-black#1a1a1argb(26, 26, 26)hsl(0, 0%, 10%)

One caveat: HSL is usually rounded to whole numbers, so a round trip through it can land one unit away from where you started. Keep the HEX or RGB value as the source of truth in your design tokens.

Contrast: making color codes pass WCAG

A palette is only useful if people can read what is written in it. The W3C's Web Content Accessibility Guidelines measure the difference between text and background as a ratio from 1:1, identical values, to 21:1, black on white. The thresholds in WCAG 2.1 and 2.2 are:

  • Body text, level AA: at least 4.5:1 (Success Criterion 1.4.3).
  • Large text, level AA: at least 3:1. Large means 18 point (about 24 CSS pixels) or 14 point bold (about 18.66 pixels).
  • User interface components and graphics: at least 3:1 against adjacent colors, covering input borders, focus indicators and meaningful icons (Success Criterion 1.4.11).
  • Level AAA: 7:1 for body text and 4.5:1 for large text (Success Criterion 1.4.6).

How the ratio is calculated

Each value's relative luminance comes first. Divide each channel by 255, then linearize it: results at or below 0.04045 are divided by 12.92, the rest become ((value + 0.055) / 1.055) raised to the power 2.4. Older copies of the guidelines print 0.03928 there; with 8-bit channels the outcome is identical. Luminance is 0.2126 × R + 0.7152 × G + 0.0722 × B, weighted towards green because the eye is most sensitive to it. The contrast ratio is (lighter luminance + 0.05) divided by (darker luminance + 0.05).

TextBackgroundRatioVerdict
#1a1a1aWhite17.40:1Passes AAA
#0066ccWhite5.57:1Passes AA for body text
#6b7280White4.83:1Passes AA for body text
#e63946White4.17:1Large text only
#9ca3afWhite2.54:1Fails even for large text
#1a1a1a#ffcc0011.51:1Passes AAA

The red row catches many brand palettes: a red that looks bold in a logo falls short for paragraph text on white. The yellow row shows the fix for bright brand colors in general. Do not put white or pale text on them; put dark text on them.

Contrast mistakes that slip through reviews

  • Placeholder text. Light gray hints inside inputs are text, and most default styles fall below 4.5:1.
  • Text over photos. Measure against the lightest part of the image, or add a translucent dark overlay behind the words.
  • Hover and focus states. A link that passes at rest can drop below the threshold in its lighter hover state.
  • Hue as the only signal. Marking an invalid field with nothing but a red border tells a color-blind user nothing. Add text or an icon as well (Success Criterion 1.4.1).

Inactive components and purely decorative elements are exempt from the contrast minimum, but that exemption never covers text people are expected to read.

Keeping a stylesheet consistent

In a growing codebase the real problem is rarely choosing a shade. It is the same blue appearing as #06C, #0066cc and rgb(0, 102, 204) across thirty files. A few habits prevent that:

  • Define every brand value once, as a custom property (--brand-blue: #0066cc;) or a Sass variable.
  • Choose one spelling, for example lowercase six-digit HEX, and enforce it in code review or with a linter.
  • Derive transparent versions from the same token, such as rgba($brand, 0.15), instead of inventing near-duplicates.
  • When auditing a minified stylesheet, beautify it first; an inventory is much easier to build from one declaration per line.

Frequently asked questions

Is there a quality difference between HEX and RGB?

No. Both store the same 8 bits per channel in a different number base, so #0066cc and rgb(0, 102, 204) render as the identical pixel. Choose whichever your team reads more easily.

Should I use eight-digit HEX or rgba() for transparency?

Both work in current browsers. Eight-digit HEX is shorter, but alpha expressed as a hex pair is hard to read at a glance, whereas rgb(0 102 204 / 15%) is obvious to anyone reviewing the code.

Why does the same code look different on two screens?

The codes describe a value in the sRGB color space. Display calibration, brightness and wide-gamut panels can render that value differently. As long as the code is the same, the browser is asking for the same result.

Does 4.48:1 round up to 4.5:1?

No. The guidelines do not round, so 4.48:1 fails the body text threshold and automated checkers will flag it. Darkening the text by a single step usually fixes it without changing the look.

For how fills and strokes are stored inside vector graphics, read what an SVG file is. The guide on how to choose an image format covers why palette size affects file weight. Once your stylesheets are ready for production, what minification is explains the last step before deployment, and if you are tempted to inline small icons in CSS, what Base64 is tells you when that pays off.

Related tools

Catalog

Blog Posts