이 문서는 W3C의 "WCAG 2.0을 위한 클라이언트측 스크립팅 기법 (WCAG 2.0 기법의 일부, W3C 워킹 그룹 노트)"을 한글로 번역한 문서입니다. 이 문서는 번역 과정에서 발생하는 오류를 포함할 수 있습니다. 번역한 문서는 규범력을 갖지 않으며 오직 영어 버전만이 규범력을 갖습니다.

This documented is a translated copy of the W3C's "Client-side Scripting Techniques for WCAG 2.0 (Part of Techniques for WCAG 2.0, W3C Working Group Note)". This document may contain translation errors. The English version of this specification is the only normative version.

Original document:
http://www.w3.org/TR/WCAG20-TECHS/client-side-script.html
Translator:
Taegon Kim <gonom9@gmail.com>, Sponsored by NIA (National Information Society Agency)
Date of translation:
2010년 8월 25일

WCAG 2.0 기법

내용으로 바로 이동(엔터키를 누르세요)

WCAG 2.0을 위한 클라이언트측 스크립팅 기법

이 웹 페이지는 WCAG 2.0 기법: 웹 콘텐트 접근성 가이드라인 2.0을 위한 기법과 실패의 클라이언트측 스크립팅 기술을 수록하고 있다. 이 기법들에 대한 정보는 WCAG 2.0 기법 소개에서 볼 수 있다. 다른 기술에 대한 기법은 목차에서 찾을 수 있다.


목차



SCR1: 사용자가 제한 시간을 연장할 수 있도록 허용

적용

클라이언트측 스크립트에서 다루어지는 제한 시간.

이 기술과 관련있는 기술:

설명

이 기술의 목적은 스크립트에서 기본 제한 시간을 가진 기능을 제공할 때, 제한 시간을 연장할 수 있는 메커니즘을 제공함으로써 사용자가 기본 제한 시간을 연장할 수 있는 방법을 제공하는 것에 있다. 스크립트는 사용자가 더 긴 제한 시간을 요청할 수 있도록 (예를 들면) 시간을 입력하거나 시간이 더 필요하다는 사실을 표현할 수 있는 폼을 제공할 수 있다. 만일 사용자에게 제한 시간이 거의 만료되었음을 경고한다면 (SCR16: 사용자에게 제한 시간이 거의 만료되었음을 경고하는 스크립트 제공 참고), 이러한 폼은 경고창으로 만들어 질 수 있다. 사용자는 최소 10배까지 기본 제한 시간을 연장할 수 있으며, 이 때 추가할 시간을 사용자가 직접 지정하거나 일정 시간을 반복적으로 연장하는 방법을 사용할 수 있다.

예제

  • 주식 시장의 실시간 통계를 제공하는 웹 페이지가 있고, 이 페이지는 주기적으로 다시 읽도록 설정되어 있다. 사용자가 처음으로 페이지를 다시 읽는 것에 대해 경고받을 때, 사용자에게 다시 읽는 주기를 연장할 수 있는 옵션이 주어진다.

  • 플레이어가 말을 움직일 수 있는 시간에 제한이 있는 온라인 체스 게임이 있다. 움직일 수 있는 시간이 거의 다 끝나간다고 경고를 받을 때, 경고를 받은 플레이어에게 시간을 연장할 수 있는 옵션이 주어진다.

참고 자료

참고 자료는 정보를 위해 제공되었을 뿐이므로, 내용을 지지하거나 동의한다는 뜻은 아니다.

  1. 자바 서블릿을 사용한 세션과 기본 제한시간 설정법

  2. Overriding timeouts in peers applications

  3. PHPBuilder Time-out Info

테스트

절차

  1. 제한 시간이 있는 스크립트를 사용한 웹페이지에서, 제한 시간이 만료될 때까지 대기한다.

  2. 제한 시간을 연장할 수 있는 설정이 제공되면 설정여부 등을 정한다.

기대 결과

  • 2번을 통과해야 하고, 동작이 완료되기 까지의 더 제공되어야 한다.


SCR2: 키보드와 마우스 이벤트 핸들러의 중복 사용

적용

스크립트를 지원하는 HTML과 XHTML.

이 기술과 관련있는 기술:

설명

이 기법은 마우스나 포커스 이벤트 발생시 장치 독립적인 이벤트를 사용해서 이미지를 변경한다. 마우스가 페이지의 HTML 요소 위에 올라가거나 요소 위에서 빠져나갈 때, onmouseover나 onmouseout 이벤트를 사용해서 이미지를 변경한다. 또한 포커스를 얻거나 잃을 때는 onfocusonblur 이벤트를 사용해서 이미지를 변경한다.

아래의 예제에는 앵커 요소를 나타내는 이미지가 있다. 사용자가 앵커 위로 마우스를 이동하면, 앵커 태그의 이미지는 변경된다. 사용자가 마우스를 앵커 바깥으로 옮기면, 이미지는 원래의 이미지로 변경된다. 사용자가 앵커 요소에 키보드 포커스를 줄 때도 동일한 이미지 효과가 나타난다. 포커스를 받으면 이미지가 변경되고, 포커스를 잃으면 복원된다. 이러한 동작은 앵커 요소에 onmouseover, onmouseout, onblur 이벤트 핸들러를 할당하여 작성한다. 이벤트 핸들러로는 자바스크립트 함수 updateImage()를 사용하는데, 이 함수에서 이미지의 src 속성을 바꾼다. updateImage()는 onmouseover, onmouseout, onfocus, onblur 이벤트에 응답해서 호출된다.

각 이미지는 고유의 아이디를 가진다. updateImage()는 고유 아이디와 이미지를 사용할 것인지 가리키는 부울 값을 인수로 받아 updateImage(imgId, isOver);와 같이 실행한다. 앵커 요소 위에 마우스가 있거나 앵커가 포커스를 받았으면 부울값으로 참(true)을 전달하고, 마우스가 앵커 바깥으로 이동했거나 앵커가 포커스를 잃었으면부울값으로 거짓(false)를 전달한다. updateImage() 함수는 이미지의 아이디를 사용해 이미지 요소를 읽어들인 후 부울값에 따라 src 속성을 변경한다. 주의할 점은 여기서는 이미지가 꾸미기 위한 목적으로 사용되었기 때문에 alt 속성에 값을 주지 않았다는 사실이다.

주: 하나의 이미지 요소에 사용할 이미지들은 높이와 너비가 동일한 편이 좋은데, 이미지가 업데이트 될 때 페이지의 레이아웃이 변경되는 것을 방지할 수 있기 때문이다. 이 예제에서 사용한 이미지들은 모두 크기가 동일하다고 가정한다.

예제

예제 1

예제 코드:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"  "http://www.w3.org/TR/html4/loose.dtd">
 <html lang="ko">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>장치 독립적인 방법으로 이미지 소스 변경하기</title>
 <script type="text/javascript">
 /* 이 함수는 이미지 요소의 이미지 src를 바꾼다.
  * param imgId -  바꿀 이미지의 객체 아이디
  * param isOver - 마우스가 객체 위로 올라가거나 객체에 포커스가 갔을 때는 true,
  *                마우스가 객체를 벗어나거나 포커스를 잃었을 때는 false
 */
 function updateImage(imgId, isOver) {
   var theImage = document.getElementById(imgId);
   if (theImage != null) { // 자바스크립트 1.4를 지원하는 사용자 도구에서는 try/catch를 사용할 수 있다.
                           // try/catch를 지원하는 브라우저 - NetScape 6, IE 5, Mozilla, Firefox
      if (isOver) {
        theImage.setAttribute("src","yellowplus.gif");
      }
      else {
        theImage.setAttribute("src","greyplus.gif");
      }
   }
 }
 </script>
 </head>
 <body>
 <p>아래의 링크에 마우스를 올리거나 탭을 입력하면 이미지가 변경된다.</p>
 <a href="http://www.w3.org/wai" onmouseover="updateImage('wai', true);" onfocus="updateImage('wai', true);"
   onmouseout="updateImage('wai',false);" onblur="updateImage('wai',false);">
 <img src="greyplus.gif" border="0" alt="" id="wai">
   W3C Web Accessibility Initiative</a> &
 <a href="http://www.w3.org/International/" onmouseover="updateImage('i18n', true);"
   onfocus="updateImage('i18n',true);" onmouseout="updateImage('i18n',false);"
   onblur="updateImage('i18n',false);">
   <img src="greyplus.gif" border="0" alt="" id="i18n">
   W3C Internationalization</a>
 </body>
 </html>

테스트

절차

웹 페이지를 읽어들인 후 마우스와 키보드를 사용해서 이벤트를 테스트한다.

  1. 웹 페이지를 읽어들이면 "표준" 이미지가 나타나는지 확인한다.

  2. 마우스 사용

    1. 이벤트 핸들러를 포함한 HTML 요소(이 예제에서는 앵커 요소) 위로 마우스를 옮긴다. 이미지가 예상한 이미지로 바뀌는지 확인한다.

    2. 마우스를 HTML 요소 바깥으로 이동한다. 이미지가 "표준" 이미지로 복원되는지 확인한다.

  3. 키보드 사용

    1. 키보드를 사용해서 이벤트 핸들러를 포함한 HTML 요소에 포커스를 준다. 이미지가 예상한 이미지로 바뀌는지 확인한다.

    2. 키보드를 사용해 HTML 요소에서 포커스를 제거한다(일반적으로 이 동작은 다른 요소로 포커스를 옮긴다). 이미지가 "표준" 이미지로 복원되는지 확인한다.

  4. 이미지가 변경될 때, 페이지에 있는 다른 HTML 요소의 레이아웃이 영향을 받지 않았는지 확인한다.

기대 결과

  • 위의 모든 절차를 통과해야 한다.


SCR14: 스크립트를 사용해 필수적이지 않은 경고창을 선택적으로 만들기

적용

위급하지 않은 커뮤니케이션에 경고창을 사용하는 스크립트 기술

이 기술과 관련있는 기술:

설명

이 기법의 목적은 (경고) 메시지를 포함한 대화창을 사용자에게 보여주는 것이다. 경고창이 나타날 때 경고창은 포커스를 얻으며, 사용자는 경고창을 닫으려면 확인 버튼을 클릭해야 한다. 경고창들은 포커스를 바꾸기 때문에 사용자의 주의를 분산시킬 수 있는데, 이러한 경향은 특히 경고창이 긴급하지 않은 정보를 표현하기 위해 사용될 때 두드러진다. 어떠한 경고창들은 오늘의 격언, 사용팁, 특정일까지의 날짜 카운트다운 등과 같이 긴급하지 않은 목적으로 사용된다. 이러한 경고창들은 웹 페이지에서 제공하는 옵션을 통해 사용자가 활성화하는 경우에만 나타난다.

이 기법은 자바스크립트 전역 변수에 경고창 표시를 위한 사용자 설정을 저장한다. 기본값은 거짓(false)이다. 래퍼 함수는 경고창을 표시하기 전에 이 변수의 값을 확인한다. 경고창은 alert() 함수를 직접 호출하지 않고 이 래퍼 함수를 사용해서 표시한다. 페이지 앞 부분에는 사용자가 경고창 표시를 활성화시킬 수 있는 버튼이 있다. 이 기법은 매번 방문시마다 적용된다. 다시 말해, 페이지를 읽어들일때마다 경고창은 비활성화되어있고 사용자는 수동으로 경고창을 활성화해야 한다. 대안으로는 쿠키를 사용해 사용자 설정을 저장하는 방법도 있다.

예제

예제 1

아래의 스크립트는 사용자가 "경고창 켜기" 버튼을 선택한 경우, 10초마다 한번씩 격언을 경고창으로 보여준다. 사용자는 "경고창 끄기"를 선택해서 격언이 나타나는 것을 중단할 수 있다.

예제 코드:


<script type="text/javascript">
var bDoAlerts = false;  // 경고창을 나타낼 것인지 가리키는 전역 변수

/* 경고창을 활성화/비활성화 하는 함수
 * param boolean bOn - 경고창을 활성화하려면 true, 비활성화하려면 false.
*/
function modifyAlerts(isEnabled) {
   bDoAlerts = isEnabled;
}
/* 경고창을 표현하는 래퍼 함수. bDoAlerts 변수의 값을 확인하여
* bDoAlerts의 값이 참(true)일 때만 alert() 함수를 호출한다.
*/
function doAlert(aMessage) {
    if (bDoAlerts) {
       alert(aMessage);
    }
}
// 사용 예제 - 루프를 실행해 유명한 격언을 표시한다.
var gCounter = -1;  // 카운터를 저장하는 전역 변수
// 유명한 격언들을 포함한 quotes 변수
var quotes = new Array("quote 1", "quote 2", "quote 3", "quote 4", "quote 5");
function showQuotes() {
   if (++gCounter &gt;= quotes.length) {
     gCounter = 0;
   }
   doAlert(quotes[gCounter]);
   setTimeout("showQuotes();", 10000);
}
showQuotes();
</script>

페이지의 본문에는 경고창을 켜고 끌 수 있는 방법을 포함한다. 다음은 하나의 예제이다:

예제 코드:


<body>
<p>아래의 버튼을 클릭해서 격언 경고창을 표시한다.<br />
<button id="enableBtn" type="button" onclick="modifyAlerts(true);">
경고창 켜기</button><br />
<button id="disableBtn" type="button" onclick="modifyAlerts(false);">
경고창 끄기</button></p>

이 코드의 실제 동작 예제: 경고창 데모.

테스트

절차

