skip to content

What can a contrast-ratio check on a static color palette miss in a live, running interface?

level: seniorimportance: nice to knowfreq 27%

answer

  1. The swatch is not what renders
  2. Ask what is actually behind the glyphs
  3. Every visual state is a new pair
  4. Imagery and translucency move the target
  5. Report the worst pair, not the average

basics

~20 s

A ratio describes two colors as finally composited, so a palette check misses whatever the palette does not pin down: text over imagery and gradients, translucent overlays, and every visual state a control enters. Measure the composite, not the swatch.

solid answer

~50 s

A contrast figure is a property of **two specific colors as they are finally composited**, so a check run against a swatch list only covers the pairs that list actually pins down. Three blind spots dominate. **Variable backdrops**: text over a photograph, a video frame or a gradient has a different background at every pixel, and a different one again for the next record, so the honest measurement is the worst pair the content can produce. **States and layers**: pointer-over, pressed, selected, in-error, inactive and focused each create a new pair, and a translucent overlay or a shadow silently changes the effective background beneath everything under it. **Rendering context**: a second theme, a denser layout, a different locale's font, or a screenshot captured under one setting each move the answer. A passing palette is a starting point, not a result.

code

pseudocode · 9 lines
pseudocode
PAIRS TO MEASURE = surfaces x states, not colors

for each surface the component can sit on:
      solid card | tinted sheet | photograph | video frame | overlay
  for each visual state it can enter:
      rest | pointer-over | pressed | selected | error | inactive | focused
    measure(text_color, color_composited_behind_the_glyphs)

report the WORST pair found, never the average, never one sample

go deeper

for a junior

Be ready to say that the two colors being measured are the text color and whatever is actually rendered directly behind it. If an image or a translucent layer sits between them, the recorded palette pair is not the pair on screen.

for a middle

Explain why a palette cannot cover everything: backgrounds that come from content rather than from the palette, visual states that each create a new pair, and layers whose transparency changes the effective color underneath.

for a senior

Show the working habit - enumerate surfaces multiplied by states, measure the composite, report the worst case rather than a sample, and change the design so a variable backdrop becomes a fixed pair instead of a recurring review item.

for a principal

Own the framing that a contrast guarantee has to be structural. Decide where text is allowed to sit at all, so the number of pairs anyone must reason about stays bounded while the product keeps growing.

