아티클

접근성 좋은 정렬 가능 데이터 테이블 만들기

2021-07-19 10:43:21

안녕하세요. 안녕하세요, 엔비전스 입니다.

표(table)은 매우 오래전부터 써 오던 문서 구조 형태입니다. 아날로그 시대에는 복잡한 표를 그리기 쉽지 않았으며, 다루는 데이터의 양 또한 지금과는 아주 달랐습니다. 지금은 컴퓨터를 쓰게 되면서, Excel과 같은 표 구조를 기본으로 하는 문서 프로그램부터 각종 데이터베이스 프로그램, 심지어 웹에서조차도 이 표가 사용되고 있으며, 만들기 간편해짐에 따라 더 많은 데이터, 복잡성을 뛰게 되었습니다.

자연스럽게 복잡하고 많은 데이터 중, 원하는 기능을 찾고자 하는 욕구가 생겼고, 자연스럽게 검색, 정렬하는 기능도 개발되었습니다.

마찬가지로, HTML이 발전함에 따라, 더 복잡한 데이터를 다루는 표들이 많아졌으며, 단순한 표를 넘어서 데이터를 다루는 Excel과 같은 프로그램을 웹 기반의 애플리케이션으로 만드는 사례 또한 늘어났습니다. 대표적으로 Google의 SpreadSheet를 예로 들 수 있지요.

이번 아티클의 주제는 테이블의 데이터 정렬로, 스크린 리더 사용자에게 테이블의 정렬 상태 정보를 어떻게 전달하는가를 다루고자 합니다.

aria-sort 사용하기

정렬이 가능한 테이블은 당연히 사용자에게 어떤 행이 정렬되었는지 알 수 있게 헤더 셀에 상태 정보를 전달해야 합니다.

WAI-ARIA는 이러한 표를 위한 정렬 상태를 알리는 aria-sort 속성이 있습니다.

이 속성은 다음과 같은 요소에 사용할 수 있습니다.

  • columnheader (열 헤더)
  • rowheader (행 헤더)

열 헤더와 행 헤더는 테이블이나 그리드 첫 행과 첫 열에 주로 쓰이는 제목 셀을 얘기합니다.

이 셀에 aria-sort를 사용하여, 스크린 리더 사용자에게 이 셀의 축을 기준으로 표의 데이터 순서가 정렬되었음을 알릴 수 있습니다. 그럼, aria-sort는 어떻게 사용하는지도 알아볼까요?

aria-sort는 총 4개의 값이 있습니다. 4개의 값은 다음과 같습니다.

  • ascending : 오름차 순 정렬
  • descending : 내림차 순 정렬
  • other : 기타 기준 정렬
  • none : 정렬 안 함(th 셀, header role 태그의 기본값)

위에서 설명했듯, rowheader, columnheader에 해당하는 태그에 모두 사용이 가능합니다. 즉, 일반적인 table > tr > th 마크업에서, th는 rowheader 또는 columnheader를 상속받는 태그이기 때문에 이 aria-sort가 적용된다는 얘기이기도 합니다.

이를 사용하면, 테이블 셀 중, 해당 제목 셀에 접근했을 때, 행 헤더를 기준으로 정렬했을 때를 예를 들어, 테이블 열이 어떤 흐름으로 정렬이 되었는지 스크린 리더로 들을 수 있게 됩니다.

table과 aria-sort 조합의 한계

우선, aria-sort는 테이블의 헤더 셀에 적용 가능한 상태 정보이기 때문에, 커스텀 그리드와 같이 헤더 셀을 직접 누르는 형태이면 문제가 없으나 일반적인 테이블 셀은 조작 가능한 요소가 아니기 때문에 하위에 버튼을 둬야 한다는 단점이 있습니다.

이로 인해 생기는 또 다른 문제로는 토글 버튼으로 구현했을 때, aria-sort는 헤더 셀에 상태 정보를 주는 것이지, 버튼에 상태 정보를 주는 것이 아니기 때문에 버튼을 아무리 눌러도 상태 정보를 들을 수 없는 문제점이 있습니다.

토글형 정렬 헤더: 그럼 어떻게 눌렀을 때 바로 상태 정보 변경을 알릴 수 있을까?

사용자에게 전달해야 하는 상태 정보가 많거나, 적절한 것이 없을 때, 주로 사용하는 방법이 몇 가지 있습니다.

(1) 라이브 영역 (Live Region)

접근성 기능 구현에 익숙한 분이라면, 이 섹션을 읽기 전부터 예상하셨을 방법입니다.

스크린 리더 사용자를 위한 숨김 텍스트나 보이는 텍스트 영역을 두고, 그 영역을 라이브 영역으로 두어 상태 정보를 주는 방법입니다.

그나마 호환성 부분에서 가장 자유로운 방법으로, 널리 쓰이는 대부분의 스크린 리더가 라이브 영역을 지원합니다.

