I adore components, because they are the astonishing.
7 years after Computer Color is Broken, the web is still doing color wrong.
Correct color mixing
Correctly rendered gradients between primary colors
Physically correct color gradients (as you would get, for example, along an out of focus edge between colors) are equally bright around the midpoint, representing the average between the two colors. Incorrect rendering turns the middle into murky dark colors.
Green and white at 25% opacity, black at 75% opacity
Overlaying bright colors at 25% transparency is supposed to tint underlying dark areas properly, washing them out like a light shone onto a projection screen. Incorrect rendering results in excessive contrast, as if we just turned up the camera exposure or stuck on an unlit filter.
Overlaying black at 75% shouldn’t completely overpower bright areas nor crush the blacks. Think about how bright the scene would be if you had 4 lights and turned off 3.
CSS rgba() background
A test image scaled down by powers of two.
The outer and inner parts of the grey square should be the same overall brightness, since they both emit an average amount of light half as bright as white. Incorrect rendering makes the outer part darker.
The image should retain the same overall brightness as it is scaled down. Incorrect rendering makes the smallest copies too dark.
Note: this demo only works properly if the image is displayed at 1:1 pixel size. If you have a HiDPI display or are using the zoom feature, your browser is already scaling it (incorrectly) and the full-size image will look wrong.
What’s going on?
Almost all colors on the web (from the data in your average PNG file to hex values in CSS and SVG) are represented not as actual color intensities, but using a lossy compression algorithm called “8-bit sRGB”. Most people call this a “color space“, but its primary purpose is to represent color data in fewer bits than would be required for decent quality if you were storing actual, numerical brightness values corresponding to light intensity. Therefore, it is more useful to think of it as a lossy compression technology.
Unfortunately, by calling it a “color space“, we’ve misled the vast majority of developers into believing that you can do math on sRGB colors, and by exposing the raw sRGB numbers to users, we’ve misled them into thinking those numbers have a reasonable meaning. Just like you can’t mix the bits of two MP3 files without uncompressing them* and expect to get something that sounds like both sounds mixed together properly, you can’t take two sRGB color values, mix them, and expect to get the right color. And yet, this is what every major browser does.
The correct way to process sRGB data is to convert it to linear RGB values first, then process it, then convert it back to sRGB if required. If you are doing any mathematical operations on sRGB color data directly, your code is broken. Please don’t do that. It’s 2022; it’s about time we make computer graphics work properly.
There is a color-interpolation SVG attribute that fixes this problem, and this page attempts to use it. Unfortuntely, no browser implements it yet. That attribute was first specified in SVG 1.1 from 2003. We’re coming up on 20 years of browsers not bothering to implement correct color blending.
It’s worth noting that GPU manufacturers and most game developers have had this figured out for a long time now, since linear processing is required for realistic environments, especially with complex effects. Modern GPUs can transparently convert from/to sRGB when loading and rendering images, without any performance penalty. This ends up causing pain when designers using broken design tools find things look different in a correctly implemented game engine.
Share this on knowasiak.com to discuss with people on this topicSign up on Knowasiak.com now if you’re not registered yet.