자바스크립트 경고창을 사용해 긴급하지 않은 중단이 발생하는 웹 페이지에서

  1. 웹 페이지를 읽어들인 후 긴급하지 않은 경고창이 표시되지 않는지 확인한다.

  2. 긴급하지 않은 경고창을 활성화하는 메커니즘이 있는지 확인한다.

  3. 긴급하지 않은 경고창을 활성화 한 후 경고창이 표시되는지 확인한다.

기대 결과

  • 자바스크립트 경고창을 사용한 긴급하지 않은 방해가 있는 웹 페이지에서 1, 2, 3번 항목을 통과해야 한다.


SCR16: 사용자에게 제한 시간이 거의 만료되었음을 경고하는 스크립트 제공

적용

스크립트에 의해 조절되는 시간 제한이 있는 경우

이 기술과 관련있는 기술:

설명

이 기법의 목적은 사용자에게 인터랙션을 마쳐야 할 시간이 거의 만료되었음을 알리는 것에 있다. 스크립트에서 제한 시간이 있는 기능을 제공할 때, 해당 스크립트에서는 사용자에게 제한 시간이 얼마 남지 않았음을 경고하고 시간을 연장할 수 있는 메커니즘을 제공할 수 있다. 제한 시간까지 20초 혹은 그 이상의 시간이 남았을 때, 스크립트는 시간이 얼마 남지 않았으며 시간이 더 필요한지 묻는 확인창을 제공한다. 사용자가 "네"라고 답하면 제한 시간은 리셋되고, "아니오"라고 답하거나 응답하지 않는다면 제한 시간은 만료된다.

이 기법에서 시간 제한은 window.setTimeout() 메소드를 사용해 설정한다. 예를 들어, 만약 제한 시간이 60초라면 타이머를 40초로 설정해두고 확인창을 표시할 수 있다. 확인창이 화면에 나타날 때, 새롭게 20초짜리 타이머를 설정한다. 20초의 "유예 시간"이 만료되면 최초 설계시 60초 제한 시간이 끝날 때 실행되도록 한 동작이 실행된다.

예제

예제 1

주식 현황 페이지는 최신 통계를 화면에 표시하고 사용할 수 있도록 스크립트를 사용해 5분마다 페이지를 새로 읽어들인다. 5분 간격이 만료되기 20초 전에 확인창이 나타나 페이지를 새로 읽어들이기 전에 시간이 더 필요한지 묻는다. 이를 통해 사용자는 곧 페이지를 새로 읽어들일 것을 알게 되고, 원하지 않는다면 새로 고침을 피할 수도 있다.

