Monthly Archives: August 2010

탭을 헤딩으로 탭 내용을 헤딩에 이어지는 컨텐츠로 구성한 마크업을 위한 jQuery plugin, flowTab

WAI-ARIA의 tab, 아직 사용하긴 이르다. 라는 글을 썼었는데, 탭을 헤딩으로 탭 내용을 헤딩에 이어지는 컨텐츠로 구성한 마크업을 위한 자바스크립트 라이브러리는 찾기가 어려워 하나 만들었다. 이름하여 flowTab. (기본적으로 자연스럽게 흐르는 컨텐츠를 탭 UI로 만든다 하여 이렇게 지었다.)

마크업과 자바스크립트를 아래 코드와 같이 작성하면 된다.

<script type="text/javascript">
// <!--
$(function() {
	$('#tabs').flowTab();
	// $('#tabs').flowTab({tabSelector: '> .heading'});
});
// -->
</script>
<div id="tabs">
	<h2 class="heading">tab1</h2>
	<div>tab1 content <a href="#">link example</a></div>
	<h2 class="heading">tab2</h2>
	<div>tab2 content <a href="#">link example</a></div>
	<h2 class="heading">tab3</h2>
	<div>tab3 content <a href="#">link example</a></div>
</div>

flowTab plugin은 몇가지 옵션이 있다.

  • tabSelector: 탭을 가리키는 jQuery 선택자. (기본값: "> .heading")
  • tabEnabledClass: 활성화된 탭 요소에 추가될 class명. (기본값: "headingEnabled")
  • contentDisabledClass: 비활성화된 탭 내용 요소에 추가될 class명. (기본값: "contentDisabledClass")

예제와 다운로드

예제: jQuery flowTab plugin example

다운로드: jquery.flowTab.js

no jQuery 버전

탭 이외에 특별히 jQuery를 사용하지 않는 사이트는 no jQuery 버전이 더 가볍게 동작한다.

jQuery 버전과의 약간 옵션 차이가 있다: tabSelector 옵션 대신 tabClassName 옵션을 사용한다. 루트 요소에서 탭을 찾을 때 tabClassName에 기재된 클래스명으로 찾는다. 기본값은 "heading".

아래는 코드 예제

<script type="text/javascript">
// <!--
// onload 구현은 알아서...;;
window.onload = function() {
	new flowTab(document.getElementById('tab'));
	// new flowTab(document.getElementById('tab'), {tabClassName: 'heading'});
};
// -->
</script>
<div id="tabs">
	<h2 class="heading">tab1</h2>
	<div>tab1 content <a href="#">link example</a></div>
	<h2 class="heading">tab2</h2>
	<div>tab2 content <a href="#">link example</a></div>
	<h2 class="heading">tab3</h2>
	<div>tab3 content <a href="#">link example</a></div>
</div>

다운로드(no jQuery): flowTab.js

view on Github.

WAI-ARIA의 tab, 아직 사용하긴 이르다.

WAI-ARIA에는 다양한 위젯 – 여기서 위젯이란 tab, dialog, alert 등을 말한다. – 이 있는데 그 중 tab은 아직 조금 문제가 많은 것 같다.

WAI-ARIA 저작 가이드 문서의 tab 부분을 보면 탭 인터페이스를 구현하는 방법을 자세히 소개하고 있는데 그 중 키보드 인터페이스에서 좌/우, Ctrl+Tab/Ctrl+Shift+Tab, Ctrl+PageUp/Ctrl+PageDown 키를 이용하여 탭과 탭을 이동하는 기능을 구현하도록 문서화되어 있는데 좌/우 키는 기존에 웹 페이지에서 탭 키를 통해 링크를 이동하던 사용자에게 혼란을, Ctrl+Tab/Ctrl+Shift+Tab이나 Ctrl+PageUp/Ctrl+PageDown 키는 브라우저의 탭간 이동에 사용되고 있어 중복된다. (문서에 이 내용도 언급이 되어있다! -_-)

현재 탭(처럼 보이는) 마크업에는 크게 2가지 코드 형태가 사용된다고 생각한다.

<div class="tabpanel">
	<ul class="tablist">
		<li><a href="#tab1">Tab1</a></li>
		<li><a href="#tab2">Tab2</a></li>
		<li><a href="#tab3">Tab3</a></li>
	</ul>
	<div id="tab1">
		<h1>Tab1</h1>
		Tab1 Content</div>
	<div id="tab2">
		<h1>Tab2</h1>
		Tab2 Content</div>
	<div id="tab3">
		<h1>Tab3</h1>
		Tab3 Content</div>
</div>
[코드1] 탭이 목록형태로 마크업되고 각각 탭 내용으로 연결되도록 구성한 마크업
<div class="tabpanel">
	<h1>Tab1</h1>
	<div id="tab1">Tab1 Content</div>
	<h1>Tab2</h1>
	<div id="tab2">Tab2 Content</div>
	<h1>Tab3</h1>
	<div id="tab3">Tab3 Content</div>
</div>
[코드2] 탭을 헤딩으로, 탭 내용을 헤딩에 이어지는 컨텐츠로 구성한 마크업

[코드1]에는 문제가 발생할 여지가 많다. 탭에서 href="#tab1"와 같은 링크가 생략되는 경우, 링크가 올바로 컨텐츠를 가리키지 못하는 경우, 컨텐츠에 헤딩이 누락되는 경우 등이다. 그리고 [코드1]을 자바스크립트를 통해 구현한 경우 보통 탭의 링크를 취소(preventDefault) 시키기 때문에 다른 탭들을 건너뛰어 해당 내용으로 이동해야 하기 때문에 마우스 사용자 이외에는 비효율적이다. 탭이 많으면 많을수록 더욱 더 비효율적이 된다.

