Build a solid fill or a two-stop gradient, watch sample text sit on top of it, and read the WCAG contrast ratio before the color reaches your stylesheet. Output comes in HEX, RGB or HSL with a solid fallback line already in place.
Section heading
Text sitting on your background
Body copy at 15px. If this line starts to swim, the ratio below has already dropped under 4.5:1.
Call to actionRatios use the worst point of the fill, composited over white.
The checkerboard shows through wherever alpha sits below 1, so a translucent fill reads as translucent rather than as a lighter tint.
background-color: #2f6fed;A background color rarely fails on its own. It fails once text lands on it. WCAG 2.1 asks for a 4.5:1 ratio between body copy and its background, dropping to 3:1 for text at 24px or 18.66px bold. The strip under the preview runs your fill against white and against near-black on every change, so a soft blue-grey gets flagged while you are still picking rather than after a designer signs off on the mockup.
The trap sits in the middle of the lightness range. Pale tints clear the bar with dark text but fail with white, deep tones do the reverse, and a narrow band of greys fails both. Run the numbers on the neutral ramp against white and against #111827 and exactly ten values, #777777 through #808080, miss 4.5:1 in either direction. Those mid-greys look confident in a swatch grid, then leave you with no text color that passes.
| Background | White text | Dark text | Works with |
|---|---|---|---|
| #f8fafc | 1.05:1 | 16.96:1 | Dark text only |
| #2f6fed | 4.55:1 | 3.90:1 | White text, any size |
| #0f766e | 5.47:1 | 3.24:1 | White text, any size |
| #7c7c7c | 4.17:1 | 4.25:1 | Large text either way |
| #7f8ea3 | 3.33:1 | 5.32:1 | Dark text at any size |
| #0f172a | 17.85:1 | 1.01:1 | White text only |
One caveat on the numbers here. A translucent fill has no fixed ratio, because what shows through changes with the layer underneath. This page composites your color over white before measuring, which matches the default page background. Drop the same rgba over a photo or a dark section, and the true ratio moves.
Two lines look interchangeable until you put text inside the box:
.overlay {background-color: rgba(15, 23, 42, 0.6);}The panel softens. The caption inside stays at full strength.
.overlay {background-color: #0f172a;opacity: 0.6;}The panel softens along with its heading, its body copy, its icons, its focus ring.
Move the alpha slider on this page and the value shifts to rgba() notation on its own, or to an 8-digit hex if you left the notation on HEX. Both forms have shipped in every current browser for years, though 8-digit hex still trips up older build tooling that predates CSS Color 4, which is the one reason to prefer the rgba form in a shared codebase.
Alpha earns its place in three spots: scrims over hero images, hover and pressed states built from the same brand color, and disabled surfaces where a separate grey token would drift out of sync. Outside those, a flat opaque value renders faster and reads the same.
Switch to gradient mode and the output grows a second line. That is deliberate:
background-color: #2f6fed;background-image: linear-gradient(135deg, #2f6fed, #0f766e);A gradient is an image, not a color. Anything stripping background-image, from a print stylesheet to forced-colors mode to an email client, leaves the box with no fill at all unless a solid line sits behind it. Setting both costs nothing at render time.
0deg points up and rotation runs clockwise, so 90deg flows left to right. The keyword to right equals 90deg, and to bottom equals 180deg.The fade checkbox rewrites the end stop as the same color at zero alpha, which is the standard recipe for a scrim over a hero image. Do not fade to the keyword transparent by hand. WebKit has a long history of interpolating that ramp through transparent black, which greys out the middle of the sweep. Naming the same color at zero alpha sidesteps the question in every engine.
The scope stops where a background stops being a background color.
background-blend-mode live in the background image generator.oklch(), lab() or color-mix() output. Those notations pick better perceptual midpoints for gradients, but they still lack a fallback story on older Safari, so this page sticks to what ships everywhere.Everything runs in the browser. No color is uploaded, and the recent swatch strip lives in your own localStorage, so clearing site data empties it.
Notation, contrast, alpha and the parts of the spec worth knowing.
background is a shorthand that resets color, image, position, size, repeat, attachment, origin and clip in one declaration. Anything you leave out returns to its initial value, so background: red wipes a background-image set earlier in the cascade. background-color touches the fill alone and leaves the other seven properties untouched.
WCAG 2.1 level AA asks for 4.5:1 against body text and 3:1 against text that is 24px or larger, or 18.66px bold. Level AAA raises those to 7:1 and 4.5:1. Non-text elements such as input borders and icons need 3:1 under success criterion 1.4.11.
Yes in every current release. Safari and Firefox shipped #rrggbbaa in 2016, Chrome followed in 2017, and Edge inherited it with the Chromium rebase in 2020. The remaining gap sits in tooling rather than browsers, since some older preprocessors and email sanitisers strip the last two digits. Switch the notation to RGB when a build step is involved.
The background on body propagates to the canvas only while html has no background of its own. Set one on html and body keeps its own fill inside the element box instead, which is why a short page sometimes shows two different colors above and below the fold.
HSL makes relationships readable. Hover states, tints and shades come from moving lightness by a fixed step while hue and saturation hold, which is hard to eyeball in hex. Hex stays more compact and copies cleanly between design tools. The notation toggle on this page prints the same color either way.
Put the alpha in the color, not on the element. rgba(15, 23, 42, 0.6) softens the fill alone. The opacity property applies to the element and every descendant, so text, borders and icons fade with it.
On a static block the cost is negligible, since the browser rasterises once. It matters on elements that animate or repaint constantly, where a large gradient repaints every frame. Animate transform or opacity instead of the gradient stops, or promote the layer with will-change.
Nothing automatic. A background color set in CSS stays fixed unless you scope it inside a prefers-color-scheme media query or drive it from a custom property you reassign. Pick your light surface here, run the dark counterpart through the tool separately, and check both ratios.