왜 LLM 채팅의 접근성이 중요한가

Claude, ChatGPT, Copilot, Gemini 같은 풀스크린 LLM 채팅 경험이 웹 전반으로 확산되고 있습니다. 그런데 대부분의 팀은 '화면에 잘 보이는가'만 신경 쓰죠. 스크린 리더 사용자 입장에서는 이야기가 완전히 달라집니다.

핵심은 사회적 모델(Social Model of Disability) 입니다. 장애는 개인의 결함이 아니라, 환경이 만들어내는 배제라는 관점이죠. 계단 대신 경사로를 놓듯, 디지털 환경도 설계 단계에서 배제를 제거해야 합니다. LLM 채팅의 주요 행위는 이미 명확합니다.

  • 텍스트를 입력하고 전송하기
  • 응답을 읽고 후속 행동 취하기

문제는 이 두 가지를 '어떻게 지원하느냐'에 있습니다. 시각적 편향(Visual Bias)에 젖어 있으면, 화면에만 반응하는 UI를 만들게 됩니다. 스크린 리더 사용자는 LLM 응답이 새로 나타나도 포커스가 입력창에 머물러 있어 새 콘텐츠가 생겼다는 사실 자체를 모릅니다. 이 글은 그 간극을 메우는 실무 패턴을 다룹니다.

참고로 이 글은 Smashing Magazine의 근거자료를 바탕으로, 국내 실무 환경에 맞게 재구성한 것입니다.

LLM chat interface with screen reader live region announcements for accessibility Software Concept Art

핵심 구현: 라이브 리전(Live Region) 공지

가장 먼저 할 일은 전용 라이브 리전 영역을 DOM 끝에 두고, LLM 응답이 완료되는 시점에 공지를 트리거하는 것입니다. 각 메시지에 aria-live를 붙이는 흔한 실수는 하지 마세요. 불안정하고 디버깅이 지옥입니다.

<!-- DOM 최하단에 두는 전용 라이브 리전 -->
<div id="sr-announcer" aria-live="polite" aria-atomic="true" class="sr-only"></div>
// LLM 응답 스트리밍이 '완료'된 시점에만 공지
const announcer = document.getElementById('sr-announcer');

function announceMessage(text) {
  // 스트리밍 중계는 금지. 완료된 텍스트만 통째로 전달
  announcer.textContent = text;
}

// 응답 완료 콜백 예시
async function onLLMResponseComplete(fullText) {
  announceMessage(fullText);
}

로딩 상태도 반드시 공지

응답이 오래 걸릴 때 시각적으로만 로딩 스피너를 돌리면, 스크린 리더 사용자에게는 앱이 멈춘 것처럼 보입니다. 프롬프트 제출 후 5초 뒤에 'Loading' 공지를 트리거하고, 응답이 완료될 때까지 5초 간격으로 반복하는 패턴이 실무에서 검증된 방식입니다.

let loadingTimer = null;

function startLoadingAnnouncements() {
  loadingTimer = setInterval(() => {
    announcer.textContent = '응답을 생성하고 있습니다. 잠시만 기다려 주세요.';
  }, 5000);
  // 최초 공지는 5초 후
  setTimeout(() => {
    announcer.textContent = '응답을 생성하고 있습니다. 잠시만 기다려 주세요.';
  }, 5000);
}

function stopLoadingAnnouncements(finalText) {
  clearInterval(loadingTimer);
  // 완료 즉시 공지 (5초 주기 기다리지 않음)
  announceMessage(finalText);
}

시맨틱 헤딩으로 메시지 구분

스크린 리더 사용자는 헤딩으로 화면을 훑습니다. 각 메시지 앞에 시각적으로 숨긴 헤딩을 넣어 '누가 말했는지'를 명확히 하세요.

<article>
  <h2 class="sr-only" aria-label="Cody said" tabindex="-1">Cody said:</h2>
  <p>Utility CSS는 전역 스타일을 희생하는 대신 컴포넌트 스타일을 더 명시적으로 만듭니다...</p>
</article>

aria-label은 헤딩에 포커스가 갈 때 WCAG의 Name, Role, Value 조건을 만족시키기 위한 보험입니다. tabindex="-1"은 F6 내비게이션에서 포커스를 받을 수 있게 하는 장치죠.

Developer implementing ARIA live regions and landmarks in web chat application Programming Illustration

실무 주의사항과 심화 팁

1. 랜드마크는 '적당히'만

nav, main, form, aside로 큰 영역을 감싸는 것은 좋습니다. 하지만 개별 메시지를 section으로 감싸는 것은 금물입니다. 랜드마크 목록이 오염되어 스크린 리더 사용자의 탐색이 오히려 고통스러워집니다. 긴 세션일수록 치명적이죠.