예제 코드:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"<url>http://www.w3.org/TR/html4/loose.dtd">http://www.w3.org/TR/html4/loose.dtd</title>">
<html lang="en">
<head>
<title>Stock Market Quotes</title>
<script type="text/javascript">
<!--
function timeControl() {
	// 타이머를 4분 40초로 설정하고, 이 때 확인창을 표시한다.
	setTimeout('userCheck()', 280000);
}
function userCheck() {
	// 20초 후에 페이지를 새로 고친도록 설정
	var id=setTimeout('pageReload()', 20000);
	// 사용자가 "확인"을 선택하면 타이머를 리셋하고,
	// 그렇지 않으면 페이지를 서버에서 새로 읽어들인다.
	if (confirm("이 페이지는 20초 후에 다시 읽어들입니다.
	시간을 연장하시겠습니까?"))
	{
	clearTimeout(id);
	timeControl();
	}
}
function pageReload() {
	window.location.reload(true);
}
timeControl();
-->
</script>
</head>
<body>
<h1>Stock Market Quotes</h1>
...etc...
</body>
</html>

테스트

절차

스크립트로 제어하는 제한 시간이 있는 웹 페이지:

  1. 페이지를 읽어들이고, 제한 시간보다 20초 적은 시간으로 타이머를 시작한다.

  2. 타이머의 시간이 만료되었을 때, 제한 시간이 끝나간다는 것을 알리는 확인창이 나타나는지 확인한다.

기대 결과

  • 2번을 통과해야 한다.


SCR18: 클라이언트측 유효성 검사와 경고 제공

적용

사용자 입력에 대해 유효성을 검사하는 콘텐트.

이 기술과 관련있는 기술:

설명

이 기법은 각 필드에 사용자가 입력한 값의 유효성을 클라이언트측 스크립트로 검사한다. 에러가 발견되면 에러의 속성을 설명하는 경고창을 표시한다. 이 때, 사용자가 경고창을 닫으면 스크립트를 사용해 에러가 발생한 필드로 키보드 포커스를 이동하는 방법이 유용하다.

예제

예제 1

다음 스크립트는 폼 콘트롤에 입력된 날짜가 유효한지 확인한다.

예제 코드:


<label for="date">Date:</label>
<input type="text" name="date" id="date"
onchange="if(isNaN(Date.parse(this.value)))
alert('이 콘트롤은 유효하지 않은 날짜입니다. 값을 다시입력해주세요.');" />

테스트

절차

특정한 형식을 요구하는 폼 필드에서:

  1. 유효하지 않은 값을 입력한다

  2. 에러를 설명하는 경고창이 나타나는지 확인한다.

기대 결과

  • 2번을 통과해야 한다.


SCR19: 컨텍스트의 변화 없이 select 요소의 onchange 이벤트 사용

적용

스크립팅을 지원하는 HTML과 XHTML. 이 기법은 자바스크립트 1.4의 try/catch 구조를 사용한다.

이 기술과 관련있는 기술:

사용자 도구와 보조 기술 지원

이 기법은 Windows XP에서 JAWS 7.0과 WindowEyes 5.5를 사용해 테스트되었으며, 테스트시 웹 브라우저로는 Firefox 1.5와 IE 6를 사용했다. 또한, 웹 브라우저에서 자바스크립트가 반드시 활성화되어 있어야 한다.

설명

이 기법의 목적은 select 요소와 onchange 이벤트를 사용해 다른 HTML 요소를 업데이트 하는 올바른 방법을 보여주는 것에 있다. 이 기법은 컨텍스트를 변경하지 않는다. 웹 페이지에 한 개 이상의 select 요소가 있을 때, 각 요소에 있는 onchange 이벤트는 같은 페이지에 있는 다른 select 요소의 옵션을 업데이트 할 수 있다. select 요소가 필요로 하는 데이타는 모두 웹 페이지안에 포함되어 있다.

읽는 순서를 기준으로 수정되는 select 요소는 이벤트가 발생한 select 요소 다음에 위치하는 것이 중요하다. 이는 보조 기술에서 변경 사항을 인식하고, 변경된 요소가 포커스를 가졌을 때 사용자가 새로운 데이터를 사용할 수 있게 한다. 이 기법은 사용자 도구에서 자바스크립트를 사용할 수 있어야 한다.

예제

예제 1

이 예제에는 두 개의 select 요소가 있다. 첫번째 select에서 어떤 항목이 선택되면, 선택에 따라 다른 select가 업데이트된다. 첫번째 select 요소는 대륙 목록을 포함하고 있고, 두번째 select는 선택한 대륙에 속한 국가를 일부 나열하고 있다. onchange 이벤트는 대륙 select 요소에 할당되었다. 대륙을 선택하면 문서 객체 모델(Document Object Model, DOM)과 자바스크립트를 사용해 국가 목록을 수정한다. 대륙과 국가 목록 등 필요한 모든 데이터는 웹 페이지에 포함되어 있다.

코드 개요

  • countryLists 배열은 첫번째 select 요소에 있는 대륙에 해당하는 국가 목록을 포함한다.

  • countryChange() 함수는 대륙 select 요소의 onchange 이벤트를 통해 호출된다.

  • 웹 페이지의 body에는 select 요소를 생성하는 XHTML 코드가 있다.

예제 코드:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko lang="ko>
  <head>
    <meta http-equiv="content-type" content="text/xhtml; charset=utf-8" />
    <title>동적인 Select 요소</title>
<script type="text/javascript">
 //<![CDATA[
 // 국가 목록에 이 순서대로 나타날 국가 목록 배열
 var countryLists = new Array(4)
 countryLists["empty"] = ["Select a Country"];
 countryLists["North America"] = ["Canada", "United States", "Mexico"];
 countryLists["South America"] = ["Brazil", "Argentina", "Chile", "Ecuador"];
 countryLists["Asia"] = ["Russia", "China", "Japan"];
 countryLists["Europe"]= ["Britain", "France", "Spain", "Germany"];
 /* CountryChange() 는 select 요소의 onchange 이벤트를 통해 호출된다.
 * param selectObj - onchange 이벤트가 발생한 select 객체
 */
 function countryChange(selectObj) {
 // 선택한 옵션의 인덱스를 얻는다
 var idx = selectObj.selectedIndex;
 // 선택한 옵션의 값을 얻는다
 var which = selectObj.options[idx].value;
 // 선택된 값을 사용해 countryLists 배열에서 옵션 목록을 가져온다
 cList = countryLists[which];
 // 아이디를 통해 국가 select 요소를 얻는다
 var cSelect = document.getElementById("country");
 // 국가 select 요소에 있는 현재 옵션들을 제거한다
 var len=cSelect.options.length;
 while (cSelect.options.length > 0) {
 cSelect.remove(0);
 }
 var newOption;
 // 새 옵션을 생성한다
 for (var i=0; i<cList.length; i++) {
 newOption = document.createElement("option");
 newOption.value = cList[i];  // 옵션 문자열과 값이 같다고 가정한다
 newOption.text=cList[i];
 // 새 옵션을 추가한다
 try {
 cSelect.add(newOption);  // DOM 브라우저에서는 에러가 나지만 IE에서 필요한 부분
 }
 catch (e) {
 cSelect.appendChild(newOption);
 }
 }
 }
//]]>
</script>
</head>
<body>
  <noscript>이 페이지를 사용하려면 자바스크립트가 필요합니다</noscript>
  <h1>동적 선택</h1>
  <label for="continent">대륙 선택</label>
  <select id="continent" onchange="countryChange(this);">
    <option value="empty">대륙 선택</option>
    <option value="North America">북미</option>
    <option value="South America">남미</option>
    <option value="Asia">아시아</option>
    <option value="Europe">유럽</option>
  </select>
  <br/>
  <label for="country">국가 선택</label>
  <select id="country">
    <option value="0">국가 선택</option>
  </select>
</body>
 </html>

실제 동작하는 예제: 동적인 Select 요소

참고 자료

참고 자료는 정보를 위해 제공되었을 뿐이므로, 내용을 지지하거나 동의한다는 뜻은 아니다.

(현재 수록된 것은 없음)

테스트

절차

  1. 이벤트를 발생시킬 select 요소(이 예제에서는 대륙 select 요소)로 이동하고 값을 변경한다.

  2. 이벤트에 의해 업데이트 된 select 요소(이 예제에서는 국가 select 요소)로 이동한다.

  3. 앞의 select 요소에서 선택한 값에 맞는 옵션들이 표시됐는지 확인한다.

  4. 이벤트를 발생시킬 select 요소로 이동하되, 선택된 값을 바꾸지는 않는다.

  5. 연관된 select 요소에서 표시되는 값들이 여전히 올바르게 일치하는지 확인한다.

보조 기술을 사용해서 어떤 select 요소를 변경했을 때 연관된 select 요소의 변경사항이 인식되는지 테스트할 것을 권장한다.

기대 결과

  • 3번과 5번을 통과해야 한다.


SCR20: 키보드와 그 외 장치 종속적인 기능들을 함께 사용

적용

스크립트를 사용해 기능을 구현한 모든 콘텐트

이 기술과 관련있는 기술:

설명

이 기법의 목적은 이벤트를 통해 스크립트를 사용할 때 키보드와 마우스 이벤트를 동시에 사용하는 방법을 보여주는 것이다. 키보드와 마우스 이벤트를 동시에 사용하면 콘텐트의 운용성을 보장할 수 있는 장치의 범위가 넓어진다. 예를 들어, 스크립트에서 keypress 이벤트를 통해 실행되는 동작은 마우스 버튼이 클릭되었을 때도 실행할 수 있다. 이 기법은 키보드 접근뿐만 아니라 다른 장치에서의 접근도 포함하고 있으므로 키보드 접근성을 위한 성공 기준 요구사항보다 더 발전한 것이다.

자바스크립트에서 일반적으로 사용하는 이벤트 핸들러는 onblur, onchange, onclick, ondblclick, onfocus, onkeydown, onkeypress, onkeyup, onload, onmousedown, onmousemove, onmouseout, onmouseover, onmouseup, onreset, onselect, onsubmit, onunload 등이다. 일부 마우스 이벤트들은 논리적으로 일치하는 키보드 이벤트가 존재한다(예로, 'onmouseover'와 'onfocus'). 마우스 이벤트 핸들러로 어떤 기능을 실행한다면, 이에 대한 키보드 이벤트 핸들러도 제공되어야 한다.

다음은 마우스 이벤트와 짝이 되는 키보드 이벤트를 나타낸 표이다.

장치 이벤트 핸들러 대응
마우스 이벤트키보드 이벤트
mousedown keydown
mouseup keyup
click [1] keypress [2]
mouseover focus
mouseout blur

1 click 은 원칙적으로는 마우스 이벤트 핸들러지만 대부분의 HTML, XHTML 사용자 도구는 마우스/키보드에 상관없이 콘트롤이 작동되면 이 이벤트를 처리한다. 따라서, 실제 사용할 때 이 이벤트는 중복 처리할 필요가 없다. 여기에서는 HTML이 아닌 사용자 도구에서의 호환성 문제를 위해 표시했다.

2 keypress 이벤트 핸들러는 모든 키에 반응하기 때문에, 이벤트를 처리하기 전에 이벤트 핸들러 함수에서 눌려진 키가 엔터인지 확인해야 한다. 그렇지 않으면, 키를 누를 때마다 이벤트가 발생하는데 심지어 탭키를 눌러 콘트롤을 벗어날 때도 반응한다. 이는 일반적으로 원하는 동작은 아닐 것이다.

일부 마우스 함수들은(dblclick, mousemove 등) 대응하는 키보드 함수가 없다. 이는 곧 일부 함수들은 각 장치별로 다르게 구현할 필요가 있다는 뜻이다.

예제

예제 1

이 예제에서 이미지 링크에 있는 이미지는 사용자가 이미지 위에 포인터를 위치했을 때 변경된다. 키보드 사용자들을 위해 유사한 경험을 제공하려면 사용자가 탭을 입력했을 때도 이미지가 바뀌도록 한다.

예제 코드:


<a href="menu.php" onmouseover="swapImageOn('menu')" onfocus="swapImageOn('menu')"
onmouseout="swapImageOff('menu')" onblur="swapImageOff('menu')">
<img id="menu" src="menu_off.gif" alt="Menu" />
</a>

예제 2

이 예제는 키보드를 사용해 함수를 실행하는 이미지를 보여준다. onclick 마우스 이벤트는 onkeypress 키보드에서도 동일하게 동작한다. tabindex 속성을 사용하면 키보드를 사용해서 이미지로 탭 이동할 수 있다. 이 예제에서 nextPage() 함수는 눌려진 키가 엔터인지 확인해야 하는데, 그렇지 않으면 이미지가 포커스를 가진 동안 모든 키보드 액션에 반응해버리기 때문이다.

예제 코드:


<img onclick="nextPage();" onkeypress="nextPage();" tabindex="0" src="arrow.gif"
alt="다음 페이지로 이동"> 

주: 이 예제는 img 요소에 tabindex를 사용한다. 비록 유효하지는 않으나 함수를 실행하기 위한 고전적인 기법으로서 제공되었다.

참고 자료

참고 자료는 정보를 위해 제공되었을 뿐이므로, 내용을 지지하거나 동의한다는 뜻은 아니다.

테스트

절차

  1. 모든 인터랙티브 기능을 찾는다

  2. 모든 인터랙티브 기능에 키보드만 사용해서도 접근할 수 있는지 확인한다.

기대 결과

  • 2번을 통과해야 한다.


SCR21: 페이지에 콘텐트를 추가하기 위한 문서 객체 모델(Document Object Model, DOM) 함수 사용

적용

HTML과 XHTML에서 사용되는 ECMAScript

이 기술과 관련있는 기술:

사용자 도구와 보조 기술 지원

이 예제는 WindowsXP에서 JAWS 7과 WindowEyes 5.5를 사용해 테스트되었으며, 테스트시 웹 브라우저로는 IE 6와 Firefox 1.5.0.1을 사용했다. 새 콘텐트가 페이지에 추가될 때 화면 낭독기는 새 콘텐트를 자동으로 읽어주지 않는다. 새 콘텐트를 읽게 하려면, 새로운 요소에 포커스를 주거나 현재 위치보다 아래에 위치시켜서 사용자가 탐색을 계속하면 만날 수 있도록 하는 것이 좋다.

설명

이 기법은 document.wirteobject.innerHTML 대신 문서 객체 모델 (DOM)을 사용한 콘텐트 추가 방법을 보여준다. document.write() 메소드는 올바른 MIME 타입(application/xhtml+xml)과 함께 제공된 XHTML에서는 동작하지 않으며, innerHTML 속성은 DOM 명세의 일부가 아니므로 사용을 피해야 한다. DOM 함수를 사용해 새 콘텐트를 추가하면, 사용자 도구에서 DOM을 사용해 콘텐트에 접근할 수 있다. createElement() 함수는 DOM에서 새 요소를 만들 때 사용한다. createTextNode() 함수는 HTML 요소와 관련된 텍스트를 만들 때 사용한다. appendChild(), removeChild(), insertBefore(), replaceChild() 함수는 HTML 요소와 노드를 추가하거나 제거할 때 사용한다. 작성한 HTML 요소에 속성을 할당할 때는 다른 DOM 함수를 사용한다.

주: 문서에 포커스를 가지 수 있는 HTML 요소를 추가할 때, 탭 순서를 정하는 tabindex 속성을 추가하면 안 된다. 문서 중간에 포커스를 받을 수 있는 HTML 요소를 추가하면 문제가 발생할 수 있기 때문이다. tabindex 속성을 추가하지 않으면 새 HTML 요소에 기본 탭 순서가 할당되는데 이를 사용하라.

예제

예제 1

이 예제는 폼의 유효성을 검사하는 클라이언트 스크립트의 사용법을 보여준다. 에러가 발견되면 적절한 에러 메시지를 표시한다. 예제에서는 제목, 발생한 에러에 대해 설명하는 짧은 문단, 순서 목록에 표시하는 에러 목록으로 구성된 에러메시지를 추가하기 위해 DOM 함수를 사용했다. 제목의 콘텐트는 링크로 작성되어 focus 메소드를 사용하면 사용자의 주의를 끌 수 있다. 목록의 각 항목은 링크로 작성하여 링크를 따라가면 에러가 발생한 폼 필드에 포커스를 이동할 수 있다.

이 예제는 간단하게 하기 위해 두 개의 텍스트 필드에 대해서만 유효성을 검사하지만, 일반적인 폼에도 충분히 사용할 수 있도록 쉽게 확장가능하다. 클라이언트측 유효성 검사가 유일한 유효성 검사 수단이 되어서는 안되며, 서버측 유효성 검사를 통한 지원이 꼭 필요하다. 클라이언트측 유효성 검사의 장점은 사용자가 서버로 데이터를 전송하고 에러를 되돌려 전송받기까지 기다리지 않아도 되도록 즉각적인 피드백을 줄 수 있다는 점이다. 그 덕분에 불필요한 서버로 오가는 불필요한 트래픽을 줄일 수 있다는 것도 장점이다.

이 예제는 폼에 이벤트 핸들러를 추가하는 스크립트를 사용한다. 스크립트를 사용할 수 있다면, validateNumbers() 함수는 서버에 폼을 전송하기 전에 클라이언트측 유효성 검사를 수행한다. 스크립트를 사용할 수 없다면, 폼을 서버로 바로 전송되어 유효성 검사를 서버에서 수행하게 될 것이다.

예제 코드:


window.onload = initialise;
function initialise()
{
  // 표준 호환 사용자 도구가 아니면 동작하지 않는다
    if (!document.getElementById || !document.createElement || !document.createTextNode)
    return;

  // 숫자 폼에 이벤트 핸들러를 추가한다
  var objForm = document.getElementById('numberform');
  objForm.onsubmit= function(){return validateNumbers(this);};
}

다음은 유효성 검사 함수이다. 에러 메시지 요소는 createElement(), createTextNode(), appendChild() 등의 DOM 함수를 사용해서 추가했다.

예제 코드:


function validateNumbers(objForm)
{
  // 필드가 유효한지 테스트한다
  var bFirst = isNumber(document.getElementById('num1').value);
  var bSecond = isNumber(document.getElementById('num2').value);
  // 유효하지 않다면 에러를 표시한다
  if (!bFirst || !bSecond)
  {
    var objExisting = document.getElementById('validationerrors');
    var objNew = document.createElement('div');
    var objTitle = document.createElement('h2');
    var objParagraph = document.createElement('p');
    var objList = document.createElement('ol');
    var objAnchor = document.createElement('a');
    var strID = 'firsterror';
    var strError;
    // 제목 요소에 링크를 포함시켜 화면 낭독기가 이를 사용해
    // 포커스를 줄 수 있도록 한다 - 링크의 목적지는 목록에서 처음으로
    // 에러가 발생한 곳이다.
    objAnchor.appendChild(document.createTextNode('Errors in Submission'));
    objAnchor.setAttribute('href', '#firsterror');
    objTitle.appendChild(objAnchor);
    objParagraph.appendChild(document.createTextNode('Please review the following'));
    objNew.setAttribute('id', 'validationerrors');
    objNew.appendChild(objTitle);
    objNew.appendChild(objParagraph);
    // 에러 목록에 발견한 에러를 추가한다
    if (!bFirst)
    {
      strError = '첫번째 숫자에 숫자값을 입력해주세요';
      objList.appendChild(addError(strError, '#num1', objForm, strID));
      strID = '';
    }
    if (!bSecond)
    {
      strError = '두번째 숫자에 숫자값을 입력해주세요';
      objList.appendChild(addError(strError, '#num2', objForm, strID));
      strID = '';
    }
    // 에러 정보에 목록을 추가한다
    objNew.appendChild(objList);
    // 에러가 있으면 이들을 새로운 것으로 대체하고,
    // 에러가 없으면 폼의 앞 부분에 새로운 에러를 추가한다.
    if (objExisting)
      objExisting.parentNode.replaceChild(objNew, objExisting);
    else
    {
      var objPosition = objForm.firstChild;
      objForm.insertBefore(objNew, objPosition);
    }
    // 제목에 있는 앵커에 포커스를 주어 화면 낭독기가
    // 에러를 알 수 있도록 한다.
    objAnchor.focus();
    // 폼을 전송하지 않는다
    objForm.submitAllowed = false;
    return false;
  }
  return true;
}

// 유효한 숫자인지 확인하는 함수
function isNumber(strValue)
{
  return (!isNaN(strValue) && strValue.replace(/^\s+|\s+$/, '') !== '');
}

다음은 에러 메시지를 만들고 관련된 폼 필드에 포커스를 주는 함수이다.

예제 코드:


// 에러를 설명하고 알맞은 폼 필드를 가리키는 링크의 목록을 만드는 함수
function addError(strError, strFragment, objForm, strID)
{
  var objAnchor = document.createElement('a');
  var objListItem = document.createElement('li');
  objAnchor.appendChild(document.createTextNode(strError));
  objAnchor.setAttribute('href', strFragment);
  objAnchor.onclick = function(event){return focusFormField(this, event, objForm);};
  objAnchor.onkeypress = function(event){return focusFormField(this, event, objForm);};
  // strID가 값을 가지고 있으면, 목록의 첫번째 에러이다.
  if (strID.length > 0)
    objAnchor.setAttribute('id', strID);
  objListItem.appendChild(objAnchor);
  return objListItem;
}

// 에러가 발생하면 해당 필드로 포커스를 옮기는 함수
function focusFormField(objAnchor, objEvent, objForm)
{
  // Allow keyboard navigation over links
  if (objEvent && objEvent.type == 'keypress')
    if (objEvent.keyCode != 13 && objEvent.keyCode != 32)
      return true;
  // 포커스를 폼 콘트롤로 이동
  var strFormField = objAnchor.href.match(/[^#]\w*$/);
  objForm[strFormField].focus();
  return false;
}

다음은 폼 예제 HTML입니다.

예제 코드:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
	<title>ECMAScript 폼 유효성검사</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<script type="text/javascript" src="validate.js"></script>
</head>
<body>
<h1>폼 유효성 검사</h1>
<form id="numberform" method="post" action="form.php">
<fieldset>
<legend>숫자 필드</legend>
<p>
<label for="num1">첫번째 숫자</label>
<input type="text" size="20" name="num1" id="num1">
</p>
<p>
<label for="num2">두번째 숫자</label>
<input type="text" size="20" name="num2" id="num2">
</p>
</fieldset>
<p>
<input type="submit" name="submit" value="폼 전송">
</p>
</form>
</body>
</html>

이 예제는 클라이언트측 스크립트에 한하므로, 서버측 유효성 검사도 함께 제공해야 합니다. 예제에서 에러 메시지는 클라이언트측 스크립트를 사용할 수 있을 때만 동작합니다.

실제 동작하는 예제: 폼 유효성검사

참고 자료

참고 자료는 정보를 위해 제공되었을 뿐이므로, 내용을 지지하거나 동의한다는 뜻은 아니다.

(현재 수록된 것은 없음)

테스트

절차

동적으로 새로운 콘텐트를 만드는 페이지에서:

  1. 소스 코드를 검토해서 새로운 콘텐트가 document.write(), innerHTML, outerHTML, outerText를 사용해서 작성되지 않았는지 확인한다.

기대 결과

  • 1번을 통과해야 한다..


SCR22: 스크립트를 사용해 깜빡임을 제어하고 5초 안에 중단하기

적용

스크립트를 사용해 콘텐트를 깜빡이는 기술

이 기술과 관련있는 기술:

설명

이 기법은 스크립트를 사용해서 깜빡임을 제어하고 5초 안에 깜빡임을 중단한다. 스크립트를 사용해 콘텐트를 시각적으로 나타냈다 감췄다를 반복하여 깜빡임 효과를 주고 5초 안에 이 효과를 중단한다. 콘텐트를 나타냈다 감췄다하며 깜빡임 효과를 주는 한편, 깜빡임 반복 시간의 합이 거의 5초가 되어 효과를 중단할 때 setTimeout() 함수를 사용할 수 있다.

예제

예제 1

이 예제는 깜빡임 효과를 제어하기 위해 자바스크립트를 사용한다. 자바스크립트에서는 콘텐트의 시각적인 상태를 변경하여 깜빡임 효과를 만들어낸다. 또한, 효과를 시작하고 5초안에 중단하는 역할도 한다.

예제 코드:


...
<div id="blink1" class="highlight">새로운 항목!</div>
<script type="text/javascript">
<!--
// 깜빡임 "켜짐" 상태
function show()
{
	if (document.getElementById)
	document.getElementById("blink1").style.visibility = "visible";
}
// 깜빡임 "꺼짐" 상태
function hide()
{
	if (document.getElementById)
	document.getElementById("blink1").style.visibility = "hidden";
}
// "켜짐"과 "꺼짐" 상태는 450ms 마다 번갈아 바뀌며 깜빡임 효과를 연출하고
// 45000ms 후에 종료한다(5초 미만)
for(var i=900; i < 4500; i=i+900)
{
	setTimeout("hide()",i);
	setTimeout("show()",i+450);
}
-->
</script>
...
            

이 코드의 실제 동작 예제: 깜빡임 제어 스크립트.

테스트

절차

각각의 깜빡이는 콘텐트에서:

  1. 깜빡임 효과가 시작할 때 5초 타이머를 시작한다.

  2. 타이머가 만료되었을 때, 깜빡임 효과가 정지되어있는지 확인한다.

기대 결과

  • 각각의 깜빡이는 콘텐트에서 2번을 통과해야 한다..


SCR24: 사용자 요구에 의한 새 창 열기에 점진적 향상 사용

적용

HTML 4.01과 XHTML 1.0

이 기술과 관련있는 기술:

설명

이 기법의 목적은 사용자가 요청하지 않은 새 창으로 인한 혼란을 피하고자 하는 것에 있다. 갑자기 새 창이 나타나면 일부 사용자들은 혼란스러워하거나 창을 못보고 지나칠 수 있다. 사용중인 문서 유형에서 target 속성을 허용하지 않거나(HTML 4.01 Strict 혹은 XHTML 1.0 Strict에서는 허용 안함) 개발자가 target 속성 사용을 꺼린다면, ECMAScript를 사용해서 새 창을 열 수 있다. 아래의 예제는 스크립트를 사용한 새 창 여는 법을 보여주고 있다. 링크(a 요소)에 이벤트 핸들러를 추가하고, 사용자에게 새 창이 열릴 것이라고 알려준다.

예제

예제 1:

마크업:

스크립트는 문서의 head에 포함되어 있고, 링크에는 나중에 스크립트에서 사용하기 위해 id를 부여했다.

예제 코드:


<script type="text/javascript" src="popup.js"></script>
…
<a href="help.html" id="newwin">도움말</a

스크립트:

예제 코드:


// 이벤트 등록 지원이 미미한 브라우저를 위해 전통적인 이벤트 모델 사용
window.onload = addHandlers;

function addHandlers()
{
  var objAnchor = document.getElementById('newwin');

  if (objAnchor)
  {
    objAnchor.firstChild.data = objAnchor.firstChild.data + ' (opens in a new window)';
    objAnchor.onclick = function(event){return launchWindow(this, event);}
    // 사용자 도구 웹 접근성 가이드(User Agent Accessibility Guidelines, UAAG)는
    // 사용자 도구가 장치 독립적인 방법으로 이벤트를 다루라고 하지만,
    // 일부 브라우저는 이것만 지원하므로 키보드 이벤트도 추가했다.
    objAnchor.onkeypress = function(event){return launchWindow(this, event);}
  }
}

function launchWindow(objAnchor, objEvent)
{
  var iKeyCode, bSuccess=false;

  // 키보드 이벤트라면 (엔터나 스페이스를 통해) 사용자가 링크를
  // 요청한 경우에만 새 창을 열도록 한다.
  if (objEvent && objEvent.type == 'keypress')
  {
    if (objEvent.keyCode)
      iKeyCode = objEvent.keyCode;
    else if (objEvent.which)
      iKeyCode = objEvent.which;

    // 엔터나 스페이스가 아니라면 true를 반환해 사용자 도구가
    // 기본 동작을 계속 처리하도록 한다
    if (iKeyCode != 13 && iKeyCode != 32)
      return true;
  }

  bSuccess = window.open(objAnchor.href);

  // 새 창이 열리지 않았으면 브라우저의 기본 동작을 수행하도록 하여
  // 현재 창에 콘텐트를 표시한다
  if (!bSuccess)
    return true;

  // 새 창이 열렸으면 브라우저가 더 처리하지 않도록 한다
  return false;
}

참고 자료

참고 자료는 정보를 위해 제공되었을 뿐이므로, 내용을 지지하거나 동의한다는 뜻은 아니다.

테스트

절차

  1. 문서에 있는 각 링크를 동작시키고, 새 창이 열리는지 확인한다.

  2. 새 창을 여는 각 링크에서, 다음 절차를 완료했는지 확인한다:

    1. 링크에 새 창을 열 것이라는 사실이 나타나는가.

    2. 장치 독립적인 이벤트 핸들러를 사용했는가

    3. 새 창이 열리지 않는 경우 현재 창을 사용해 콘텐트를 표시하는가

기대 결과

  • 2번을 통과해야 한다.


SCR26: DOM에서 이벤트가 발생한 요소 바로 뒤에 동적인 콘텐트 삽입하기

적용

HTML, XHTML, 스크립트

이 기술과 관련있는 기술:

설명

이 기법의 목적은 DOM에 사용자 인터페이스 요소를 삽입할 때 사용자 도구의 기본 동작을 사용하게 하여 탭 순서나 화면 낭독기의 읽는 순서가 올바르게 위치하는 법을 보여주는 것에 있다. 이 기법은 메뉴나 대화창 등과 같이 숨겨졌다 나타나는 모든 사용자 인터페이스 요소에 적용할 수 있다.

화면 낭독기에서의 읽는 순서는 기본 탭 순서와 마찬가지로 DOM에서의 HTML 혹은 XHTML 요소에 기반한다. 이 기법은 스크립트를 실행하는 요소 바로 뒤에 새로운 콘텐트를 삽입한다. 이벤트가 실행되는 요소는 링크나 버튼일 것이며 스크립트는 이러한 요소의 onclick 이벤트를 통해 실행된다. 이러한 요소는 기본적으로 포커스를 가질 수 있고, 이들의 onclick 이벤트는 장치에 독립적이다. 이벤트가 발생하고 새로운 콘텐트를 만들어서 이벤트가 발생한 요소 뒤에 삽입하는 동안에도 포커스는 계속 유지되어 탭 순서나 화면 낭독기의 읽는 순서상 바로 다음 요소는 새로 작성한 요소가 된다.

이 기법은 동기 업데이트에서 동작한다는 사실에 주의하라. 비동기 업데이트(종종 AJAX라고 불린다)에서는 보조 기술에 비동기적으로 추가된 콘텐트를 알리기 위한 기술이 추가적으로 필요하다.

예제

예제 1

이 예제는 링크를 클릭하면 메뉴를 만들어서 링크 바로 뒤에 삽입한다. ShowHide 스크립트는 링크의 onclick 이벤트를 통해 실행되는데, 인수로 새 메뉴의 아이디를 전달받는다.

예제 코드:

<a href="#" onclick="ShowHide('foo',this)">보이기/감추기</a>

ShowHide 스크립트는 새 메뉴가 있는 div를 작성하고, 메뉴에 링크를 삽입한다. 마지막 줄이 스크립트의 핵심 부분인데, 스크립트를 실행하는 요소의 부모를 찾아 새로 작성한 div를 자식으로 추가한다. 이 덕분에 DOM에서 새로 작성한 div는 링크 뒤에 오게 된다. 사용자가 탭을 누르면 메뉴에서 포커스를 받을 수 있는 첫번째 요소인 링크로 포커스가 이동한다.

예제 코드:

function ShowHide(id,src)
{
	var el = document.getElementById(id);
	if (!el)
	{
		el = document.createElement("div");
		el.id = id;
		var link = document.createElement("a");
		link.href = "javascript:void(0)";
		link.appendChild(document.createTextNode("Content"));
		el.appendChild(link);
		src.parentElement.appendChild(el);
	}
	else
	{
		el.style.display = ('none' == el.style.display ? 'block' : 'none');
	}
}

CSS는 div와 링크가 메뉴처럼 보이게 꾸며준다.

테스트

절차

  1. 팝업이 아닌 대화창을 여는 페이지의 모든 영역을 찾는다.

  2. 버튼이나 링크의 click 이벤트를 통해 대화창이 표시되는지 확인한다.

  3. 스크립트로 생성한 DOM을 확인할 수 있는 도구를 사용해 대화창이 DOM에서 해당 영역 다음에 위치하는지 확인한다.

기대 결과

  • 2번과 3번을 통과해야 한다.


SCR27: 문서 객체 모델을 사용한 페이지 섹션의 재정렬

적용

HTML, XHTML, 스크립트

이 기술과 관련있는 기술:

설명

이 기법의 목적은 사용성과 접근성이 높은 컴포넌트 재정렬 방법을 제공하는 것에 있다. 가장 일반적으로 사용하는 두 가지 재정렬 메커니즘에는 사용자가 컴포넌트에 번호를 매길 수 있는 설정 페이지로 사용자를 이동시키는 것과 사용자가 컴포넌트를 원하는 위치로 옮길 수 있도록 드래그 앤 드롭 기능을 제공하는 것이 있다. 드래그 앤 드롭 방식이 훨씬 더 유용한데, 사용자가 바로 그 자리에서 한번에 하나씩 결과를 직접 보면서 항목을 정렬할 수 있기 때문이다. 불행히도 드래그 앤 드롭은 마우스에 종속적이다. 이 기법을 사용하면 사용자는 컴포넌트에 있는 메뉴를 사용하여 장치 독립적인 방식으로 항목을 재정렬할 수 있다. 이 기법은 또한 그 자리에서 혹은 드래그 앤 드롭 기능과 함께 사용할 수도 있다.

메뉴는 장치 독립적인 onclick 이벤트를 사용하는 링크의 목록인데, 이벤트를 통해 콘텐트를 재정렬하는 스크립트를 실행한다. 콘텐트는 (시각적으로는 물론) DOM에서의 순서가 재정렬되어 모든 장치에서 올바른 순서로 표현된다.

예제

예제 1

이 예제는 순서를 위 아래로 재정렬한다. 이러한 접근법은 좌우에 옵션을 추가하는 2차원 재정렬에도 사용할 수 있다.

이 예제의 컴포넌트들은 순서가 없는 목록에 속한 항목이다. 순서가 없는 목록은 이런 컴포넌트와 같이 유사한 항목들의 묶음을 표현할 때 매우 좋은 시맨틱 모델이다. 메뉴 접근 방식은 다른 방식의 그루핑에서도 사용할 수 있다.

모듈은 목록의 항목이며, 각 모듈은 div 요소안의 콘텐트와 더불어 중첩 목록으로 표현한 메뉴를 포함한다.

예제 코드:

<ul id="swapper">
    <li id="black">
        <div class="module">
            <div class="module_header">
                <!-- 메뉴 링크 -->
                <a href="#" onclick="ToggleMenu(event);">menu</a>
                <!-- 메뉴 -->
                <ul class="menu">
                    <li><a href="#" onclick="OnMenuClick(event)"
                        onkeypress="OnMenuKeypress(event);">up</a></li>
                    <li><a href="#" onclick="OnMenuClick(event)"
                        onkeypress="OnMenuKeypress(event);">down</a></li>
                </ul>
            </div>
            <div class="module_body">
                black 모듈의 텍스트
            </div>
        </div>
    </li>
    ...
</ul>

이미 간단한 트리 샘플에서 메뉴를 보여주고 숨기는 것에 대해 다룬 바 있기 때문에, 여기서는 모듈을 서로 교환하는 코드에만 집중한다. 일단 이벤트를 동기화한 뒤에는 링크의 기본 동작을 취소하고, 작업을 계속한다. 우선 다루어야 할 요소들(메뉴, 재정렬할 모듈, 메뉴 링크 등)을 위한 지역 변수를 선언한다. 다음으로 재정렬 방향을 확인한 후에, 바꿀 노드를 구한다. 노드를 하나 구한 다음에는 swapNode()를 호출하여 두 모듈의 위치를 바꾸고, PositionEleemnt()를 사용해 모듈을 따라 절대 위치값을 가진 메뉴를 이동시킨다. 그 뒤에는 메뉴 항목에 포커스를 준다.

예제 코드:

function MoveNode(evt,dir)
{
    HarmonizeEvent(evt);
    evt.preventDefault();

    var src = evt.target;
    var menu = src.parentNode.parentNode;
    var module = menu.parentNode.parentNode.parentNode;
    var menuLink = module.getElementsByTagName("a")[0];
    var swap = null;

    switch(dir)
    {
        case 'up':
        {
            swap = module.previousSibling;
            while (swap && swap.nodeType != 1)
            {
                swap = swap.previousSibling;
            }
            break;
        }
        case 'down':
        {
            swap = module.nextSibling;
            while (swap && swap.nodeType != 1)
            {
                swap = swap.nextSibling;
            }
            break;
        }
    }
    if (swap && swap.tagName == node.tagName)
    {
        module.swapNode(swap);
        PositionElement(menu,menuLink,false,true);
    }
    src.focus();
}

바뀌는 노드에 사용되는 CSS는 이전에 트리 샘플에서 사용된 것과 크게 다르지 않다. CSS는 모듈과 작은 메뉴에 사용할 크기와 색상을 조절한다.

예제 코드:

ul#swapper { margin:0px; padding:0px; list-item-style:none; }
ul#swapper li { padding:0; margin:1em; list-style:none; height:5em; width:15em;
    border:1px solid black; }
ul#swapper li a { color:white; text-decoration:none; font-size:90%; }

ul#swapper li div.module_header { text-align:right; padding:0 0.2em; }
ul#swapper li div.module_body { padding:0.2em; }

ul#swapper ul.menu { padding:0; margin:0; list-style:none; background-color:#eeeeee;
    height:auto; position:absolute; text-align:left; border:1px solid gray; display:none; }
ul#swapper ul.menu li { height:auto; border:none; margin:0; text-align:left;
    font-weight:normal; width:5em; }
ul#swapper ul.menu li a { text-decoration:none; color:black; padding:0 0.1em;
    display:block; width:100%; }

