명암 대비

Contrast ratio

글자와 배경의 밝기 차이를 1:1~21:1 숫자로 나타낸 WCAG 지표. 4.5:1 이상이면 일반 텍스트 AA 기준을 통과합니다.

다른 이름: WCAG contrast대비율
···
html
<div class="wrap">
  <div class="patch" id="patch"><span id="patchText">Aa</span></div>
  <div class="stats">
    <div class="ratio" id="ratio">4.50:1</div>
    <div class="badges">
      <span class="badge" id="bAA">AA</span>
      <span class="badge" id="bAAlg">AA Large</span>
      <span class="badge" id="bAAA">AAA</span>
    </div>
  </div>
</div>
css
.wrap{width:min(440px,92%);display:grid;gap:14px;justify-items:center}
.patch{width:100%;height:clamp(64px,18vmin,110px);border-radius:14px;display:grid;place-items:center;border:1px solid var(--line);transition:background .6s;cursor:pointer}
#patchText{font:800 clamp(20px,6.4vmin,36px)/1 system-ui}
.stats{display:grid;gap:8px;justify-items:center}
.ratio{font:800 clamp(16px,4.4vmin,22px)/1 ui-monospace,monospace;color:var(--fg)}
.badges{display:flex;gap:8px}
.badge{padding:4px 10px;border-radius:999px;font:700 clamp(9px,2.4vmin,11px)/1 ui-monospace,monospace;border:1px solid var(--line);opacity:.35;color:var(--muted)}
.badge.pass{opacity:1;background:var(--accent-3);color:#04241c;border-color:transparent}
js
const PAIRS = [
  ['#1b1b1f', '#ffffff'],
  ['#ffffff', '#2563eb'],
  ['#0f172a', '#facc15'],
  ['#6b7280', '#f3f4f6'],
  ['#f43f5e', '#111827'],
  ['#111827', '#22c55e'],
];
let idx = 0;
function hexToRgb(hex) { hex = hex.replace('#', ''); return [0, 2, 4].map(i => parseInt(hex.substr(i, 2), 16)); }
function channel(v) { v /= 255; return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); }
function luminance(hex) { const c = hexToRgb(hex).map(channel); return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2]; }
function ratio(a, b) { const la = luminance(a) + 0.05, lb = luminance(b) + 0.05; return la > lb ? la / lb : lb / la; }

const patch = document.getElementById('patch'), patchText = document.getElementById('patchText');
const ratioEl = document.getElementById('ratio'), bAA = document.getElementById('bAA'), bAAlg = document.getElementById('bAAlg'), bAAA = document.getElementById('bAAA');

function render() {
  const [fg, bg] = PAIRS[idx];
  patch.style.background = bg;
  patchText.style.color = fg;
  const r = ratio(fg, bg);
  ratioEl.textContent = r.toFixed(2) + ':1';
  bAA.classList.toggle('pass', r >= 4.5);
  bAAlg.classList.toggle('pass', r >= 3);
  bAAA.classList.toggle('pass', r >= 7);
}
render();
patch.addEventListener('click', () => { idx = (idx + 1) % PAIRS.length; render(); });
setInterval(() => { idx = (idx + 1) % PAIRS.length; render(); }, 2400);

사람 눈은 "밝기"를 선형으로 느끼지 않아서, 단순히 RGB 평균을 비교하면 안 됩니다. WCAG는 sRGB 채널을 감마 보정으로 선형화한 뒤 0.2126R + 0.7152G + 0.0722B로 상대 휘도(luminance)를 구하고, 밝은 색과 어두운 색의 휘도에 각각 0.05를 더해 (L1+0.05)/(L2+0.05)로 대비율을 계산합니다.

기준은 세 단계입니다 — 일반 텍스트 AA 4.5:1, 큰 텍스트(18pt 이상 또는 14pt 굵게) AA 3:1, 일반 텍스트 AAA 7:1. 순수 검정 위 순수 흰색은 21:1로 이론적 최댓값입니다.

디자인 툴의 "대비 체크" 플러그인도 결국 이 공식을 그대로 씁니다 — 색을 고를 때 감으로 판단하지 말고 계산기를 돌려보는 습관이 접근성 사고를 가장 많이 줄입니다.

언제 쓰나

텍스트, 아이콘, 폼 테두리 등 의미를 전달하는 모든 색 조합에 배포 전 반드시 확인하세요.