Ray Book
웹 접근성

색상, 대비, 모션

색상만으로 정보를 전달하고 있지 않은가? 대비 비율, 색맹 고려, prefers-reduced-motion을 시각화합니다

accessibilitycontrastcolor-blindmotionwcag

색상만으로 정보를 전달하고 있지 않은가?

이전 글에서 스크린 리더와 키보드 내비게이션을 다뤘습니다. 하지만 접근성은 시각 장애에만 국한되지 않습니다. 저시력 , 색맹 , 전정 장애 등 시각적 요소와 관련된 접근성 문제도 중요합니다.

이번 글에서는 세 가지 질문을 던집니다.

  1. 텍스트를 읽을 수 있는가?, 대비 비율
  2. 색을 구분하지 못해도 정보를 얻을 수 있는가?, 색맹 고려
  3. 움직이는 요소가 불편하지 않은가?, 모션 감소

색 대비 기준: WCAG AA와 AAA

WCAG (Web Content Accessibility Guidelines) 는 텍스트와 배경 사이의 대비 비율 (contrast ratio) 을 구체적인 숫자로 규정합니다.

수준일반 텍스트큰 텍스트 (24px+ 또는 18.66px 볼드)UI 컴포넌트
AA4.5 : 13 : 13 : 1
AAA7 : 14.5 : 1-

대비 비율의 범위는 1:1 (동일 색상) 에서 21:1 (흰색 위 검정) 까지입니다. 비율이 높을수록 읽기 쉽습니다.

대비 비율 = (밝은 색의 상대 휘도 + 0.05) / (어두운 색의 상대 휘도 + 0.05)

