Contrast is what a scanner actually reads — design around that and most brand palettes survive.
A scanner does not see red or blue. It reduces the image to greyscale and looks for a light-dark difference between the modules and the background. Any color pair works if the luminance gap is wide enough, and any pair fails if it is not — including pairs that look strikingly different to your eye.
The useful measure is contrast ratio, the same one used for web accessibility. Black on white is 21:1. For print, aim for 7:1 or better and treat anything under 4:1 as a code that will fail somewhere: a dim room, a cheap camera, a worn label, a phone held at an angle.
Two colors can be wildly different in hue and nearly identical in brightness. Hue is what you see; brightness is what the scanner sees.
Dark modules on a light background is what every decoder expects. It is what the specification describes, and it is what hardware scanners, older phones and in-app scanners assume before they try anything clever.
Inverted codes — light modules on a dark background — do work on many modern phones. The iOS camera and Google Lens usually handle them. But a lot of in-app scanners, older Android handsets and almost every dedicated laser or imager scanner will not invert, so an inverted code silently loses you a slice of your audience with no error message and no way to know.
If the design really needs a dark surface, do not invert. Print a light plate behind the code — a white or cream panel with the full quiet zone inside it — and keep the modules dark. It looks deliberate and it scans everywhere.
Contrast ratios below are approximate and calculated the WCAG way, code color against background color. Anything in the safe band has margin left for bad light and cheap cameras.
| Code on background | Approx. contrast | Verdict |
|---|---|---|
| Black on white | 21:1 | Safe — the benchmark |
| Near-black #111827 on white | 17:1 | Safe, and softer than pure black |
| Navy #0B1F3B on white | 16:1 | Safe |
| Dark green #14532D on white | 9:1 | Safe |
| Dark code on light cream #FAF5EC | 15:1+ | Safe — warm backgrounds are fine |
| Teal #0F766E on white | 5.5:1 | Borderline — usable in print, test it |
| Mid grey #808080 on white | 4:1 | Risky — fails in low light |
| Orange #F97316 on white | 2.8:1 | Fails |
| Dark red #8B0000 on black | 2.1:1 | Fails |
| Pastel blue #A7D8F0 on white | 1.5:1 | Fails |
| Yellow #FFD700 on white | 1.4:1 | Fails badly |
| White on near-black #111827 | 17:1 | High contrast but inverted — avoid in print |
Red carries very little luminance for how loud it looks. Pure red on black measures around 5:1 on paper but collapses in practice, because the camera's red channel is the noisiest one and warm indoor lighting shifts white balance further against it. Dark red on black lands near 2:1 and simply does not decode.
The same trap catches yellow and orange from the other end. They read as bright to the eye, so designers pair them with white, where the luminance gap is almost nothing. Yellow on white is about 1.4:1 — a code you can see clearly and a scanner cannot read at all.
The three large squares in the corners are the finder patterns, and a smaller alignment square sits near the bottom right on all but the smallest codes. The scanner uses them to locate the code, work out its orientation, and correct for angle before it reads a single data module.
They must stay the darkest, highest-contrast part of the image. Tinting them a lighter accent color, filling them with a gradient, outlining them with a thin stroke, or letting a logo or photograph overlap them are all reliable ways to build a code that looks great and scans intermittently.
Restyling their shape is a different matter and it is fine. Rounded or circular finder patterns keep the same light-dark relationship while changing the outline, which is why style options exist. Changing their contrast is the thing to avoid.
A gradient across the modules is safe only if every stop in it clears your contrast floor against the background. A gradient running from deep navy to pale sky blue will scan at one end of the code and fail at the other, which is worse than failing outright because it passes your first test.
Most palettes contain something dark enough to work. Take the darkest color in the brand, check it against white, and if it clears 7:1 you can build the entire code from it and still be on brand.
If the brand color is light or mid-tone, spend it somewhere other than the modules: as the background behind a near-black code, as the frame or panel around it, as the call-to-action text underneath, or as the logo in the center. The code itself stays dark and everything around it carries the brand.
A center logo adds its own constraint. Keep it under roughly 20 to 25 percent of the code area and raise error correction to Q (about 25 percent recovery) or H (about 30 percent) so the covered modules can be reconstructed.
Three checks catch nearly everything, and all of them take less time than a reprint.
Colors shift between screen and press. An RGB navy measuring 16:1 on your monitor can print noticeably lighter in CMYK on uncoated stock, so the paper proof is the check that counts.
Free, no sign-up, and your code never expires.
Got your code? ☕ Buy me a coffee — it keeps this tool free for everyone.