2. 스킵 링크와 복합 위젯(Composite Widget)

  • 스킵 링크: main 콘텐츠, 프롬프트 입력창, 프로필/설정 영역으로 바로 점프할 수 있게 하세요.
  • 복합 위젯: 대화 세션 목록은 Tab 한 번으로 전체를 통과하고, 내부는 화살표 키로 이동하게 만드세요. Tab 50번 vs Tab 1번의 차이는 운동 제어에 어려움이 있는 사용자에게 결정적입니다. Home/End와 타입어헤드까지 지원하면 금상첨화입니다.

3. F6 내비게이션 지원

Windows 스크린 리더 사용자에게 익숙한 F6 패턴을 재현하세요. 웹에서는 Ctrl+F6/Ctrl+Shift+F6, 네이티브 래퍼(Electron/Tauri)에서는 F6/Shift+F6입니다. 각 랜드마크에 id와 tabindex="-1"을 부여하고 이벤트 리스너로 순환 포커스를 구현합니다. 입력창으로 갈 때는 form이 아니라 input에 직접 포커스를 주고, 마지막 메시지로 갈 때는 시각적 숨김 헤딩에 포커스를 주면 키보드만으로 응답 검토-재입력 사이클을 빠르게 돌 수 있습니다.

4. 특수 콘텐츠 공지 전략

라이브 리전은 순수 텍스트라서 표나 코드 블록의 시맨틱이 사라집니다. 2,376줄 코드를 한 글자씩 듣는 사람은 없습니다.

  • 표: "성능 감사 표, 4열 36행, 심각도별 분류"처럼 요약 공지
  • 코드 블록: "settings.json, 738줄"처럼 파일명/줄 수만 공지

실제 메시지 본문에는 시맨틱을 제대로 적용해 두어, 사용자가 나중에 돌아와 정독할 수 있게 하세요. 라이브 리전은 '미리보기'입니다.

5. 사용자 선호 설정

  • 공지 세분화: 중간 추론/도구 호출 같은 부수 액션 공지를 끌 수 있게
  • 애니메이션 끄기: prefers-reduced-motion을 기본값으로 존중
  • 사운드 끄기: 네이티브 알림, 배지, 이메일, 인앱 배너 등 대안 제공
  • 단축키 재바인딩: 다른 앱과의 충돌, 다국어 키보드 레이아웃 문제 해결

6. 확대/줌 검증

브라우저 폰트 크기를 키웠을 때 콘텐츠가 잘리거나 가로 스크롤이 생기지 않는지 반드시 확인하세요. LLM 채팅 UI는 정보량 때문에 작은 폰트를 쓰는 경향이 있어 특히 취약합니다.

아직 ariaNotify()가 매력적으로 보일 수 있지만, 스크린 리더 사용자의 업그레이드 회피 성향과 폴리필 지원 범위를 고려하면 당분간은 검증된 라이브 리전 패턴을 유지하는 편이 안전합니다.

Keyboard navigation with F6 shortcuts in accessible LLM chat experience IT Technology Image

결론: 접근성은 '될까요?'가 아니라 '얼마나 잘 되게 할까요?'의 문제

LLM 채팅 UI는 특별한 마법이 아닙니다. 웹 기술로 만든 인터랙티브 경험이고, 다른 웹 콘텐츠와 동일한 접근성 기준이 적용됩니다. 다만 시각적 편향 때문에 놓치기 쉬운 지점이 많을 뿐이죠.

실무 적용 순서를 정리하면 다음과 같습니다.

  1. 전용 라이브 리전 + 완료 시점 공지 + 5초 로딩 공지
  2. 시각적 숨김 헤딩으로 메시지 소유자 명시
  3. 랜드마크는 큰 영역에만, 메시지는 article로
  4. 스킵 링크 + 대화 목록 복합 위젯 + F6 내비게이션
  5. 표/코드는 요약 공지, 본문에는 시맨틱 유지
  6. 애니메이션/사운드/단축키 선호 설정 제공

마지막으로 강조하고 싶은 것은 당사자성입니다. 장애를 가진 사용자를 '조언의 대상'이 아니라 '자기 경험의 전문가'로 대우하세요. 포괄적 사용자 리서치 없이는 '규정 준수는 했지만 쓸 수 없는' 결과물이 나오기 쉽습니다.

함께 보면 좋은 글

국내 SI 환경에서는 특히 레거시 디자인 시스템과의 충돌을 주의하세요. 기존 컴포넌트가 aria-live를 남발하고 있다면, 이번 기회에 전용 리전 패턴으로 통합 리팩터링할 가치가 충분합니다.

본 콘텐츠는 신뢰할 수 있는 출처를 바탕으로 AI 도구를 활용하여 초안이 작성되었으며, 편집자의 검토를 거쳐 발행되었습니다. 전문가의 조언을 대체하지 않습니다.