테스트

절차

  1. 드래드 앤 드롭을 사용해 순서를 정렬하는 모든 컴포넌트를 찾는다.

  2. 링크 목록으로 구성된 메뉴를 사용해 이들을 재정렬 할 수 있는 메커니즘이 있는지 확인한다.

  3. DOM에서 재정렬할 수 있는 항목에 메뉴가 포함되었는지 확인한다.

  4. 재정렬 스크립트가 링크의 onclick을 통해서만 실행되는지 확인한다.

  5. 항목들이 시각적으로는 물론 DOM에서도 재정렬되었는지 확인한다.

기대 결과

  • 2번부터 5번까지 통과해야 한다.


SCR28: 콘텐트 블럭을 건너뛰기 위한 접거나 펼칠 수 있는 메뉴 사용

적용

클라이언트측 스크립트를 제공하는 기술.

이 기술과 관련있는 기술:

설명

이 기법은 사용자가 접거나 펼칠 수 있는 메뉴에 반복되는 구성 요소를 배치하여 이 부분을 건너뛸 수 있게 한다. 사용자는 메뉴를 접어서 반복되는 구성 요소를 건너뛸 수 있다. 사용자는 사용자 인터페이스 콘트롤을 동작시켜 메뉴의 요소들을 숨기거나 제거한다. 참고 자료 섹션에서는 메뉴, 툴바, 트리 등 탐색을 건너뛰는 메커니즘을 제공하는 것들에 대한 여러가지 기법을 볼 수 있다.

