Modal.js를 활용한 모달 대화상자 접근성 개선하기
안녕하세요, 엔비전스입니다.
웹페이지 내에서 기존 레이아웃에 중첩된 형태로 모달 대화상자를 구현할 때 접근성과 관련해서 고려해야 할 사항들이 많습니다. 그중 하나는 레이어에 가려져 클릭이 불가능한 요소들은 스크린 리더 및 키보드로도 접근이 되지 않도록 해야 한다는 것입니다.
화면상에서 다른 요소에 가려진 요소들은 브라우저 입장에서는 실질적으로 사라진 것이 아니기 때문에 접근성 노드에서 해당 요소들을 강제로 숨기고 Tab, Shift + Tab 키를 눌렀을 때 대화상자 바깥으로 나가지 못하도록 여러 스크립트를 구현해야 합니다.
이러한 작업들을 좀 더 간단하게 구현할 수 있도록 본 문서에서는 improveAccessibility 내에 modalDialog() 메서드를 만들어 사용방법을 공유하도록 하겠습니다.
modalDialog()의 특징
improveAccessibility.js 내의 modalDialog() 메서드는 다음과 같은 특징이 있습니다.
- improveAccessibility.js 파일 내에서 modalDialog() 메서드를 실행하는 것만으로 접근성과 관련된 별다른 스크립트 구현 없이 모달 대화상자와 관련된 마크업만 정확하게 해 주면 관련 접근성이 자동 구현됩니다.
- js에 구현된 접근성 기능으로는 다음과 같은 것들이 있습니다.
- 대화상자가 열렸을 때 대화상자의 특정 요소로 초점 보내기.
- 대화상자가 열렸을 때 Tab이나 Shift + Tab 키 눌러도 대화상자 외부로 초점 가지 않게 하기.
- 대화상자가 열렸을 때 aria-modal=”true” 미지원 스크린 리더를 위해 대화상자가 포함된 영역 이외의 모든 영역에 aria-hidden=”true” 적용.
- ESC 키로 대화상자 레이어 닫기 가능.
- 대화상자를 닫았을 때 초점을 원래의 대화상자를 여는 버튼으로 돌리고 기존 aria-hidden=”true” 속성 제거.
기본 마크업
- improveAccessibility.js 파일을 HTML 파일에서 다음 예시와 같이 불러옵니다.
<script src="https://a11y-nvisions.github.io/js/improveAccessibility.js"></script> - 대화상자를 여는 버튼에는 aria-haspopup=”dialog” 속성과 aria-controls 속성을 추가합니다. Aria-haspopup 속성은 스크린 리더가 대화상자를 여는 버튼에 포커스 했을 때 단순히 버튼이라고 읽지 않고 대화상자 팝업 등으로 읽게 함으로써 실행하면 팝업이 열릴 것임을 예상하도록 도와줍니다.
- aria-controls는 대화상자를 여는 버튼과 대화상자 영역을 서로 연결시켜 주는 역할을 하며 대화상자 영역에 id를 지정하여 연결합니다. 예를 들어 대화상자 영역의 id가 dialogPopup이라면 대화상자를 여는 버튼에는 다음과 같이 HTML을 작성할 수 있겠습니다.
<button aria-haspopup=”dialog” aria-controls=”dialogPopup”>문의하기</button> - 대화상자 영역에는 role=”dialog”, aria-modal=”true” 속성을 줍니다. Role=”dialog”는 말 그대로 해당 영역은 대화상자 영역이라는 것을 알리는 것이고 aria-modal=”true”는 해당 대화상자 영역만 접근성 노드에 표시하겠다는 것입니다.
단 위의 두 속성은 반드시 대화상자가 표시되었을 때는 display:block, 사라졌을 때는 display:none으로 변경되는 영역에 주어야 합니다. 본 js는 대화상자와 관련된 속성들이 들어 있는 요소의 display 스타일 변경에 따라 초점을 돌려주거나 모달과 관련이 없는 부분들을 숨기는 등의 작업을 수행하기 때문입니다. 혹은 대화상자가 열리거나 닫혔을 때 aria-hidden 속성이 변경되는 곳이어도 됩니다.
대화상자가 열렸다는 가정 하에 대화상자 영역 div에는 다음 예시와 같이 HTML을 작성할 수 있겠습니다.
<div style=”display: block;” role=”dialog” aria-modal=”true” id=”dialogPopup”> - 대화상자가 열렸을 때 초점을 특정 요소로 보내주어야 한다면, 초점을 보내 주어야 하는 요소에 autoFocus 클래스를 추가합니다. 다만 기존 페이지에서 이미 접근성 초점을 대화상자 내부로 보내주고 있다면 해당 클래스는 필요하지 않습니다.
- 대화상자가 표시되었을 때 대화상자 내부 요소 중 첫 번째 포커스 되는 요소와 마지막에 포커스 되는 요소에 각각 firstTab, lastTab 클래스를 추가합니다. 그러면 마지막 요소와 첫번째 요소에서 각각 tab과 Shift + Tab 키를 눌렀을 때, 이 두 클래스를 기준으로 초점이 대화상자 내부 콘텐츠 사이에서만 순환하게 됩니다. 만약 대화상자 내부에 확인 버튼과 같이 초점을 줄 수 있는 요소가 하나뿐인 경우에는 firstTab 클래스만 추가하면 됩니다. firstTab, lastTab CSS 속성이 없으면 대화상자 내부에서 초점이 가는 모든 요소들을 가져와서 자동으로 첫 번째 탭과 마지막 탭을 지정하게 되어 firstTab, lastTab 은 필수는 아닙니다.
- 대화상자를 닫는 버튼에는 closeModal 클래스를 추가합니다. 그러면 대화상자가 열렸을 때 ESC 키를 누르면 대화상자가 닫힙니다.
- 대화상자 팝업이 위의 조건과 같이 마크업되어 있다면 modalDialog() 메서드를 실행합니다.
모달 대화상자를 구현 시 참고사항
다음은 필수는 아니지만 스크린 리더 사용자의 사용성을 조금 더 향상시킬 수 있는 참고 사항들을 기술합니다.
- 대화상자가 열렸을 때 초점을 주는 곳은 <div> 와 같은 대화상자 영역 자체보다는 버튼, 링크, 편집창과 같은 초점 가능한 요소에 주는 것이 좋습니다. 이는 영역에 주게 되면 대화상자가 열렸을 때 스크린 리더가 대화상자 영역의 전체 내용을 연속적으로 읽게 되므로 음성으로 출력되는 메시지가 간결하지 못하기 때문입니다.
- Role=”dialog” 요소에는 aria-label 혹은 aria-labelledby 속성을 지정하여 대화상자 제목을 포함시키는 것이 좋습니다. 이렇게 하면 어떤 대화상자인지를 읽어주게 됩니다.
- 알림을 목적으로 하는 대화상자인 경우에는 role=”dialog” 대신 role=”alertdialog” 속성을 사용합니다.
- 대화상자가 열렸을 때 초점을 보내지 않고 특정 내용을 처음에 읽을 수 있게 하려면 aria-describedby 속성을 사용할 수 있습니다.
지금까지 modal.js를 활용한 대화상자 접근성 개선하기에 대해 함께 살펴보았습니다. 해당 js 파일을 열면 사용방법에 대한 주석이 포함되어 있으므로 참고하시기 바랍니다.