색상 팔레트에 숨어 있는 명암비 버그

작성자

카테고리:

← 피드로
DEV Community · zhihu wu · 2026-09-11 개발(SW)

zhihu wu

Most accessibility bugs I’ve shipped were not missing alt text or broken keyboard order. They were colors.

A brand blue that looked fine in Figma, dropped onto a button, with white label text that nobody could read on a laptop at 40% brightness.

Contrast is a number, not a vibe

WCAG 2.1 defines contrast as a ratio between the relative luminance of two colors:

L = 0.2126 * R + 0.7152 * G + 0.0722 * B
contrast = (L1 + 0.05) / (L2 + 0.05)

Enter fullscreen mode Exit fullscreen mode

R, G and B have to be linearized first (undo the sRGB gamma curve), which is why you cannot just average RGB values and call it done. The thresholds are 4.5:1 for normal text, 3:1 for large text (18px+, or 14px bold) and UI component boundaries.

Three traps that keep sailing through design review:

  1. Gray body text. #999999 on white is about 2.8:1 and fails. #767676 is the lightest gray that still passes on white.
  2. Colored text on a colored background. Dark blue on medium blue can measure 1.6:1 even though both colors clearly “look different.”
  3. Placeholder text. Usually the same light gray as trap 1, and it is text the user has to read to fill in the form.

HSL lightness lies to you

hsl(60, 100%, 50%) (yellow) and hsl(240, 100%, 50%) (blue) share an identical lightness value and have wildly different perceived brightness. That is because HSL lightness is a geometric property of the RGB cube, not a measure of how much light actually reaches your eye.

When you need a fast estimate, use perceived brightness:

Y = (0.299 * R + 0.587 * G + 0.114 * B) / 255

Enter fullscreen mode Exit fullscreen mode

Above roughly 0.6 the background is light, so use dark text. Below 0.4, use white. The 0.4-0.6 band is where both options look muddy, and that is your signal to change the background instead of fighting it.

A 30-second workflow

Pick the background, read off the RGB values, and check the ratio before you hand off to QA. I use CodeToolbox’s color picker (https://codetoolbox.pro/tools/color-picker.html) because it shows HEX, RGB and HSL side by side and updates live as you drag a slider, so you can nudge a color until it crosses the threshold without converting anything by hand. It runs entirely in your browser, no uploads, no signup.

Contrast is one of the few accessibility requirements you can satisfy completely and deterministically in a single commit. Might as well.

원문에서 계속 ↗