주: 서버측 스크립트와 수정된 웹 페이지를 새로 읽어오는 방식으로 유사한 접근방법을 구현할 수 있다.

예제

예제 1

웹 페이지 상단의 탐색 링크는 HTML, CSS, 자바스크립트를 사용해서 모든 항목이 구현되었다. 탐색 메뉴가 펼쳐지면 사용자는 탐색 링크를 사용할 수 있다. 탐색 메뉴가 접혔을 때, 링크는 사용할 수 없다.

예제 코드:


...

  <script type="text/javascript">
  function toggle(id){
    var n = document.getElementById(id);
    n.style.display =  (n.style.display != 'none' ? 'none' : '' );
  }
  </script>

...

  <a href="#" onclick="toggle("navbar")">탐색 메뉴 보이기/감추기</a>

  <ul> id="navbar">
  <li><a href="http://target1.html">Link 1</a></li>
  <li><a href="http://target2.html">Link 2</a></li>
  <li><a href="http://target3.html">Link 3</a></li>
  <li><a href="http://target4.html">Link 4</a></li>
  </ul>

...

이 코드의 실제 동작 예제: 링크가 있는 탐색 메뉴 토글.

예제 2

한 무리의 웹 페이지에서 목차는 각 페이지 상단에 반복해서 나타난다. 목차 시작부의 버튼은 사용자가 목차를 감추거나 보일 수 있게 한다.

예제 코드:


...

   <script type="text/javascript">
  function toggle(id){
    var n = document.getElementById(id);
    n.style.display =  (n.style.display != 'none' ? 'none' : '' );
  }
  </script>

  ...

  <button onclick="return toggle('toc');">목차 보이기/감추기</button>
  <div id="toc">
    ...
  </div>

...

이 코드의 실제 동작 예제: 버튼을 사용한 목차 토글.

참고 자료

참고 자료는 정보를 위해 제공되었을 뿐이므로, 내용을 지지하거나 동의한다는 뜻은 아니다.

테스트

절차

  1. 사용자 인터페이스 콘트롤에 반복되는 콘텐트를 펼치거나 접는 기능이 있는지 확인한다.

  2. 콘텐트가 펼쳐졌을 때, 프로그램에서 해석할 수 있는 부분도 고려하여 읽는 순서대로 논리적인 위치에 있는지 확인한다.

  3. 콘텐트가 접혔을 때, 프로그램에서 해석할 수 있는 부분이 없는지 확인한다.

기대 결과

  • 모든 항목을 통과해야 한다.


SCR29: 정적인 HTML 요소에 키보드 접근성있는 동작 추가

적용

HTML과 XHTML, 스크립트

이 기술과 관련있는 기술:

사용자 도구와 보조 기술 지원

HTML 4.01에서는 a, area, button, input, object, select, textarea에만 tabindex 속성을 사용할 수 있으며, 값의 범위는 0부터 32767까지이다. Internet Explorer 5.01 이상, Firefox 1.5 이상, Opera 9.5 이상, Camino 브라우저에서는 다른 유형의 요소와 함께 tabindex를 사용할 수 있고, 값으로 -1을 가질 수 있다. 주의할 점은 스크립트를 통해 포커스를 수정하면 시각적인 커서를 사용하는 화면 낭독기에서는 예상치 못한 동작이 발생하는 원인이 될 수 있다는 것이다.

설명

이 기법의 목적은 divspan과 같이 정적인 HTML 요소에 액션을 붙여서 구현하는 사용자 인터페이스 콘트롤에 키보드 접근성을 부여하는 방법을 보여주는 것에 있다. 이 기법은 tabindex 속성을 설정해 HTML 요소가 포커스를 받을 수 있도록 하고, onclick 핸들러와 더불어 onkeyuponkeypress 핸들러를 추가해 키보드로 스크립트를 실행할 수 있게 한다.

tabindex 속성의 값이 0이면, HTML 요소는 키보드를 통해 포커스를 받을 수 있으며 문서의 탭 이동 순서에 포함된다. tabindex 속성의 값이 -1이면, HTML 요소는 element.focus()를 통해 프로그램으로는 포커스를 줄 수 있으나 탭을 사용해서 포커스를 줄 수는 없다.

정적인 HTML 요소는 기본 동작을 가지고 있지 않기 때문에, 스크립트를 사용할 수 없는 환경을 위한 대비책이나 설명을 제공할 수 없다. 이 기법은 클라이언트측 스크립트를 실행할 수 있는 환경에서만 사용할 수 있다.

주: 이런 사용자 인터페이스 콘트롤들은 성공 기준 4.1.2를 반드시 만족시켜야 한다. 역할(role), 이름(name), 상태 정보를 제공하지 않고 이 기법을 적용하면 F59 : div와 span을 사용자 인터페이스로 만드는 스크립트의 사용으로 인한 성공 기준 4.1.2 미달의 사유가 된다.

예제

예제 1: div 요소에 자바스크립트 동작 추가하기

웹 페이지의 div 요소는 고유한 id 속성과 값이 0인 tabindex 속성을 가진다. 스크립트에서는 문서 객체 모델(Document Object Model, DOM)을 사용해 아이디로 div 요소를 찾고, 요소에 onclick 핸들러와 onkeyup 핸들러를 추가한다. 엔터키가 눌려지면 onkeyup에서 동작을 실행한다. div 요소는 이를 찾고 수정하기 전에 DOM에 읽혀져있어야 한다. 그래서 body 요소의 onload 이벤트를 통해 스크립트를 호출하는 방법이 일반적으로 사용된다. 이벤트 핸들러를 추가하는 스크립트는 사용자 도구에서 이벤트 핸들러를 지원하고 자바스크립트를 사용할 수 있는 경우에만 실행된다.

예제 코드:


...
<script type="text/javascript">
 // 동작을 수행하는 함수. 메시지를 토글한다.
 function doSomething(event) {
   var msg=document.getElementById("message");
   msg.style.display = msg.style.display=="none" ? "" : "none";
   // 링크의 href를 따라 이동하지 않도록 false를 반환한다.
   return false;
 }
 // 엔터키가 눌렸을 때 동작을 수행하는 함수
 function doSomethingOnEnter(event) {
   var key = 0;
   // window.event나 event 객체에서 눌려진 키를 가져온다
   if (window.event) {
     key = window.event.keyCode;
   } else if (event) {
     key = event.keyCode;
   }
   // 눌려진 키가 엔터키인가?
   if (key == 13) {
     return doSomething(event);
   }
   // 이벤트를 처리하지 않았으면 true를 반환한다.
   return true;
 }
 // setUpActions() 함수는 이미 존재하는 div 요소에 onclick, onkeyup 이벤트를 설정할 때 호출한다.
 // 이 함수는 id="active"인 div 요소를 DOM에 읽어들인 후에 호출해야 한다.
 // 이 예제에서 setUpActions() 함수는 body 요소의 onload 이벤트에서 호출된다.
 function setUpActions() {
   // div 객체를 얻는다
   var active=document.getElementById("active");
   // onclick 핸들러를 객체에 할당한다.
   // onclick 이벤트 핸들러에서 함수가 실행된 후에 href 속성을 따라 이동하지 않게 하기 위해
   // false를 반환하는 것이 중요하다.
   active.onclick=doSomething;
   // onkeyup 핸들러를 객체에 할당한다.
   active.onkeyup=doSomethingOnEnter;
 }
 </script>

 <body onload="setUpActions();">
 <p>Here is the link to modify with a javascript action:</p>
 <div>
  <span id="active" tabindex="0">Do Something</span>
 </div>
 <div id="message">Hello, world!</div>
...

참고 자료

참고 자료는 정보를 위해 제공되었을 뿐이므로, 내용을 지지하거나 동의한다는 뜻은 아니다.

테스트

절차

스크립트를 지원하는 사용자 도구에서:

  1. 콘트롤을 마우스로 클릭한다.

  2. 스크립트 동작이 정상적으로 실행되는지 확인한다.

  3. 키보드를 통해 콘트롤로 탐색하고 포커스를 줄 수 있는지 확인한다.

  4. 키보드를 사용해 콘트롤에 포커스를 준다.

  5. 엔터를 눌러 스크립트 동작이 실행되는지 확인한다.

기대 결과

  • 모든 항목을 통과해야 한다.


SCR30: 스크립트를 사용해 링크 텍스트 변경

적용

HTML과 XHTML에서 사용하는 클라이언트측 스크립트

이 기술과 관련있는 기술:

설명

이 기법은 사용자가 링크 텍스트에 추가할 정보를 선택하여 문맥을 참고하지 않아도 링크를 이해할 수 있도록 하는 것이 목적이다.

어떤 사용자들은 굳이 문맥을 참조하지 않아도 되도록 링크에 모두 포함해두는 것을 좋아한다. 다른 사용자들은 문맥 정보에서 반복되는 부분을 찾아내어 가능한 줄인다. 보조 기술 사용자들 사이에서는 어느쪽이 더 좋은지에 대해 의견이 분분하다. 이 기법은 사용자가 자신에게 가장 좋은 방식을 선택하도록 한다.

페이지 상단에 있는 링크는 링크 텍스트를 확장해서 어떤 링크인지 이해하기 위한 문맥을 별도로 필요치 않는다. 확장한 링크는 항상 링크의 링크 텍스트 만으로도 그 목적을 충분히 이해할 수 있어야 한다.

이 기법은 현재 보고 있는 페이지의 링크만 확장한다. 사용자의 설정을 쿠키나 서버측 사용자 프로필에 저장하여 사용자가 처음 한번만 선택하면 되도록 하는 기법도 사용할 수 있는데, 때때로 이런 방식이 바람직할 때도 있다.

예제

예제 1

이 예제는 링크의 텍스트에 문맥 정보를 직접 추가하는 자바스크립트를 사용한다. 추가 정보를 더할 링크를 구분하기 위해 클래스를 사용되었다. "Expand Links" 링크를 선택하면 페이지에 있는 모든 링크에 대해 추가 정보를 추가할지 말지 테스트한다.

예제 코드:


...
<script>
 var linkContext = {
   "hist":" version of The History of the Web",
   "cook":" version of Cooking for Nerds"
 };

 function doExpand() {
   var links = document.links;
   var link;

   for (link in links) {
     var cn = links[link].className;
     if (linkContext[cn]) {
       links[link].appendChild(document.createTextNode(linkContext[cn]));
     }
   }
 }
</script>

<h1>Books for download</h1>
<p><a href="#" onclick="doExpand();">Expand Links</a></p>

<ul>
<li>The History of the Web:
<a href="history.docx" class="hist">Word</a>,
<a href="history.pdf" class="hist">PDF</a>,
<a href="history.html" class="hist">HTML</a>
</li>

<li>Cooking for Nerds:
<a href="history.docx" class="cook">Word</a>,
<a href="history.pdf" class="cook">PDF</a>,
<a href="history.html" class="cook">HTML</a>
</li>
</ul>

...

테스트

절차

  1. 페이지 시작부에 확장할 링크가 있는지 확인한다.

  2. 1단계에서 찾은 링크가 링크라면, 링크 텍스트만으로도 식별할 수 있는지 확인한다.

  3. 링크 텍스트만으로 식별할 수 없는 링크를 찾는다.

  4. 1단계에서 찾은 콘트롤을 작동시킨다.

  5. 3단계에서 찾은 링크들이 가진 목적을 링크 텍스트 만으로도 식별할 수 있는지 확인한다.

기대 결과

  • 1, 2, 5번을 모두 통과해야 한다.


SCR31: 포커스를 가진 요소의 배경색이나 경계선을 바꾸는 스크립트 사용

적용

HTML과 XHTML, CSS, 스크립트

이 기술과 관련있는 기술:

사용자 도구와 보조 기술 지원

이 기법은 :focus 가상클래스를 지원하지 않지만 스크립트는 지원하는 Microsoft Internet Explorer와 같은 사용자 도구에서 사용할 수 있다.

설명

이 기법의 목적은 자바스크립트를 사용해 CSS를 적용하여 평상시보다 포커스를 시각적으로 더 잘 보이게 만드는 것에 있다. HTML 요소가 포커스를 받을 때 배경색이나 경계선 색을 바꿔 요소를 눈에 띄게 만든다. HTML 요소가 포커스를 잃으면 보통 모양으로 돌아온다. 이 기법은 :focus 가상클래스 지원 여부와 상관없이 스크립트와 cSS를 지원하는 HTML에서 사용할 수 있다.

