기술 포스트

접근성은 미루면 빚이 된다


Article

프로젝트 막바지에 접근성을 몰아서 고친 적이 있다. 그때 배운 게 오래 남는다. 접근성은 미루면 이자가 붙는 빚이다. 그리고 그 빚의 대부분은 처음에 시맨틱하게만 짰어도 애초에 안 생겼을 빚이었다.

뒤늦게 고치려니 다 뜯어야 했다

기능부터 다 만들고 나서 접근성 점검을 돌렸더니 문제가 우수수 나왔다. 버튼이 <div onClick>이라 키보드 포커스가 안 잡히고, 이미지엔 alt가 없고, 색 대비는 미달이고, 모달을 열면 포커스가 뒤 배경으로 새어 나갔다. 하나씩 고치는데 문제는 이게 표면이 아니라 구조에 박혀 있다는 것이었다.

클릭 div를 접근 가능하게 만들려면 role, tabIndex, onKeyDown을 다 붙여야 한다.

// 나중에 이걸 다 붙여가며 고쳤다
<div
  role="button"
  tabIndex={0}
  onClick={handleClick}
  onKeyDown={(e) => {
    if (e.key === "Enter" || e.key === " ") {
      e.preventDefault();
      handleClick();
    }
  }}
>
  더보기
</div>

처음부터 <button>을 썼으면 이 여덟 줄이 통째로 필요 없었다. 포커스, 엔터/스페이스 키 처리, role이 전부 브라우저 기본으로 딸려온다.

// 처음부터 이렇게 짰으면 공짜였다
<button type="button" onClick={handleClick}>
  더보기
</button>

시맨틱하게 짜면 8할은 공짜다

이걸 겪고 나서 원칙이 하나 생겼다. 접근성을 별도 작업으로 미루지 말고, 마크업하는 순간에 지불한다. 그리고 그 지불의 대부분은 올바른 태그를 고르는 것만으로 끝난다.

  • 누르는 건 <button>, 이동하는 건 <a href>. div로 흉내내지 않는다.
  • 페이지 구조는 <header> <nav> <main> <article> <footer>로. 스크린리더 사용자는 이 랜드마크로 페이지를 훑는다.
  • 폼 요소엔 <label>을 연결한다. placeholder는 라벨이 아니다.
  • 제목은 <h1>부터 순서대로. 시각적 크기 때문에 레벨을 건너뛰지 않는다.
  • 이미지 alt는 마크업하는 그 자리에서 바로 쓴다. 나중에 몰아 쓰면 무슨 이미지였는지 기억이 안 난다.

이렇게만 해도 aria 속성을 손으로 붙일 일이 확 준다. aria의 첫 번째 규칙이 "가능하면 aria를 쓰지 말고 네이티브 HTML 요소를 써라"인 데는 이유가 있다. aria는 네이티브로 표현이 안 될 때 보강하는 도구지, 잘못 고른 태그를 때우는 반창고가 아니다.

퍼블리셔 출신의 강점

이 대목에서 퍼블리셔로 커리어를 시작한 게 도움이 됐다고 느낀다. 마크업을 손으로 오래 짜다 보면 어떤 콘텐츠에 어떤 태그가 맞는지가 반사적으로 나온다. 목록이면 <ul>, 표 데이터면 <table>, 정의 나열이면 <dl>. 프레임워크로 바로 넘어온 사람들이 종종 모든 걸 div로 처리하는 걸 보는데, 그게 나중에 접근성 빚으로 돌아온다.

프론트엔드로 넘어와 상태 관리와 렌더링 최적화를 배우면서도, 결국 브라우저에 나가는 건 HTML이라는 사실은 안 변한다. 화려한 컴포넌트 안쪽이 div 범벅이면 접근성도 SEO도 같이 무너진다. 시맨틱 HTML은 접근성과 SEO를 동시에 사는 가장 싼 투자다. 미루지 말고 마크업하는 순간에 지불하는 게 제일 싸게 먹힌다.

접근성은 미루면 빚이 된다 — 디코드랩(DCODELAB)