You pick a colour, note the hex code, and hand it to a designer, a developer and a printer. Three different renderings come back. Nobody made a mistake, and the file was not corrupted. The hex code simply does not contain enough information to specify a colour on its own, and the missing piece is the colour space.
Three numbers are not a colour
A hex code is three values describing how much red, green and blue to mix. To turn that into light you need two further pieces of information that the code does not carry.
The first is which red, green and blue. “Red” is not a fixed physical thing; it is whatever the display’s red primary emits, and different standards specify different primaries. The set of colours reachable by mixing a particular trio is that space’s gamut.
The second is the transfer curve, which describes how a stored number maps to emitted light intensity. The relationship is deliberately not linear, because human vision is far more sensitive to differences among dark tones than among bright ones, so spending an equal share of the available numbers on each would waste most of them on distinctions nobody can see. The curve allocates more precision where perception needs it.
Change either the primaries or the curve and the same three numbers become a different colour.
What sRGB actually is
sRGB is a specification from the late 1990s that pinned down both of those things, modelled on the cathode ray tube monitors of the era. It defines exact primaries, a white point, and a transfer curve.
Its historical importance is hard to overstate: it is why the web works at all. When a browser meets an image or a hex code with no profile attached, it assumes sRGB, and because essentially everyone targeted sRGB for two decades, that assumption was almost always right.
The curve is worth looking at concretely, because it appears in more places than people realise. It is not a simple power function. It has a small linear segment near black, below a threshold of 0.03928 in normalised terms, where the value is divided by 12.92, and above that a power function applied to the value offset and scaled by 0.055 and 1.055, raised to 2.4. The linear toe exists to avoid an infinite slope at zero, which would cause numerical trouble and amplify sensor noise in the darkest tones.
That exact formula is not academic trivia. It is the first step of the accessibility contrast calculation, and getting it wrong produces a ratio that looks plausible and is wrong.
Contrast is defined in sRGB, and the numbers are unforgiving
Web accessibility contrast is computed by linearising each channel with that curve, combining them into a relative luminance with fixed weights, and taking a ratio between the lighter and darker result with a small constant added to both.
The weights are the interesting part: red contributes 0.2126, green 0.7152, and blue 0.0722. Green dominates by a wide margin because human vision is most sensitive in that part of the spectrum, and blue contributes almost nothing to perceived brightness. This is why a saturated blue on black is so hard to read while a saturated yellow on black is easy, even though both are “bright colours”.
The constant added to both luminances before dividing is what keeps the ratio finite and bounded: the scale runs from 1 to 1 for identical colours up to 21 to 1 for black on white.
The thresholds that matter are 4.5 to 1 for normal text at level AA, 3 to 1 for large text at AA, 7 to 1 for normal text at AAA and 4.5 to 1 for large text at AAA. Our own contrast checker reports all four at once rather than a single pass or fail, because a colour pair that fails for body text can be perfectly acceptable for a heading, and collapsing that into one verdict throws away the useful part of the answer.
The boundaries are sharper than intuition suggests. On a white background, the grey #767676 just clears the 4.5 to 1 threshold and #777777 does not, a difference of one step in each channel. The stricter 7 to 1 threshold falls between #595959 and #5a5a5a. Nobody can see the difference between those pairs, and one passes while the other fails, which is a good argument for measuring rather than eyeballing.
Note the dependency: because the formula is defined against sRGB values and the sRGB curve, feeding it numbers from a different colour space produces a number that does not mean what the standard says. Convert first, then measure.
Wide gamut, and where photos go wrong
Modern displays can show colours sRGB cannot express, and the spaces built for them, such as Display P3, have primaries further out, particularly in the reds and greens. A photograph captured and stored in one of those spaces holds saturated colours that simply have no representation in sRGB.
Handled correctly, this is invisible: the file carries an embedded profile saying which space its numbers belong to, and software reads that profile and converts as needed. Handled incorrectly, it is the single most common cause of “my photo looks wrong on the web”.
Two failure modes account for most of it. If the profile is stripped, by an export setting or by a tool that rebuilds the pixels without carrying metadata across, the numbers are left to be interpreted as sRGB, and a wide-gamut number read as sRGB lands on a less saturated colour. The photo looks flat. Conversely, if sRGB content is displayed by software that assumes a wide space, everything looks oversaturated and slightly cartoonish.
The practical rule is to export as sRGB for the web and keep the wide-gamut file as the master. The conversion is lossy in a way worth being explicit about: colours outside the destination gamut are mapped to the nearest available ones, so distinctions between two very saturated colours can collapse to a single value, and no later conversion recovers them.
Converting between notations is not converting between spaces
Hex, RGB and HSL are three ways of writing the same numbers, and a colour converter moves between them losslessly. That is a genuinely useful operation, particularly since HSL makes “the same colour but lighter” a single-parameter change, which is how design token scales are usually built.
But changing notation is not changing space. Converting a hex code to HSL does not move it into a different gamut or alter which physical colour it names. It is the same colour described differently. Space conversion is a separate operation involving the primaries and the transfer curve, and it is the one that can lose information.
Two ways of removing colour, and only one is about perception
Colour spaces also decide what happens when you take colour away, and the two operations people lump together are quite different.
Converting a photo to greyscale is a weighted sum of the channels, using weights that reflect perceived brightness rather than a plain average. The traditional broadcast coefficients put red at 0.299, green at 0.587 and blue at 0.114. Applied to a fully saturated red, that yields a grey of about 76; saturated green yields about 150 and saturated blue about 29. A naive average would put all three at 85, making them indistinguishable, which is exactly why converting a photo to black and white uses weights: an averaged conversion flattens a red car against green foliage into one undifferentiated smear.
Simulating colour blindness is a different operation entirely. It does not remove colour; it transforms it to model what a viewer with a particular cone deficiency perceives. Our colour blindness simulator applies published matrices for the three common dichromacies, and it does so in linear light: the pixel is linearised out of sRGB first, the matrix is applied, the result is clamped back into range, and then it is re-encoded to sRGB. Applying a matrix directly to the stored values, without linearising, produces a plausible-looking image that is not what the model describes, because the transfer curve is in the way.
Achromatopsia is treated separately there, because the complete absence of colour discrimination is not the same kind of shift as a red-green deficiency and is not described by the same family of matrices.
The design consequence is one worth internalising: a palette that satisfies the contrast thresholds may still be unusable if it distinguishes states by hue alone. A red and green pair can have identical luminance, pass nothing, and be indistinguishable to a significant share of readers. Checking both is two operations, not one.