예제

예제 1

이 예제에서 링크가 포커스를 받으면 배경색이 노랑으로 바뀐다. 포커스를 읽으면 노란색이 사라진다. 링크가 시작할 때부터 배경색을 가지고 있으면 스크립트에서 "" 대신 그 색상을 사용해야 한다.

예제 코드:


...
<script>
 function toggleFocus(el)
 {
  el.style.backgroundColor =  el.style.backgroundColor=="yellow" ? "inherit" : "yellow";
 }
</script>

...

<a href="example.html" onfocus="toggleFocus(this)" onblur="toggleFocus(this)">focus me</a>
...

테스트

절차

  1. 탭을 눌러 각 요소로 이동한다.

  2. 포커스 받은 객체가 보이는지 확인한다.

기대 결과

  • 2번을 통과해야 한다.


SCR32: DOM을 통한 클라이언트측 유효성 검사 제공과 에러 메시지 추가

적용

HTML이나 XHTML에서 사용하는 스크립트

이 기술과 관련있는 기술:

설명

이 기법의 목적은 폼 필드가 유효성 검사를 통과하지 못했을 때 에러 메시지를 표시하는 방법을 보여주는 것이다. 앵커 요소는 목록에서 에러 메시지를 표시하기 위해 사용되고, 유효성을 검사한 필드 위에 삽입된다. 에러 메시지에서 앵커 요소를 사용하므로 에러 메시지에 포커스를 줄 수 있고, 사용자의 주의를 에러 메시지로 끌 수 있다. 앵커 요소의 href는 에러가 발생한 필드를 참조하는 링크를 가리킨다.

배포된 애플리케이션에서는 자바스크립트가 꺼져있으면 클라이언트측 유효성 검사가 동작하지 않는다. 따라서 이 기법은 스크립트가 표준 준수면에서 신뢰할만 하거나 서버측 유효성 검사를 사용해 에러를 찾고 에러가 발생한 필드에 대한 정보가 있는 페이지를 반환하는 경우에만 충분하다 할 수 있다.

예제

예제 1

이 예제는 필드가 필수인지 필드에 입력된 값이 특정한 형식에 맞는지 유효성을 검사한다. 에러가 발견되면 스크립트는 DOM에 에러 메시지 목록을 삽입하고, 에러 메시지로 포커스를 이동한다.

Screenshot showing the error messages for several fields that were not filled out correctly. Error messages appear as a list of links near the top of the form.

HTML과 자바스크립트 코드

다음은 폼 예제 HTML이다:

예제 코드:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title>Form Validation</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <link href="css/validate.css" rel="stylesheet" type="text/css"/>
        <script type="text/javascript" src="scripts/validate.js"/>
    </head>
    <body>

        <h1>Form Validation</h1>

        <p>The following form is validated before being submitted if scripting is available,
            otherwise the form is validated on the server. All fields are required, except those
            marked optional. If errors are found in the submission, the form is cancelled and
            a list of errors is displayed at the top of the form.</p>

        <p> Please enter your details below. </p>

        <h2>Validating Form</h2>

        <form id="personalform" method="post" action="index.php">
            <div class="validationerrors"/>
            <fieldset>
                <legend>Personal Details</legend>
                <p>
                    <label for="forename">Please enter your forename</label>
                    <input type="text" size="20" name="forename" id="forename" class="string"
                        value=""/>
                </p>
                <p>
                    <label for="age">Please enter your age</label>
                    <input type="text" size="20" name="age" id="age" class="number" value=""/>
                </p>
                <p>
                    <label for="email">Please enter your email address</label>
                    <input type="text" size="20" name="email" id="email" class="email" value=""/>
                </p>
            </fieldset>
            <p>
                <input type="submit" name="signup" value="Sign up"/>
            </p>
        </form>
        <h2>Second Form</h2>
        <form id="secondform" method="post" action="index.php#focuspoint">
            <div class="validationerrors"/>
            <fieldset>
                <legend>Second Form Details</legend>
                <p>
                    <label for="suggestion">Enter a suggestion</label>
                    <input type="text" size="20" name="suggestion" id="suggestion"
                      class="string" value=""/>
                </p>
                <p>
                    <label for="optemail">Please enter your email address (optional)</label>
                    <input type="text" size="20" name="optemail" id="optemail"
                        class="optional email" value=""/>
                </p>
                <p>
                    <label for="rating">Please rate this suggestion</label>
                    <input type="text" size="20" name="rating" id="rating"
                      class="number" value=""/>
                </p>
                <p>
                    <label for="jibberish">Enter some jibberish (optional)</label>
                    <input type="text" size="20" name="jibberish" id="jibberish" value=""/>
                </p>

            </fieldset>
            <p>
                <input type="submit" name="submit" value="Add Suggestion"/>
            </p>
        </form>
    </body>
</html>                      

다음은 유효성을 검사하고 에러 메시지를 삽입하는 자바스크립트이다.

예제 코드:


window.onload = initialise;

function initialise()
{
   var objForms = document.getElementsByTagName('form');
   var iCounter;

   // 각 폼에 이벤트 핸들러를 추가한다
   for (iCounter=0; iCounter<objForms.length; iCounter++)
   {
      objForms[iCounter].onsubmit = function(){return validateForm(this);};
   }
}


// 폼에 사용할 이벤트 핸들러
function validateForm(objForm)
{
   var arClass = [];
   var iErrors = 0;
   var objField = objForm.getElementsByTagName('input');
   var objLabel = objForm.getElementsByTagName('label');
   var objList = document.createElement('ol');
   var objError, objExisting, objNew, objTitle, objParagraph, objAnchor, objPosition;
   var strLinkID, iFieldCounter, iClassCounter, iCounter;

   // 폼의 id나 name을 얻어서 고유한 식별자를 만든다.
   if (objForm.id)
   {
      strLinkID = objForm.id + 'ErrorID';
   }
   else
   {
      strLinkID = objForm.name + 'ErrorID';
   }

   // 입력 콘트롤에 루프를 실행하여 유효성 검사 클래스를 찾는다
   for (iFieldCounter=0; iFieldCounter<objField.length; iFieldCounter++)
   {
      // 필드의 클래스를 얻고 적절한 클래스가 있는지 찾는다
      arClass = objField[iFieldCounter].className.split(' ');
      for (iClassCounter=0; iClassCounter<arClass.length; iClassCounter++)
      {
         switch (arClass[iClassCounter])
         {
            case 'string':
               if (!isString(objField[iFieldCounter].value, arClass))
               {
                  if (iErrors === 0)
                  {
                     logError(objField[iFieldCounter], objLabel, objList, strLinkID);
                  }
                  else
                  {
                     logError(objField[iFieldCounter], objLabel, objList, '');
                  }
                  iErrors++;
               }
               break;
            case 'number':
               if (!isNumber(objField[iFieldCounter].value, arClass))
               {
                  if (iErrors === 0)
                  {
                     logError(objField[iFieldCounter], objLabel, objList, strLinkID);
                  }
                  else
                  {
                     logError(objField[iFieldCounter], objLabel, objList, '');
                  }
                  iErrors++;
               }
               break;

            case 'email' :
               if (!isEmail(objField[iFieldCounter].value, arClass))
               {
                  if (iErrors === 0)
                  {
                     logError(objField[iFieldCounter], objLabel, objList, strLinkID);
                  }
                  else
                  {
                     logError(objField[iFieldCounter], objLabel, objList, '');
                  }
                  iErrors++;
               }
               break;
         }
      }
   }

   if (iErrors > 0)
   {
      // 유효하지 않다면 에러 메시지를 표시한다
      objError = objForm.getElementsByTagName('div');

      // 이미 존재하는 에러를 찾는다
      for (iCounter=0; iCounter<objError.length; iCounter++)
      {
         if (objError[iCounter].className == 'validationerrors')
         {
            objExisting = objError[iCounter];
         }
      }

      objNew = document.createElement('div');
      objTitle = document.createElement('h2');
      objParagraph = document.createElement('p');
      objAnchor = document.createElement('a');

      if (iErrors == 1)
      {
         objAnchor.appendChild(document.createTextNode('1개의 에러가 전송 중에 발생했습니다'));
      }
      else
      {
         objAnchor.appendChild(document.createTextNode(iErrors + '개의 에러가 전송 중에 발생했습니다'));
      }
      objAnchor.href = '#' + strLinkID;
      objAnchor.className = 'submissionerror';

      objTitle.appendChild(objAnchor);
      objParagraph.appendChild(document.createTextNode('다음 사항을 확인해주세요'));
      objNew.className = 'validationerrors';

      objNew.appendChild(objTitle);
      objNew.appendChild(objParagraph);
      objNew.appendChild(objList);

      // 에러가 있다면 새로운 것들로 이들을 대체하고,
      // 없다면 새로운 에러를 폼의 시작부에 추가한다.
      if (objExisting)
      {
         objExisting.parentNode.replaceChild(objNew, objExisting);
      }
      else
      {
         objPosition = objForm.firstChild;
         objForm.insertBefore(objNew, objPosition);
      }

      // 지연
      setTimeout(function() { objAnchor.focus(); }, 50);

      // 폼을 전송하지 않는다
      objForm.submitAllowed = false;
      return false;
   }

   // 폼 전송
   return true;
}

// 목록 항목에 문제가 발생한 필드 콘트롤을 가리키는 링크를 추가하는 함수
function addError(objList, strError, strID, strErrorID)
{
   var objListItem = document.createElement('li');
   var objAnchor = document.createElement('a');

   // 폼 콘트롤을 가리키는 식별자
   objAnchor.href='#' + strID;

   // 에Ÿ¬ 제목을 위한 링크의 대상으로 만든다.
   if (strErrorID.length > 0)
   {
      objAnchor.id = strErrorID;
   }

   // 에러 메시지를 알려주는 라벨 사용
   objAnchor.appendChild(document.createTextNode(strError));
   // 폼 콘트롤에 포커스를 줄 수 있는 키보드와 마우스 이벤트 추가
   objAnchor.onclick = function(event){return focusFormField(this, event);};
   objAnchor.onkeypress = function(event){return focusFormField(this, event);};
   objListItem.appendChild(objAnchor);
   objList.appendChild(objListItem);
}