예) 흰색(#fff)과 회색(#767676)
  L_white = 1.0, L_gray = 0.176
  비율 = (1.0 + 0.05) / (0.176 + 0.05) = 4.54:1 → AA 통과

아래 시각화에서 각 대비 수준이 실제로 어떻게 보이는지 확인하세요. 마지막 단계에서는 색상만으로 정보를 전달할 때의 문제도 함께 보여줍니다.

FAIL낮은 대비 — WCAG 실패
이 텍스트는 읽기 어렵습니다
흰 배경 + 밝은 회색 텍스트2.3:1
배경과 구분이 안 됩니다
밝은 회색 배경 + 회색 텍스트1.6:1
대비 비율이 4.5:1 미만이면 저시력 사용자는 텍스트를 읽을 수 없습니다. 화면 밝기를 낮추거나 햇빛 아래서 보면 일반 사용자도 힘들어집니다.

색맹 고려

전 세계 남성의 약 8% , **여성의 약 0.5%**가 색각 이상을 가지고 있습니다. 가장 흔한 유형은 적록 색맹으로, 빨간색과 초록색을 구분하기 어렵습니다.

유형영향비율 (남성)
제1색맹 (Protanopia)빨간색 인식 불가~1%
제2색맹 (Deuteranopia)초록색 인식 불가~1%
제1색약 (Protanomaly)빨간색 인식 감소~1%
제2색약 (Deuteranomaly)초록색 인식 감소~5%

실무에서의 원칙:

  • 색상에만 의존하지 말 것 , 아이콘, 패턴, 텍스트를 함께 사용
  • 성공/실패를 빨강/초록으로만 표시하지 말 것, ✓/✕ 아이콘 병행
  • 그래프에서 색 구분이 어려우면 패턴 (빗금, 점선) 을 추가
  • 링크를 색상만으로 구분하지 말 것, 밑줄을 함께 사용
/* ❌ 색상만으로 링크 구분 */
a { color: blue; text-decoration: none; }

/* ✅ 밑줄 + 색상으로 구분 */
a { color: blue; text-decoration: underline; }

대비 검사 도구

대비 비율을 직접 계산할 필요는 없습니다. 도구를 사용하세요.

Chrome DevTools , Elements 패널에서 색상 값을 클릭하면 대비 비율이 표시됩니다. AA/AAA 통과 여부도 함께 보여줍니다.

WebAIM Contrast Checker , 전경색과 배경색을 입력하면 즉시 대비 비율을 계산합니다. 가장 많이 사용되는 온라인 도구입니다.

Lighthouse , Chrome DevTools의 Lighthouse 탭에서 접근성 감사를 실행하면 대비 문제를 자동으로 찾아줍니다.

// 프로그래밍 방식으로 대비 비율 계산
function relativeLuminance(hex) {
  const [r, g, b] = [1, 3, 5].map((i) => {
    const c = parseInt(hex.slice(i, i + 2), 16) / 255;
    return c <= 0.04045
      ? c / 12.92
      : Math.pow((c + 0.055) / 1.055, 2.4);
  });
  return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}

function contrastRatio(hex1, hex2) {
  const l1 = relativeLuminance(hex1);
  const l2 = relativeLuminance(hex2);
  const lighter = Math.max(l1, l2);
  const darker = Math.min(l1, l2);
  return (lighter + 0.05) / (darker + 0.05);
}

contrastRatio("#ffffff", "#767676"); // 4.54 → AA 통과

모션 감소: prefers-reduced-motion

일부 사용자는 화면의 움직임으로 인해 어지러움, 메스꺼움, 두통을 겪습니다. 전정 장애 (vestibular disorders) 를 가진 사용자가 대표적입니다.

OS에서 "모션 줄이기" 설정을 켜면 CSS 미디어 쿼리 prefers-reduced-motion으로 감지할 수 있습니다.

/* 기본: 애니메이션 적용 */
.card {
  transition: transform 0.3s ease;
}

.card:hover {
  transform: scale(1.05);
}

/* 모션 줄이기 설정 시: 애니메이션 제거 또는 대체 */
@media (prefers-reduced-motion: reduce) {
  .card {
    transition: none;
  }

  .card:hover {
    transform: none;
    /* 대신 opacity 변경 같은 부드러운 대안 사용 */
    opacity: 0.9;
  }
}

JavaScript에서도 확인할 수 있습니다.

// JS에서 모션 감소 설정 감지
const motionQuery = window.matchMedia(
  "(prefers-reduced-motion: reduce)"
);

if (motionQuery.matches) {
  // 애니메이션을 비활성화하거나 간소화
  document.documentElement.classList.add("reduce-motion");
}

// 설정 변경 감지
motionQuery.addEventListener("change", (e) => {
  if (e.matches) {
    // 모션 감소 활성화됨
    cancelAllAnimations();
  }
});

핵심 원칙:

  • 모든 애니메이션을 없애는 것이 아니라, 과도한 모션 을 줄이는 것
  • 페이드인/페이드아웃은 유지해도 됨, 회전, 확대/축소, 슬라이드는 줄이거나 제거
  • 5초 이상 지속되는 애니메이션은 정지 버튼 제공
  • 자동 재생 캐러셀은 prefers-reduced-motion: reduce에서 정지

다크 모드와 접근성

다크 모드를 지원한다고 접근성이 자동으로 좋아지는 것은 아닙니다. 다크 모드에서도 대비 비율을 유지 해야 합니다.

:root {
  --text: #1a1a1a;        /* 라이트: 거의 검정 */
  --bg: #ffffff;           /* 라이트: 흰색 */
  /* 대비 비율: 약 17.4:1 ✅ */
}

@media (prefers-color-scheme: dark) {
  :root {
    --text: #e5e5e5;       /* 다크: 밝은 회색 */
    --bg: #171717;         /* 다크: 거의 검정 */
    /* 대비 비율: 약 15.4:1 ✅ */
  }
}

/* ❌ 다크 모드에서 흔한 실수 */
@media (prefers-color-scheme: dark) {
  :root {
    --text: #888888;       /* 너무 어두운 텍스트 */
    --bg: #333333;         /* 너무 밝은 배경 */
    /* 대비 비율: 약 2.4:1 ❌ */
  }
}

텍스트 크기와 확대

WCAG 1.4.4는 텍스트를 200%까지 확대해도 콘텐츠가 유실되거나 기능이 깨지지 않아야 한다 고 규정합니다.

  • px 대신 rem을 사용하면 사용자가 브라우저 기본 글꼴 크기를 변경할 때 함께 조정됨
  • 본문 텍스트는 최소 16px (1rem) 을 권장
  • max-widthch 단위로 설정하면 줄당 문자 수를 제한해 가독성 향상
/* ❌ 고정 px, 사용자 설정 무시 */
body { font-size: 14px; }

/* ✅ rem, 사용자 브라우저 설정에 반응 */
body { font-size: 1rem; } /* 기본 16px */
h1   { font-size: 2rem; } /* 32px */

/* 줄 길이 제한으로 가독성 향상 */
article { max-width: 70ch; }

시각 접근성 체크리스트

항목기준
텍스트 대비일반 4.5:1 이상, 큰 텍스트 (24px+) 3:1 이상 (AA)
UI 컴포넌트 대비3:1 이상
색상만으로 정보 전달❌ 아이콘/텍스트/패턴 병행
링크 구분색상 + 밑줄
prefers-reduced-motion과도한 모션 제거 또는 대체
다크 모드 대비라이트 모드와 동일한 기준 유지
텍스트 크기rem 사용, 200% 확대 대응
줄 길이70~80ch 이내 권장

다음 글: 폼과 에러 처리

시각적 접근성을 확보했다면, 이제 사용자가 실제로 상호작용 하는 폼을 살펴볼 차례입니다. 다음 글에서는 label 연결, 에러 메시지 전달, aria-live를 다룹니다.