Color Consistency Across Print, Web and Product
Brand color consistency across media comes from designating a source of truth, not from hunting a perfect conversion: one canonical definition per color — a screen value for everything digital, a committed print twin for ink, cross-referenced and both written down — one derived system per medium generated from that canonical value, and roles rather than raw values in every instruction that mentions color.
The honest boundary belongs up front: a perfect visual match across ink, screen and fabric is not physically available, because the media produce color in different ways. The achievable goal — and the one viewers actually judge — is family resemblance across media plus strict consistency within each medium. How to build that is the subject of this article, part of our brand colors guide.
Why does cross-media consistency fail by default?
Because each medium has its own color space, its own tools and its own people. Print work thinks in inks and process builds; the web thinks in hex and CSS; packaging and product vendors think in whatever their supplier’s spec sheet asks for. The whole discipline of color management exists because media do not agree with each other on their own.
Without a designated source of truth, each medium’s team approximates from whatever artifact they happen to have: the sales deck approximates the website, which approximated the brand book, which was exported from a design file nobody can find. A useful analogy is a photocopy of a photocopy — though the analogy flatters the process, since here every copy is made by a different person with different tools. The failure is organizational before it is technical: not that any conversion was done badly, but that nobody declared which artifact is the original.
What does a source of truth actually contain?
Per brand color, a canonical record with three properties:
- One screen value — the source for everything digital: web, app, templates, decks, video.
- One committed print twin — the spot ink and/or process build the brand prints with, settled with the printer, not computed from the screen value at the moment of need.
- Cross-references in both directions — the screen entry names its print twin, the print entry names its screen value, and both live in the brand book.
The point is that this is a pair, decided once — not one value asked to serve both media, and not two values that each team converts between on demand. When the record also states which value governs which medium, the ad-hoc conversion that produces most of the spread has nowhere left to happen.
Why roles instead of raw values?
Because “use brand-600 on light surfaces” travels, and “use our blue” doesn’t. A raw value tells you what a color is; a role tells you what it is for — and for is the part every instruction actually needs. “Our blue” gets resolved by each reader against a different artifact, which is the approximation chain restarting. A role name binds the instruction to the system instead of to someone’s memory.
Roles are also what make instructions durable. If an audit of the palette later moves the fill-under-white-text one step darker, every instruction written in role language remains correct — the role’s value changed, the role’s job did not. Instructions written in raw values all silently expire.
What does one color’s canonical record look like?
Checklist-shaped, for a brand blue:
brand blue — canonical record
screen (governs all digital): #2563EB — oklch(0.546 0.215 262.9)
print twin (committed): the brand's named spot ink;
process build CMYK ≈ 84/58/0/8 on coated stock
(one plausible build — settled with the
printer, not computed)
And beneath it, the role table for the digital side, derived from the screen value:
| Role | Step | Where it is used |
|---|---|---|
| Brand fill | brand-500 #2563EB | buttons, links, key accents |
| Fill under white text | brand-600 ≈#1E4FC2 | anywhere white text sits on brand color |
| Tinted surface | brand-100 ≈#DFE9FD | washes, cards, highlighted rows |
| Brand text on light | brand-700 ≈#173A8A | headings and links that must stay readable |
| Text on brand fill | onFill, contrast-checked near-white | labels inside filled components |
The division of labor is worth stating exactly: the digital half of this record — the ramp, the roles, the contrast checks behind them — is what the Scale Composer generates from the canonical screen value. The print twin comes from print work, matching ink on paper with the printer, and is recorded alongside, cross-referenced. One tool owns the screen side; one decision owns the pair.
Open one canonical value with its derived role system in the Scale Composer — the screen half of the record above, generated from the single seed, role names attached to their steps.

How close can print, screen and product actually get?
Close enough to read as one brand; never identical. Ink reflects light, screens emit it, fabric and coated surfaces each do something else again — no amount of care produces the same light from all of them.
What makes this workable is a perceptual point: viewers almost never hold two media side by side. They hold memory against the present — the blue remembered from the app against the blue on the box in front of them. And memory stores the family, not the coordinates: the hue, the character, the role. A screen blue and a printed blue that are honest siblings both confirm the same memory. What breaks the spell is not the print-versus-screen gap — it is two screens disagreeing, or two printed pieces disagreeing, because within one medium there is no physics to excuse it. Hence the goal stated at the top: family resemblance across media, strict consistency within each.
Where does the consistency work start?
In dependency order: designate the canonical pair for each brand color; let the digital system be derived from the screen value rather than assembled by hand; rewrite standing instructions from raw values to roles; and retire the orphan values the old approximation chain left behind, explicitly, so they stop being found and reused.
The first and second steps are one motion in practice. Generate the role map from one canonical value — seed the system with the screen value you commit to, and the role table that every digital instruction can point at comes out with it.