function focusFormField(objAnchor, objEvent)
{
   var strFormField, objForm;

   // 링크를 통한 키보드 탐색 허용
   if (objEvent && objEvent.type == 'keypress')
   {
      if (objEvent.keyCode != 13 && objEvent.keyCode != 32)
      {
         return true;
      }
   }

   // 폼 콘트롤에 포커스 주기
   strFormField = objAnchor.href.match(/[^#]\w*$/);
   objForm = getForm(strFormField);
   objForm[strFormField].focus();
   return false;
}

// 필드 이름에 해당하는 폼 요소를 반환하는 함수
function getForm(strField)
{
   var objElement = document.getElementById(strField);

   // 적절한 폼을 찾는다
   do
   {
      objElement = objElement.parentNode;
   } while (!objElement.tagName.match(/form/i) && objElement.parentNode);

   return objElement;
}

// 목록에 에러를 기록하는 함수
function logError(objField, objLabel, objList, strErrorID)
{
   var iCounter, strError;

   // 에러 알림을 위한 라벨 찾기
   for (iCounter=0; iCounter<objLabel.length; iCounter++)
   {
      if (objLabel[iCounter].htmlFor == objField.id)
      {
         strError = objLabel[iCounter].firstChild.nodeValue;
      }
   }

   addError(objList, strError, objField.id, strErrorID);
}

// 유효성 검사 루틴들 - 필요에 따라 추가

function isString(strValue, arClass)
{
   var bValid = (typeof strValue == 'string' && strValue.replace(/^\s*|\s*$/g, '')
     !== '' && isNaN(strValue));

   return checkOptional(bValid, strValue, arClass);
}

function isEmail(strValue, arClass)
{
   var objRE = /^[\w-\.\']{1,}\@([\da-zA-Z\-]{1,}\.){1,}[\da-zA-Z\-]{2,}$/;
   var bValid = objRE.test(strValue);

   return checkOptional(bValid, strValue, arClass);
}

function isNumber(strValue, arClass)
{
   var bValid = (!isNaN(strValue) && strValue.replace(/^\s*|\s*$/g, '') !== '');

   return checkOptional(bValid, strValue, arClass);
}

function checkOptional(bValid, strValue, arClass)
{
   var bOptional = false;
   var iCounter;

   // 선택적일 때만 확인
   for (iCounter=0; iCounter<arClass.length; iCounter++)
   {
      if (arClass[iCounter] == 'optional')
      {
         bOptional = true;
      }
   }

   if (bOptional && strValue.replace(/^\s*|\s*$/g, '') === '')
   {
      return true;
   }

   return bValid;
   }
   

PHP, 자바스크립트, CSS, XHTML로 작성된 실제 동작하는 예제는 폼 유효성 검사 예제에서 볼 수 있다.

테스트

절차

위의 기술을 통해 앵커 태그와 적절한 스크립트를 사용해 에러 메시지를 작성한다.

  1. 페이지를 읽어들인다.

  2. 에러 메시지가 표시되지 않은, 검증이 필요하고 에러 메시지와 연관된 필드에 유효한 값을 입력한다.

  3. 에러 메시지와 연관된 필드에 유효하지 않은 값을 입력하고 필드에 맞는 올바른 에러 메시지가 나타나는지 확인한다.

  4. 에러 메시지가 포커스를 받는지 확인한다.

  5. 나타난 에러 메시지와 연관된 필드에 올바른 값을 입력하고 에러 메시지가 사라지는지 확인한다.

  6. 앵커 태그를 통해 작성된 에러 메시지들과 연관된 모든 필드에 앞의 과정을 반복한다.

주: 위의 과정을 보조 기술을 사용해서도 실행해볼 것을 권장한다.

기대 결과

  • 2, 3, 4, 5번을 모두 통과해야 한다.


SCR33: 콘텐트를 스크롤하는 스크립트 사용과 스크롤을 멈추는 메커니즘 제공

적용

스크립트에 의한 콘텐트 스크롤을 지원하는 기술

이 기술과 관련있는 기술:

설명

이 기법은 스크립트에서 콘텐트를 스크롤할 때 사용자가 스크롤을 멈출 수 있는 방법을 제공하는 것을 목표로 한다. 저시력자나 인지장애가 있는 사람들은 스크롤되는 콘텐트를 읽기 어렵거나 혹은 아예 읽지 못할 수 있다. 또 어떤 사람들에게 있어 콘텐트의 이동은 웹 페이지의 다른 부분에 집중하지 못하게 방해가 될 수 있다.

예제

예제 1

이 예제는 스크롤 형식으로 텍스트를 표현하기 위해 CSS와 자바스크립트를 사용한다. 스크롤 이동을 멈추기 위해 링크를 포함했다.

자바스크립트나 CSS를 지원하지 않거나 사용할 수 없을 때는 전체 텍스트를 보여주고 링크를 생략한다.

다음 코드는 webSemantic의 접근성있는 스크롤러(2008년 7월)를 수정한 것이다.

XHTML 부분:

예제 코드:


...
<div id="scroller">
<p id="tag">This text will scroll and a Pause/Scroll link will be present
when Javascript and CSS are supported and active.</p>
</div>
...

CSS 부분:

예제 코드:


...
body {font:1em verdana,sans-serif; color:#000; margin:0}

/* position:relative와 overflow:hidden은 꼭 필요하다 */
#scroller { position:relative; overflow:hidden; width:15em; border:1px solid #008080; }

/* 스크롤되는 텍스트 꾸미기 */
#tag { margin:2px 0; }

/* #testP은 #tag의 모든 텍스트 크기 속성을 포함해야 한다. */
#testP { visibility:hidden; position:absolute; white-space:nowrap; }

/* 페이지 상단 마커로 사용하고 너비를 제한한다 */
#top { width:350px; margin:auto; }
...

다음은 자바스크립트 부분이다:

예제 코드:


var speed=50        // 스크롤 속도
var step=3          // 이동의 부드러움
var StartActionText= "Scroll"  // 시작 링크 텍스트
var StopActionText = "Pause"   // 멈춤 링크 스트

var x, scroll, divW, sText=""

function onclickIE(idAttr,handler,call){
  if ((document.all)&&(document.getElementById)){idAttr[handler]="javascript:"+call}
}

function addLink(id,call,txt){
  var e=document.createElement('a')
  e.setAttribute('href',call)
  var linktext=document.createTextNode(txt)
  e.appendChild(linktext)
  document.getElementById(id).appendChild(e)
}

function getElementStyle() {
    var elem = document.getElementById('scroller');
    if (elem.currentStyle) {
        return elem.currentStyle.overflow;
    } else if (window.getComputedStyle) {
        var compStyle = window.getComputedStyle(elem, '');
        return compStyle.getPropertyValue("overflow");
    }
    return "";
}

function addControls(){
// 먼저 CSS 지원을 테스트한다.
// style 요소나 외부 파일에서 설정된 overflow 값을 테스트한다.
if (getElementStyle()=="hidden") {
  var f=document.createElement('div');
  f.setAttribute('id','controls');
  document.getElementById('scroller').parentNode.appendChild(f);
  addLink('controls','javascript:clickAction(0)',StopActionText);
  onclickIE(document.getElementById('controls').childNodes[0],"href",'clickAction(0)');
  document.getElementById('controls').style.display='block';
  }
}

function stopScroller(){clearTimeout(scroll)}

function setAction(callvalue,txt){
  var c=document.getElementById('controls')
  c.childNodes[0].setAttribute('href','javascript:clickAction('+callvalue+')')
  onclickIE(document.getElementById('controls').childNodes[0],"href",'clickAction

('+callvalue+')')
  c.childNodes[0].firstChild.nodeValue=txt
}

function clickAction(no){
  switch(no) {
    case 0:
      stopScroller();
      setAction(1,StartActionText);
      break;
    case 1:
      startScroller();
      setAction(0,StopActionText);
  }
}

function startScroller(){
  document.getElementById('tag').style.whiteSpace='nowrap'
  var p=document.createElement('p')
  p.id='testP'
  p.style.fontSize='25%' //모질라 계열을 위한 버그 수정. 사용 전에 4배 확대한다
  x-=step
  if (document.getElementById('tag').className) p.className=document.getElementById

('tag').className
  p.appendChild(document.createTextNode(sText))
  document.body.appendChild(p)
  pw=p.offsetWidth
  document.body.removeChild(p)
  if (x<(pw*4)*-1){x=divW}
  document.getElementById('tag').style.left=x+'px'
  scroll=setTimeout('startScroller()',speed)
}

function initScroller(){
  if (document.getElementById && document.createElement && document.body.appendChild) {
    addControls();
    divW=document.getElementById('scroller').offsetWidth;
    x=divW;
    document.getElementById('tag').style.position='relative';
    document.getElementById('tag').style.left=divW+'px';
    var ss=document.getElementById('tag').childNodes;
    for (i=0;i<ss.length;i++) {sText+=ss[i].nodeValue+" "};
    scroll=setTimeout('startScroller()',speed);
  }
}

function addLoadEvent(func) {
  if (!document.getElementById | !document.getElementsByTagName) return
  var oldonload = window.onload
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      oldonload()
      func()
    }
  }
}

addLoadEvent(initScroller)

참고 자료

참고 자료는 정보를 위해 제공되었을 뿐이므로, 내용을 지지하거나 동의한다는 뜻은 아니다.

테스트

절차

  1. 스크롤되는 콘텐트를 일시정지 할 수 있는 메커니즘을 제공하는지 확인한다.

  2. 스크롤되는 콘텐트를 일시정지 할 수 있는 메커니즘을 사용해 움직임을 멈춘다.

  3. 스크롤이 멈추고 스스로 다시 시작하지 않는지 확인한다.

  4. 일시정지된 콘텐트를 다시 시작할 수 있는 메커니즘이 있는지 확인한다.

  5. 콘텐트를 다시 스크롤 할 수 있는 메커니즘을 사용해 스크롤을 다시 시작한다.

  6. 멈추었던 시점에서부터 스크롤이 재개되는지 확인한다.

기대 결과

  • 3번과 6번을 통과해야 한다.


SCR34:텍스트 크기에 따라 변경된 사이즈의 크기와 위치 계산

적용

클라이언트측 스크립트.

이 기술과 관련있는 기술:

사용자 도구와 보조 기술 지원

크기와 위치를 계산하는 것은 복잡할 수 있으며, 브라우저에 따라 결과가 다를 수 있다. 이런 문제는 객체의 padding, margin, width 등을 혼합해서 CSS로 꾸미거나 offsetWidth와 width처럼 오프셋(offset)과 평범한 값을 섞어서 쓸 때 발생한다. 이런 동작 중 일부는 줌 했을 때 실행하면 다르게 동작하기도 한다. Internet Explorer 6 이상과 그 이전 버전이 어떻게 다른지 확인하려면 MSDN: Fix the Box Instead of Thinking Outside It 문서를 확인하라.

설명

이 기법은 텍스트 크기가 변하는 것에 따라 크기가 바뀔 HTML 요소의 크기와 위치를 계산하는 것을 목표로 한다.

자바스크립트에는 HTML 요소의 크기와 위치를 얻을 수 있는 4가지 속성이 있다.

  • offsetHeight (요소의 픽셀 단위 높이)

  • offsetWidth (요소의 픽셀 단위 너비)

  • offsetLeft (부모 요소(offsetParent) 좌측으로부터의 픽셀 단위 거리)

  • offsetTop (부모 요소(offsetParent) 상단으로부터의 픽셀 단위 거리)

객체의 높이와 너비는 offsetHeightoffsetWidth를 사용하면 바로 구할 수 있지만, 객체의 좌측과 상단 위치의 절대 값을 계산하려면 부모 위치도 고려해야 한다. The calculatePosition 함수는 요소의 부모 노드들을 계속 탐색하며 최종값을 구한다. 인수로는 값을 구할 요소인 objElement와 구할 offset 속성인 strOffset를 전달받는다. strOffsetoffsetLeft이나 offsetTop 중에 하나의 값이다.

예제

예제 1

자바스크립트 함수:

예제 코드:


function calculatePosition(objElement, strOffset)
{
    var iOffset = 0;

    if (objElement.offsetParent)
    {
        do
        {
            iOffset += objElement[strOffset];
            objElement = objElement.offsetParent;
        } while (objElement);
    }

    return iOffset;
}

다음 예제는 위 함수를 사용하여 참조 객체 아래에 있는 객체를 왼쪽으로부터 같은 거리에 정렬한다.

예제 코드:


// 참조 객체 얻기
var objReference = document.getElementById('refobject');
// 정렬할 객체 얻기
var objAlign = document.getElementById('lineup');

objAlign.style.position = 'absolute';
objAlign.style.left = calculatePosition(objReference, 'offsetLeft') + 'px';
objAlign.style.top = calculatePosition(objReference, 'offsetTop') + objReference.offsetHeight + 'px';

참고 자료

참고 자료는 정보를 위해 제공되었을 뿐이므로, 내용을 지지하거나 동의한다는 뜻은 아니다.

테스트

절차

  1. 글자 크기가 변하면 컨테이너의 크기를 조정하도록 설계된 페이지를 연다.

  2. 브라우저의 텍스트 조절 기능을 사용해 텍스트의 크기를 200%로 키운다(줌 기능 아님).

  3. 텍스트 컨테이너가 텍스트 사이즈를 수용하도록 조절되는지 텍스트를 시험한다.

  4. 텍스트를 키웠을 때 잘리거나(clipped) 사라지는 텍스트가 없는지 확인한다.

기대 결과

  • 3번과 4번을 통과해야 한다.


SCR35: 앵커와 버튼의 onclick 이벤트를 사용해 동작에 키보드 접근성 더하기

적용

HTML이나 XHTML에서 사용하는 스크립트

이 기술과 관련있는 기술:

설명

이 기법의 목적은 키보드로 접근할 수 있는 콘트롤에 스크립트를 추가해 키보드 접근성 있게 스크립트를 실행하는 법을 보여준다. 키보드를 사용해 스크립트를 실행하기 위해 "원래 접근성있는" HTML 요소(링크와 버튼)를 사용했다. 이러한 요소의 onclick 이벤트는 장치에 독립적이다. "onclick"이라는 단어가 마우스에 한정된 것으로 보이지만, 사실 onclick 이벤트는 링크나 버튼의 기본 동작과도 매핑되어있다.기본 동작은 사용자가 해당 요소에 포커스를 주고 엔터 또는 스페이스를 입력하거나 접근성 API를 통해 해당 요소에 접근하고 동작시킬 때도 실행된다.

이 기법은 클라이언트측 스크립트를 필요로 하지만 스크립트를 사용할 수 없는 환경을 위한 대비책이나 설명을 제공해주면 좋다. 자바스크립트를 실행하는 앵커 요소를 사용하면, href 속성을 통해 대비책이나 설명을 제공할 수 있다. 버튼을 사용하면 폼 전송을 통해 제공한다.

예제

예제 1

스크립트를 실행하는 링크는 스크립트를 실행할 수 없는 브라우저를 위한 대비책(fallback)이 없다. 이러한 접근법은 접근성을 지원하는 기술로서 스크립트에 의존하는 경우에만 사용할 수있다.

링크로 탐색하기를 원하지 않더라도 이 링크를 실제 링크로 만들고 올바르게 이벤트가 동작하도록 하기 위해 a 요소에 href 속성을 반드시 사용해야 한다. 이 경우에 우리는 링크의 목적지로 "#"을 사용했지만, 원한다면 뭐든 사용할 수 있다. 이 링크는 탐색에 사용되지 않는다.

doStuff() 이벤트 핸들링 함수 끝의 "return false;"는 브라우저가 URI로 탐색하지 않도록 한다. 이 코드가 없다면 스크립트가 실행된 후에 이 페이지를 새로 고친다.

예제 코드:


<script>
function doStuff()
 {
  // 작업을 실행한다
    return false;
  }
</script>
<a href="#" onclick="return doStuff();">do stuff</a>

예제 2

링크는 스크립트를 실행하지만, 스크립트를 사용할 수 없는 경우에는 다른 페이지로 이동한다. 이러한 접근 방식은 스크립트에 의존하지 않는 사이트에서 이동할 페이지에서 스크립트와 같은 기능을 제공하는 경우에 사용할 수 있다. 이 예제는 예제 1과 동일하지만, href에 dostuff.htm이라는 실제 페이지를 설정했다는 점이 다르다. dostuff.htm은 스크립트와 동일한 기능을 제공한다. doStuff() 이벤트 핸들링 함수의 끝에 있는 "return false;"는 브라우저가 URI를 탐색하지 않도록 한다. 이 코드가 없다면 브라우저는 스크립트가 실행된 후에 dostuff.htm으로 이동한다.

예제 코드:


<script>
function doStuff()
 {
  // 작업을 실행한다
  return false;
 }
</script>
<a href="dostuff.htm" onclick="return doStuff();">do stuff</a>

이 코드의 실제 동작하는 예제는 자바스크립트를 사용한 액션 링크 작성에서 볼 수 있다.

예제 3

버튼은 스크립트를 실행하고 스크립트를 사용할 수 없는 사용자를 위해 폼을 전송하는 대비책(fallback)을 제공한다. 이러한 접근법은 스크립트에 의존하지 않는 사이트에서 폼 전송이 스크립트와 같은 기능을 제공하는 경우에 사용할 수 있다. onsubmit="return false;"는 폼이 전송되는 것을 방지한다.

예제 코드:


<script>
  function doStuff()
 {
     // 작업을 실행한다
 }
</script>
<form action="doStuff.aspx" onsubmit="return false;">
 <input type="submit" value="작업 실행" onclick="doStuff();" />
</form>

이 코드의 실제 동작하는 예제는 자바스크립트를 사용한 액션 버튼 작성에서 볼 수 있다.

예제 4

스크립트를 실행하는 버튼을 input type="image"로 작성한다. 이미지의 텍스트 설명을 제공하기 위해 input에 title 속성을 반드시 추가해야 한다. 이러한 접근법은 스크립트에 의존하는 경우에만 사용해야 한다.

예제 코드:


<script>
  function doStuff()
  {
     // 작업을 실행한다
   return false;
  }
</script>
<input  type="image"  src="stuff.gif"  title="Do stuff"  onclick="return doStuff();" />

예제 5

스크립트를 실행하는 버튼을 input type="submit", input type="reset", input type="button"으로 작성했다. 이러한 접근법은 스크립트에 의존하는 경우에만 사용해야 한다.

예제 코드:


<input type="submit" onclick="return doStuff();" value=”Do Stuff” />

예제 6

스크립트를 실행하는 버튼은 button/button으로 작성했다. 이 태그는 버튼의 모양을 세세하게 다루고자 할 때 유용하다. 아래의 예제에서 버튼은 아이콘과 텍스트를 모두 포함한다. 이러한 접근법은 스크립트에 의존하는 경우에만 사용해야 한다.

예제 코드:

<button onclick="return doStuff();">
 <img src="stuff.gif" alt="stuff icon">
 작업 실행
</button>

참고 자료

참고 자료는 정보를 위해 제공되었을 뿐이므로, 내용을 지지하거나 동의한다는 뜻은 아니다.

테스트

절차

a, button, input 요소와 관련이 있는 모든 스크립트 동작에서:

  1. 스크립트를 지원하는 사용자 도구에서

    • 마우스로 콘트를을 클릭한다.

    • 스크립트 동작이 올바르게 실행되는지 확인한다.

    • 콘트롤이 앵커 요소라면, 앵커 요소의 href 속성에 있는 URI가 이동하지 않는지 확인한다.

    • 키보드를 통해 콘트롤을 탐색하거나 포커스를 주는게 가능한지 확인한다.

    • 콘트롤에 키보드 포커스를 준다.

    • 엔터키를 입력해서 스크립트 액션이 동작하는지 확인한다.

    • 콘트롤이 앵커 요소라면, 앵커 요소의 href 속성에 있는 URI로 이동하지 않는지 확인한다.

  2. 스크립트를 지원하지 않는 사용자 도구에서

    • 마우스로 콘트롤을 클릭한다.

    • 콘트롤이 앵커 요소라면, 앵커 요소의 href 속성에 있는 URI로 이동하는지 확인한다.

    • 키보드를 통해 콘트롤을 탐색하거나 포커스를 주는게 가능한지 확인한다.

    • 콘트롤에 키보드 포커스를 준다.

    • 콘트롤이 앵커 요소라면, 엔터를 입력해 앵커 요소의 href 속성에 있는 URI로 이동하는지 확인한다.

기대 결과

  • 위의 모든 항목을 통과해야 한다.


SCR36: 정적인 창이나 영역에서 이동, 스크롤, 자동 업데이트 되는 텍스트를 사용자가 표시할 수 있는 메커니즘 제공

적용

텍스트를 이동, 깜빡임, 업데이트하고 정적인 텍스트 블록을 만들 수 있는 모든 기술.

이 기술과 관련있는 기술:

설명

어떤 웹 페이지는 사용할 수 있는 공간이 한정되어 있어 텍스트를 스크롤하며 표시한다. 작은 창에서 스크롤되는 텍스트는 콘텐트를 충분히 빠르게 읽을 수 있는 사용자들을 위한 방법이지만, 그 보다 늦게 읽거나 보조 기술을 사용하는 사용자들에게는 문제가 될 수 있다. 이 기법은 움직임을 멈추어 전체 텍스트 블록을 정지시키는 메커니즘을 제공한다. 텍스트는 여러 창에서 분리되어 표시될 수도 있고, 페이지에 있는 (큰) 영역에서 표시할 수도 있다. 이 기법을 적용하면 사용자는 자신들의 속도로 텍스트를 읽을 수 있다.

이 기법은 움직이는 텍스트가 화면에서 한번에 나타나지 않는 경우에는 적용할 수 없다(예: 긴 채팅 대화).

주: 이 기법은 표준 미달 콘텐트에 사용되는 표준 준수 대체 버전 페이지를 표현하기 위한 스타일 변경 기법과 함께 사용할 수 있다. 더 자세한 정보는 C29: 표준 준수 대체 버전을 제공하는 스타일 변경 스크립트 사용(CSS)과 표준 준수 대체 버전의 이해를 참고하라.

예제

예제 1: 스크롤하는 텍스트 펼치기

페이지의 작은 영역에서 큰 텍스트 블록이 스크롤된다. 사용자는 버튼을 통해 스크롤을 멈추고 텍스트 블록 전체를 표시할 수 있다.

주: 이 예제코드는 CSS와 자바스크립트를 모두 사용할 수 있어야 한다.

CSS 구성:

예제 코드:

#scrollContainer {
        visibility: visible;
        overflow: hidden;
        top: 50px; left: 10px;
        background-color: darkblue;
      }
      .scrolling {
        position: absolute;
        width: 200px;
        height: 50px;
      }
      .notscrolling {
        width: 500px;
        margin:10px;
      }
      #scrollingText {
        top: 0px;
        color: white;
      }
      .scrolling #scrollingText {
        position: absolute;
      }
      </a>    