코드1의 키보드 이동 순서

[그림1] 코드1의 키보드 이동 순서는 1번탭 → 2번탭 → … → 마지막 탭 → 선택된 탭 내용 순이다.

[코드2]는 코드1의 키보드 비효율성이 전혀 없다. 코드1의 문제가 발생할 여지들도 애초에 차단된다. 탭 UI를 위해 헤딩을 작성하도록 유도시키고 빼먹거나 잘못 구현할지 모르는 탭 링크들을 애초에 제거하였다.

코드2의 키보드 이동 순서

[그림2] 코드2의 키보드 이동 순서는 1번탭 → 1번탭 내용 → 2번탭 → 2번탭 내용 → …

웹 어플리케이션 위젯을 OS의 그것들처럼 인식시키려고 하는 ARIA의 구현방식에서 볼 때는 코드2와 같은 구현이 적절하지 않다고 생각되기도 한다. 하지만 마우스 사용자에게는 어차피 상관없는 문제이고 키보드 사용자에게는 이전의 웹 페이지들과 다른 사용행태에 대한 혼란을 없앨 수 있다(익숙함을 유지하는 것을 영원히 장점이라고 하긴 어렵지만…). 무엇보다 개발자들에게 오류 발생 가능성을 상당히 줄여줄 수 있다는 사실 때문에 앞서 언급했던 ARIA tab의 문제들을 제거한 라이브러리들이 등장하기 전까지는 코드2와 같은 구현 방식을 추천하고 싶다.

WAI-ARIA의 Live Region

이 글은 아래의 두 문서 내용의 요약 정리본이다.

이 글을 통해 ARIA 개발의 감각을 끌어올릴 수 있기를 바라며 스펙(Taxonomy of WAI-ARIA States and Properties)에 더 많은 내용이 있으니 참고바란다. 예제들은 ARIA를 지원하는 스크린리더(Korean JAWS for Windows (한글용; 유료), NVDA (영어용; 무료))로 어떻게 동작하는지 테스트해볼 수 있다.

Live Region이란?: 개발자가 웹 문서의 특정 부분을 동적인 컨텐츠라고 명시할 수 있는데 그 영역을 일컬어 Live Region이라고 할 수 있다.

개요

과거에는 웹 페이지 변경은 전체를 읽어주게 하거나 거의 읽어주지 않아서 일부 혹은 전체의 정보에 접근할 수 없도록 만들어 종종 사용자를 짜증나게 했다. 최근까지는 보조기기는 이를 개선할 수 없었다. 왜냐하면 변경에 대응하여 보조기기에 경고해줄 수 있는 마크업 표준이 없었기 때문이다. Live Region은 이 차이를 메우고 보조기기에 DOM 변경을 알려줄 수 있는 설정을 제공하였다. 설정은 언제 어디서 업데이트가 발생하고 얼마나 중요한지를 포함한다. Live Region을 사용하는 목표는 가장 먼저 관련 정보를 제공하고 가능한한 사소한 정보는 제한하는 것이다. 웹 개발자는 Live Region 사용에 익숙해져야 하고 웹 사이트의 사용자 인터페이스를 설계할 때 이것을 고려해야 한다.

Live Region state

페이지를 다시 로드하지 않고 업데이트 되는 동적 컨텐츠는 반드시 Live Region을 표시해야한다. Live Region은 ARIA 가이드라인 상태의 영향을 받으며 많은 사용자 정의 설정들은 가지고 있다. 다음은 각 관련 설정의 목록과 그 설명이다.

aria-live: (aria-live=POLITENESS_SETTING)
보조기기가 live region의 업데이트를 처리하는 우선순위를 설정하는데 사용된다. 가능한 설정들은 “off/polite/assertive“이며 기본값은 off.

설정값

aria-relevant: (aria-relevant=[LIST_OF_CHANGES])
live region이 변경될 때 보조기기로 하여금 어떤 변경을 주시하도록 할 것인가를 설정한다. 여기서의 변경은 의미있는 변경 – 예를 들어, 온라인 친구목록에서 친구 리스트 한개가 없어졌다면 이는 친구가 오프라인이 되었다는 의미 – 가능한 설정들은 “additions/removals/text/all“이고 기본값은 “additions text“.

설정값

aria-atomic: (aria-atomic=BOOLEAN)
live region이 변경될 때 보조기기가 live region 중 변경된 요소만을 알려줄지, live region 전체를 알려줄지 설정한다. 가능한 설정들은 “false/true“이고 기본값은 false.

설정값

aria-controls: (aria-controls=[IDLIST])
사용된 요소가 컨트롤하는 요소들을 나타내는데 사용된다. 값에는 컨트롤하는 요소들의 ID가 공백으로 구분되어 들어갈 수 있다. 예) aria-controls="myRegionID1 myRegionID2"
예제: http://accessibleajax.clcworld.net/simple/controls.htm
aria-labelledby: (aria-labelledby=[IDLIST])
live region에 해당하는 레이블들을 나타내는데 사용된다. live region에 사용하며 값에는 레이블 요소들의 ID가 공백으로 구분되어 들어갈 수 있다.
예제: http://accessibleajax.clcworld.net/simple/labelledby.htm
aria-describedby: (aria-describedby=[IDLIST])
live region에 해당하는 설명들을 나타내는데 사용된다. live region에 사용하며 값에는 설명이 포함된 요소들의 ID가 공백으로 구분되어 들어갈 수 있다.
예제: http://accessibleajax.clcworld.net/simple/describedby.htm