라이브 영역을 만드는 방법은 aria-live 속성에 polite나 assertive 값을 주는 방법과 role=“alert”이나 role=“status”를 쓰는 방법이 있습니다.

이 중에 role=“alert”만 약간 다른 특성을 보여주는데, alert 유형은 다른 라이브 영역처럼 자신 안에서 발생한 변경사항을 알리기도 하지만, 자기 자신이 HTML 문서에 표시될 때, 자기 자신을 스크린 리더 사용자에게 알리기도 합니다.

나머지 라이브 영역은 자기 자신이 아닌, 하위에 있는 요소가 변경, 삭제, 추가되었을 때, 변경된 값만을 알립니다.

(2) aria-label, labelledby

헤더 셀 아래의 버튼을 상태 정보를 포함한 레이블 텍스트로 변경하는 방법입니다.

aria-label, labelledby의 특징은 해당 속성에 지정된 텍스트로 요소의 대체 텍스트를 덮어씌운다는 점입니다.

즉, button 안에 “이름”이라는 텍스트가 있더래도, aria-label에 “오름차순으로 정렬됨”이 쓰여있다면, 버튼 안에 있는 text 노드는 무시됩니다.

따라서, 아래 예와 같이 반드시 스크립트로 처리할 때, 버튼 안에 있는 텍스트도 같이 레이블에 넣어주어야 합니다.

headerButton.setAttribute(“aria-label”,`${headerButton.textContent}, 오름차순 정렬됨.`);

일반적으로 클릭이나 기타 키보드 조작으로 aria-label이 변경되면 스크린 리더 사용자에게 변경된 레이블 정보를 알리므로, 널리 쓰이는 방법이지만, Android Talkback에서는 이를 따르지 않습니다.

눌렀을 때 레이블이 바뀌어도 읽지 않기에 호환성 문제가 생기는 것이지요.

다만, aria-sort와 같이 적용했을 때, 중복된 상태 정보를 주게 되는 문제가 있습니다.

(3) aria-describedby

바로 이전에 설명한 aria-label과 비슷한 방법으로, 접근할 수 없는 display:none 처리된 텍스트 태그에 id를 부여하고, 해당 텍스트를 버튼과 aria-describedby로 묶으면, 해당 태그에서 텍스트를 가져와 타이틀 속성처럼 읽어주게 됩니다.

일반적으로 aria-describedby도 aria-label처럼, 눌렀을 때 내용이 변경되면 스크린 리더가 내용을 바로 알리게 됩니다.

단점은 따로 참조할 태그가 필요하므로 마크업이 필요하다는 점이며, aria-label처럼 현재 Android Talkback과 호환성 이슈가 있습니다.

Android 호환성만 해결된다면 caption에 눈으로는 볼 수 없는 텍스트 형태로 span을 두고 aria-describedby로 상태 정보를 준다면, 테이블 단위 탐색 시에도 어떤 순으로 정렬되어 있는지 알 수 있는 효율적인 형태가 되기도 합니다.

aria-label과 마찬가지로 aria-sort와 같이 적용했을 때, 중복된 상태 정보를 주게 되는 문제가 있어 둘 중 하나만 적용해야 합니다.

특정한 방법을 최고의 방법이라고 딱히 말할 수는 없습니다. 하지만, 웹은 특정 기기에서만 사용하지 않습니다. 되도록 호환성이 좋은 방향으로 개발되는 것이 좋겠지요.

상태 정보 문제를 해결할 다른 대안을 찾자면 토글 버튼으로 구현하지 않고, 각 셀에 텍스트와 함께 콤보 상자나, 드롭다운 버튼을 별도로 두어 정렬하는 방식을 사용할 수 있습니다.

이를 적용한 예시

아래 프레임은 정렬 가능한 테이블에 대한 예제입니다. 행 헤더 중 하나를 선택하여 해당 행에 속한 열의 셀을 정렬할 수 있는 토글 버튼이 행 헤더마다 있습니다.

라디오 버튼처럼 한 번에 한 개의 헤더만을 활성화하여 정렬할 수 있습니다.

caption 태그에는 눈으로는 보이지 않지만, 스크린 리더 사용자에게 유효한 role=“alert” span 태그가 있으며, 버튼을 누르면 상태 정보를 이 span 태그를 통해 전달하게 됩니다.

caption 태그에 상태 정보를 넣는 이유는 테이블이 여러 개 있을 때, 테이블 단위로 접근하면 바로 정렬 정보를 들을 수 있게 하기 위함입니다.

지금까지 정렬 가능한 테이블을 스크린 리더 사용자에게 어떻게 전달하는지 알아보았습니다. 다음 시간에도 더 좋은 아티클로 찾아뵙도록 노력하겠습니다. 감사합니다.

댓글 0
댓글을 작성하려면 해주세요.