RGBA and alpha compositing
A semi transparent overlay looks fine in your design tool and then develops a strange dark fringe once it is composited in code. The culprit is almost always a misunderstanding of what the alpha channel means and how two colors actually blend. The rules are simple arithmetic once you see them written out.
What the alpha channel is
In RGBA, the fourth value is alpha, a coverage or opacity factor from 0 to 1 (or 0 to 255). It does not change the color itself. It says how much of the pixel the color occupies when placed over something else. An alpha of 1 is fully opaque, 0 is fully transparent, and 0.5 means the color contributes half and whatever sits behind it contributes the other half.
Alpha is a channel, not a color. A red at 50 percent alpha and a red at 100 percent alpha are the same red; they differ only in how they combine with the background.
The source over formula
The standard way to place a foreground over a background is called source over. For each color channel, the result is a weighted blend based on the foreground alpha.
out = fg_color * fg_alpha + bg_color * (1 - fg_alpha)
So a foreground red (255, 0, 0) at alpha 0.5 over a white background (255, 255, 255) gives:
R = 255 * 0.5 + 255 * 0.5 = 255
G = 0 * 0.5 + 255 * 0.5 = 128
B = 0 * 0.5 + 255 * 0.5 = 128
The result is a pink (255, 128, 128). Change the background and the same translucent red produces a different final color, which is exactly why a design checked against white can look wrong against a dark page.
Premultiplied versus straight alpha
There are two ways to store an RGBA pixel, and mixing them up is the classic source of fringing.
- Straight (non premultiplied) alpha stores the pure color plus a separate alpha. (255, 0, 0, 0.5) means a full red at half coverage.
- Premultiplied alpha stores the color already multiplied by alpha. The same pixel becomes (128, 0, 0, 0.5).
Premultiplied form makes the compositing math cheaper and, more importantly, handles filtering correctly. When a transparent pixel has a stored color of black, straight alpha blending can bleed that black into the edges during scaling or interpolation, producing a dark halo around soft shapes. Premultiplied alpha avoids this because fully transparent pixels contribute nothing regardless of their stored color. If your faint overlays or anti aliased edges look muddy, check whether one stage of your pipeline expects premultiplied data and another is handing it straight.
You can experiment with colors and see how values combine in the Color Converter & Contrast Checker. It runs in your browser, so the values you test never leave your device. For contrast decisions on layered interfaces, see WCAG color contrast requirements, and for converting between formats, convert HEX, RGB, and HSL colors.
The practical takeaway: alpha is coverage, not color, source over is a simple weighted average, and if soft edges show a dark fringe, suspect a premultiplied versus straight alpha mismatch rather than the colors themselves.