How RGB Color Mixing Works: Additive Light and the 0–255 Range
An RGB color picker mixes red, green, and blue light \u2014 and the results break every intuition you developed finger-painting as a kid. Set Red to 255 and Green to 255 with Blue at 0, and you don't get brown or olive. You get bright yellow. That one result trips up more people than any color theory textbook, and it reveals the fundamental difference between mixing light and mixing ink.

Additive vs. Subtractive: Why RGB Isn't Paint
Your monitor doesn't have yellow pixels. It has red, green, and blue sub-pixels \u2014 nothing else. When you see yellow on screen, that's your red and green sub-pixels firing at high intensity while blue stays dark. Your retina's L-cones (sensitive to red, peaking at ~564 nm) and M-cones (sensitive to green, peaking at ~534 nm) both respond strongly, and your brain interprets that paired signal as yellow (~580 nm). There's no 580 nm light actually being emitted.
Paint works in reverse. Mix red and green pigment and you get a muddy brown because pigments subtract light. Red paint absorbs green and blue wavelengths. Green paint absorbs red and blue. Combine them and almost everything gets absorbed. That's subtractive mixing \u2014 the more you add, the darker it gets. The RGB to CMYK converter shows you exactly how a screen color maps into subtractive ink percentages, and the shift is often dramatic: vivid screen blues land at CMYK values that print noticeably duller.
The 0\u2013255 Range and Where It Comes From
Each RGB channel stores one byte: 8 bits, giving 28= 256 possible values from 0 to 255. That's not arbitrary. In the early 1980s, the IBM PC's VGA standard allocated 8 bits per channel, and the rest of computing followed. Three channels \u00d7 8 bits = 24-bit color = 16,777,216 possible combinations. That number \u2014 ~16.7 million \u2014 lands just above the human eye's ability to distinguish adjacent shades (estimated at 7-10 million discriminable colors under ideal conditions). More bits would be wasted storage for most use cases.
The boundary values matter most. 0 means no light from that channel. 255 means full intensity. RGB(0, 0, 0) is black \u2014 all sub-pixels off. RGB(255, 255, 255) is white \u2014 everything at max. Every shade of neutral gray sits on the diagonal line where R = G = B, from (1, 1, 1) to (254, 254, 254). That's 254 shades of gray, which is 204 more than a certain novel claimed.
Channel Math: Three Worked Examples
Example 1: Coral.Start with RGB(255, 127, 80). Red is maxed out. Green is at half (127/255 = 49.8%). Blue is at 31.4%. This creates a warm, salmon-like tone. In hex, that's #FF7F50. The conversion: 255 \u2192 FF, 127 \u2192 7F (7\u00d716 + 15 = 127), 80 \u2192 50 (5\u00d716 + 0 = 80).
Example 2: A medium gray.RGB(128, 128, 128) sits exactly at the midpoint of each channel. You'd expect this to look like 50% brightness, but on a standard monitor it actually appears brighter than true 50% gray because of gamma encoding. We'll cover that trap in a moment. The hex is #808080 \u2014 each pair being 80 in hex (8\u00d716 + 0 = 128).
Example 3: Constructing teal. Teal is equal parts green and blue with no red: RGB(0, 128, 128). Both the G and B channels at 50% produce a muted, dark cyan. Bump it to RGB(0, 255, 255) and you get full cyan \u2014 one of the three secondary colors in additive mixing. The hex to RGB converter can verify these breakdowns if you want to go the other direction.
When RGB Falls Short
RGB can address 16.7 million colors, but not every color that exists. The sRGB gamut \u2014 the color space web browsers use \u2014 covers only about 35% of the colors the human eye can perceive (the CIE 1931 visible gamut). Highly saturated cyans and greens are the biggest gaps; no sRGB value matches the vivid turquoise of a tropical ocean or the electric green of a highlighter pen.
Wider gamuts exist. Display P3 covers about 25% more than sRGB, and Rec. 2020 covers about 75% of visible colors. Apple devices default to Display P3, which is why that photo you shot on an iPhone can look subtly duller when opened in a standard sRGB browser window. CSS now supports color(display-p3 0.145 0.388 0.922)for wider gamut, but fallbacks are essential \u2014 older browsers will silently drop any color they don't understand, defaulting to inherited or black.
| Color Space | Coverage of CIE 1931 | Bits per Channel | Typical Use |
|---|---|---|---|
| sRGB | ~35% | 8 | Web, CSS, most monitors |
| Display P3 | ~43% | 10 | Apple devices, HDR displays |
| Adobe RGB | ~50% | 16 | Photography, print proofing |
| Rec. 2020 | ~75% | 10\u201312 | HDR video, 4K/8K broadcast |
RGB Sliders vs. HSL Sliders: Which to Use When
Moving an RGB slider affects the final color in a non-intuitive way. Push the red slider from 100 to 200 and the color doesn't just "get more red" \u2014 it also shifts in hue, saturation, and perceived brightness simultaneously. That makes RGB sliders great for precision (you know exactly which byte you're changing) but awkward for exploration.
HSL (Hue, Saturation, Lightness) separates these concerns. Want a darker version of the same color? Drop the L value. Want a muted version? Drop the S value. The hue stays constant. That's why design systems like Tailwind generate their color scales in HSL: adjust one axis, keep the other two fixed. Our RGB to hex converter can help bridge the gap if you start with RGB values from a screenshot and need to derive an HSL-based palette.
Use RGB sliders when you have a specific numeric target (matching a brand spec, pasting values from an API response, tuning individual channel output for LED hardware). Use HSL when you're designing \u2014 exploring tints, shades, and tonal variations of a base color.
The Gamma Trap That Silently Shifts Your Colors
RGB(128, 128, 128) is the mathematical midpoint of each channel. But on your monitor, it doesn't look like 50% brightness. It looks closer to 22%. That's because monitors apply gamma correction \u2014 a nonlinear transfer function that maps stored values to physical light output. The standard sRGB gamma curve is approximately value2.2, which means a stored value of 128 (50% of 255) produces only (128/255)2.2 \u2248 21.8% of the maximum light intensity.
This matters when you try to average two colors. Naively averaging RGB(255, 0, 0) and RGB(0, 0, 255) gives RGB(128, 0, 128) \u2014 a purple. But because of gamma, that purple is darker than you'd expect. The physically accurate midpoint (in linear light space) would be around RGB(188, 0, 188) after gamma encoding. Any time you're blending, interpolating, or computing gradients in code, convert to linear RGB first, do the math, then convert back. CSS gradients handle this automatically since Chrome 111 and Firefox 120 added support for color-interpolation in linear sRGB.
Storing RGB Values in Production Code
Hardcoding rgb(37, 99, 235) across 47 files creates a maintenance nightmare. The industry-standard approach: define once, reference everywhere.
In CSS, use custom properties: :root { --brand-blue: 37, 99, 235; }. Then apply with rgba(var(--brand-blue), 0.5) for 50% opacity, or rgb(var(--brand-blue)) for full. This lets you adjust opacity per-use without duplicating the color.
In JavaScript/TypeScript, a color object is cleaner than a hex string when you need channel math. Store { r: 37, g: 99, b: 235 } and write conversion functions that accept this shape. Hex strings require parsing on every use, while an object gives you direct access to each channel for Canvas API calls like ctx.fillStyle or WebGL uniform buffers.
For design tokens shared between CSS, iOS, and Android, the W3C Design Tokens spec uses an 8-digit hex with alpha (#2563EBFF) or a structured JSON object. Either way, the single source of truth lives in one token file, and build tools generate platform-specific output. Never let the same RGB value exist in two places \u2014 divergence is inevitable.