스크립트와 HTML 콘텐트:

예제 코드:

<script type="text/javascript">

      var tid;
      function init() {
        var st = document.getElementById('scrollingText');
        st.style.top = '0px';
        initScrolling();
      }
      function initScrolling () {
        tid = setInterval('scrollText()', 300);
      }
      function scrollText () {
        var st = document.getElementById('scrollingText');
        if (parseInt(st.style.top) > (st.offsetHeight*(-1) + 8)) {
          st.style.top = (parseInt(st.style.top) - 5) + 'px';
        } else {
          var sc = document.getElementById('scrollContainer');
          st.style.top = parseInt(sc.offsetHeight) + 8 + 'px';
        }
      }
      function toggle() {
        var scr = document.getElementById('scrollContainer');
        if (scr.className == 'scrolling') {
          scr.className = 'notscrolling';
          clearInterval(tid);
           document.getElementById('scrollButton').value="Shrink";
        } else {
          scr.className = 'scrolling';
          initScrolling();
          document.getElementById('scrollButton').value="Expand";
        }
      }
  <input type="button" id="scrollButton" value="Expand" onclick="toggle()" />
  <div id="scrollContainer" class="scrolling">
    <div id="scrollingText" class="on">
    .... 스크롤할 텍스트 ...
    </div>
  </div>
...

이 코드의 실제 동작 예제: 스크롤하는 텍스트 펼치기.

테스트

이 기법을 위한 테스트 없음


SCR37: 장치 독립적인 방법으로 사용자 정의 대화상자 작성

적용

스크립트를 사용하는 HTML과 XHTML.

이 기술과 관련있는 기술:

설명

웹 사이트 디자이너들은 종종 브라우저에서 제공하는 팝업창이 아닌 대화창을 만들고자 할 때가 있다. 이러한 대화창은 일반적으로 div에 대화창 콘텐츠를 담고 CSS에서 z-order와 absolute 위치 속성을 사용해 div의 위치를 정하는 방법으로 만들어진다.

다음은 접근성을 보장하기 위해 이러한 대화창들이 반드시 따라야 할 몇가지 간단한 규칙이다.

  1. 대화창을 나타내는 스크립트는 링크나 버튼의 onclick 이벤트를 통해 사용한다.

  2. 대화창 div는 DOM에서 볼 때 이벤트가 발생한 HTML 요소 바로 뒤에 위치하도록 한다. 이벤트가 발생한 HTML 요소는 포커스를 가진다. 대화창 콘텐트는 이 요소 바로 뒤에 삽입되는데, 그 덕분에 화면 낭독기에서 탭 순서대로 읽을 때 대화창 내부의 콘텐트가 요소 바로 다음에 읽힌다. 이 때에도 대화창은 절대(absolute) 위치를 가지고 있어, 시각적으로는 페이지의 어느 곳에도 있을 수 있다. 이같은 동작은 아래의 예제와 같이 대화창을 HTML로 작성한 후 CSS를 사용해 숨기거나 스크립트를 사용해 이벤트가 발생한 HTML 요소 바로 다음에 삽입함으로써 가능하다.

  3. 대화창 div 안의 HTML도 다른 콘텐트와 마찬가지로 동일한 접근성 표준을 충족시키는지 확인한다.

대화창을 여는 링크가 토글 기능을 하도록 만들어서 대화창을 열고 닫는 기능을 모두 하도록 하거나 링크가 키보드 포커스를 잃었을 때 대화창을 닫도록 하는 것도 꼭 필요하진 않으나 좋은 방법 중 하나이다.

예제

예제 1: 대화창을 여는 옵션 버튼

이 예제의 HTML은 대화창을 여는 HTML 요소로 버튼을 포함하고 있으며, 대화창의 껍데기 역할을 하는 div도 포함하고 있다.

버튼은 onclick 이벤트를 통해 스크립트를 실행하는데, 이는 운영체제에 적절한 이벤트를 전송해 보조 기술에서 DOM의 변화를 인식하도록 한다.

이 예제에서 대화창 안에 있는 확인과 취소 버튼은 div를 숨긴다.

예제 코드:

...
<button onclick="TogglePopup(event,true)"
	name="pop0001">옵션</button>

<div class="popover" id="pop0001">
  <h3>정렬 정보 수정</h3>
  <form action="default.htm" onsubmit="this.parentNode.style.display='none'; return false;" onreset="this.parentNode.style.display='none'; return false;">
    <fieldset>
      <legend>순서 정렬</legend>
      <input type="radio" name="order" id="order_alpha" /><label for="order_alpha">알파벳순</label>
      <input type="radio" name="order" id="order_default" checked="true" /><label for="order_default">기본</label>
    </fieldset>
<div class="buttons">
  <input type="submit" value="확인" />
  <input type="reset" value="취소" />
</div>
</form>

</div>
...

div, 제목과 form 요소들은 대화창과 비슷하게 보이도록 CSS로 꾸민다.

예제 코드:

...
a { color:blue; }
a.clickPopup img { border:none; width:0; }

div.popover { position:absolute; display:none; border:1px outset; background-color:beige; font-size:80%; background-color:#eeeeee; color:black; }
div.popover h3 { margin:0; padding:0.1em 0.5em; background-color:navy; color:white; }
#pop0001 { width:20em; }
#pop0001 form { margin:0; padding:0.5em; }
#pop0001 fieldset { margin-bottom:0.3em; padding-bottom:0.5em; }
#pop0001 input, #pop0001 label { vertical-align:middle; }
#pop0001 div.buttons { text-align:right; }
#pop0001 div.buttons input { width:6em; }
...

스크립트는 팝업 div를 보여주거나 감추도록 토글한다.

예제 코드:

...
function TogglePopup(evt,show)
{
	HarmonizeEvent(evt);
	var src = evt.target;
	if ("click" == evt.type)
	{
		evt.returnValue = false;
	}
	var popID = src.getAttribute("name");
	if (popID)
	{
		var popup = document.getElementById(popID);
		if (popup)
		{
			if (true == show)
			{
				popup.style.display = "block";
			}
			else if (false == show)
			{
				popup.style.display = "none";
			}
			else
			{
				popup.style.display = "block" == popup.style.display ? "none" : "block";
			}
			if ("block" == popup.style.display)
			{
				//window.alert(document.documentElement.scrollHeight);
				popup.style.top = ((document.documentElement.offsetHeight - popup.offsetHeight) / 2 ) + 'px';
				popup.style.left = ((document.documentElement.offsetWidth - popup.offsetWidth) / 2) + 'px';
			}
		}
	}
}

function SubmitForm(elem)
{
	elem.parentNode.style.display='none';
	return false;
}

function ResetForm(elem)
{
	elem.parentNode.style.display='none';
	return false;
}
...

실제 동작하는 예제는 대화창을 여는 옵션 버튼에서 볼 수 있다.

참고 자료

참고 자료는 정보를 위해 제공되었을 뿐이므로, 내용을 지지하거나 동의한다는 뜻은 아니다.

테스트

절차

  1. 페이지에서 팝업창이 아닌 대화창을 띄우는 영역을 모두 찾는다.

  2. 탭을 사용해 해당 영역으로 이동한 후 엔터를 입력해서 대화창을 열 수 있는지 확인한다.

  3. 대화창이 열렸다면 다음 탭 순서로 이동한다.

  4. 버튼이나 링크의 클릭(click) 이벤트를 통해 대화상자가 나타나는지 확인한다.

  5. 스크립트에 의해 생성된 DOM을 검사할 수 있는 도구를 사용해서 DOM에서 대화상자가 다음에 있는지 확인한다.

기대 결과

  • 2, 3, 4, 5번 항목을 통과해야 한다.