## Why the swatch is not the thing being measured A contrast ratio is defined over **two colors**. Not a color, not a set of colors, and not a design - two colors, as they finally land on the display after everything above and below them has been composited. A palette review checks the pairs somebody thought to write down. The interface renders whatever it renders. The gap between those two sentences is where nearly every shipped contrast defect lives. It is not caused by anyone computing a ratio wrongly. It is caused by measuring the wrong pair. ## The three blind spots | Blind spot | Why the palette check misses it | What to do instead | | --- | --- | --- | | **Variable backdrops** - text over photographs, video frames, gradients | The background is not in the palette at all, and it changes with the content | Bound the worst case: put the text on a solid or heavily tinted plate, or apply a mandatory tint layer at composite time | | **Visual states** - pointer-over, pressed, selected, in error, inactive, focused | The palette usually records one resting pair per component | Enumerate surfaces multiplied by states and measure each combination | | **Layers and translucency** - overlays, scrims, shadows, sheets | A translucent layer changes the effective background under everything beneath it | Measure the composited color, not the color of the layer you authored | A fourth, quieter one: **rendering context**. A second theme, a denser layout, a locale whose script needs a different font, or a screenshot captured on one device under one setting all move the number without anyone editing a color. ## Text over imagery is a design problem, not a measurement problem This is worth separating out, because it is the case teams try hardest to solve with more measuring. If caption text sits over a photograph, the pair is different at every glyph and different again for the next photograph. Measuring one sample asset tells you about that asset. You can sample the darkest region, but the next upload will not honour your sample, and asking content authors to check contrast on every image they add is a process that fails quietly within a month. The durable answers all remove the variability rather than measure it: 1. **A solid plate.** Put the text on an opaque band or card. The pair becomes fixed and checkable, once, forever. 2. **A mandatory tint applied at composite time.** Every image gets a darkening or lightening layer as part of rendering, so the worst possible backdrop is bounded by construction rather than by review. 3. **Move the text off the image.** Frequently the cheapest option, and frequently the one nobody proposes because the mockup had the text on the image. A soft shadow behind the text is the popular fourth option and it is the weakest: it helps perceptually, it is hard to reason about as a measured pair, and it degrades exactly where the backdrop is busiest. ## A worked case A hospital patient check-in app came to review with a redesign already in build, a 12-person delivery team and 43 screens in scope. The palette sheet was genuinely good: 26 approved pairs, none below 4.71:1, all documented. The team's position was that contrast was finished. Three findings came out of looking at rendered screens instead: - The department queue screen laid appointment times over a photograph of the department, chosen per site. On one site's image the worst pair measured about 2.3:1. The palette had never been wrong; the photograph was simply not in it. - Helper text under three form fields used a muted color that passed against the card surface it was designed on, and failed on the tinted surface those cards sat on inside a modal sheet. Same two palette entries, different composite. - The inactive state of a confirm control was well below the threshold. That one is *exempt* under the minimum-contrast criterion, because text in an inactive control is incidental - and it was still the only place the appointment reference number was readable, so the exemption was a signal to redesign rather than permission to ship. The last finding is the one worth carrying into an interview. **Exempt means unmeasured, not acceptable.** A criterion carving something out is a statement about what is required, not about what is usable. ## What senior judgement looks like here - Treat the **rendered screen** as the artefact under test, not the swatch list. - Enumerate pairs as **surfaces multiplied by states**, once per component, and record the enumeration rather than the individual numbers. - Report the **worst** pair a case can produce, never the average and never a representative sample. - Where a backdrop is variable, **change the design so the pair is fixed**, because a bounded worst case survives contact with real content and a measured sample does not. - Keep a **manual pass** for what a static measurement cannot reach: text on imagery, states that need an interaction to enter, and anything that only exists after composition. None of this makes the palette useless. A palette that passes is a real and necessary floor, and it removes a large class of defect cheaply. It just answers a narrower question than the one people think they asked.

  • What is the durable fix for body text over a photograph that changes per record?
    Stop depending on the image. Put the text on a solid or near-solid plate, or apply a mandatory tint layer to every image at composite time so the worst possible backdrop is bounded by construction. Measuring one sample asset only tells you about that asset, and asking content authors to check every upload is a process that quietly stops happening. A text shadow helps perceptually but is hard to reason about as a measured pair.
  • Text in an inactive control is exempt from the minimum-contrast criterion. Does that make faint inactive text fine?
    No. The exemption says the pair carries no contrast requirement, so it is not a conformance failure - but if the inactive control is the only place a value is readable, the user still cannot read it. Exempt means unmeasured, not good. The right response to landing in an exemption is usually to ask why important content is sitting in an unmeasured place at all.
  • How would you stop this regressing across a 12-person team without adding review load?
    Make the checked artefact the rendered screen rather than the swatch list, enumerate surfaces multiplied by states once per component, and record that enumeration alongside the component so a new state has an obvious slot. Then remove whole classes of case by design - a plate behind text on imagery, a fixed tint on overlays - so the number of pairs anyone has to think about stays small as the product grows.

Checking a palette is like weighing the ingredients and declaring the cake baked. The measurement that counts is taken on what actually came out of the oven.

saying these in an interview costs you the question

  • Declares the product accessible because the palette passed
  • Measures text over imagery against a single sample asset
  • Forgets that translucency changes the effective background
  • Checks the resting state and no other visual state
  • Treats a screenshot under one theme as the whole answer
  • Reports an average across pairs instead of the worst one