방탄 Ajax 표지
DOM Script의 저자 제레미 키스(Jeremy Keith)가 쓴 방탄 Ajax가 출간되었습니다. DOM Script에서 올바른 DOM, 겸손한(unobtrusive) 자바스크립트에 관한 이야기를 했다면 이번엔 올바른 Ajax의 활용, 접근성을 확보하는 Ajax 개발론, 즉 겸손한(unobtrusive) Ajax에 대해 이야기하고 있습니다.
이 책에서의 Ajax는 Asynchronous JavaScript and XML가 아닌 미국과 영국 등에서 과거에 쓰였던 Ajax라는 단어의 뜻으로서 정의하고 있습니다. 쉽게 말해 Flex, Silverlight 등의 RIA을 포괄하는 의미라는 것입니다.
모든 웹 사이트, 웹 어플리케이션의 기본은 문서이다.
라고 이야기하는 이 책에서는 기본적인 문서((X)HTML)로 부터 출발하여 점층적으로 CSS, Ajax를 덧붙여 나아가는 개발 방식을 이야기하고 있습니다. 기본적으로 하위 호환성과 접근성이 보장된 문서((X)HTML)의 틀에서 점층적으로 새로운 기술들을 적용해 나아간다면 겸손한(unobtrusive) Ajax의 제작이 어렵지 않을 것이라는 이야기입니다.
Ajax 기술들은 아직 충분히 접근성이 검증되어 있지 않은 새로운 기술들입니다. 방탄 Ajax는 그에 대해 지적하며 Ajax 기술 적용 시에 잃을 수 있는 것들에 대해 경고하고 있습니다. 저는 이것이 이 책이 얘기하는 주제라고 생각합니다. 눈 앞에 펼쳐질 화려한 효과에 앞서 고려하지 않으면 잃게 될 것이 무엇인지, 잃게 될 것들을 지키려면 어떻게 해야 할지가 명확하지 않다면 이 책을 볼 충분한 이유가 될 것 같습니다.
덧) 항상 좋은 책을 볼 수 있게 해주시는 명수씨, 감사합니다! :)
웹 사이트 개발을 하다보면 하나의 폼에 여러 개의 제출 버튼을 써야하는 경우가 있다. 그 경우 자바스크립트를 사용하지 않고 원하는 기능을 구현하려면 어떻게 해야할까? IE의 버그로 인해 여러 방법 중 대부분이 사용이 어렵지만 submit 타입의 input 태그를 여러 개 넣어서 폼을 구성하면 버그 없고 자바스크립트 의존적이지 않은 결과물을 만들 수 있다.
그럼 실제로 각 글에 체크박스가 있어서 체크 후 삭제 혹은 이동하는 기능이 있는 게시판 목록을 만들어보자. 결과물은 다음의 그림과 같을 것이다.
그림을 보고 HTML 페이지를 만들어보자.
<!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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>여러개의 폼 제출 버튼 예제</title>
</head>
<body>
<form action="test.html">
<h1>여러개의 폼 제출 버튼 예제</h1>
<table summary="게시판 목록">
<thead>
<tr>
<th>선택</th>
<th>제목</th>
<th>작성자</th>
<th>작성일</th>
<th>조회수</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox" title="1번글 선택"
name="check1" value="Y" /></td>
<td>게시판 제목1</td>
<td>아무개</td>
<td>2007년 10월 13일</td>
<td>4</td>
</tr>
<tr>
<td><input type="checkbox" title="2번글 선택"
name="check2" value="Y" /></td>
<td>게시판 제목2</td>
<td>아무개</td>
<td>2007년 10월 13일</td>
<td>4</td>
</tr>
<tr>
<td><input type="checkbox" title="3번글 선택"
name="check3" value="Y" /></td>
<td>게시판 제목3</td>
<td>아무개</td>
<td>2007년 10월 13일</td>
<td>4</td>
</tr>
<tr>
<td><input type="checkbox" title="4번글 선택"
name="check4" value="Y" /></td>
<td>게시판 제목4</td>
<td>아무개</td>
<td>2007년 10월 13일</td>
<td>4</td>
</tr>
</tbody>
</table>
<p>
<input type="submit" name="delete_selected"
value="선택된 글 삭제" />
<input type="submit" name="move_selected"
value="선택된 글 이동" />
</p>
</form>
</body>
</html>
선택된 글 삭제와 선택된 글 이동 버튼을 submit 타입의 input 태그로 주고 각각에 name 속성을 부여하였다. 여기에서 1번글을 선택하고 선택된 글 삭제 버튼을 누른다면 제출된 값은 다음과 같을 것이다.
check1 = "Y"
delete_selected = "선택된 글 삭제"
마찬가지로 이동 버튼을 누른다면,
check1 = "Y"
move_selected = "선택된 글 이동"
위와 같은 값이 제출될 것이다.
"선택된 글 삭제"와 같은 값을 다른 원하는 임의의 값으로 줄 수 없을까? 답은 불가능하다. 화면에 보여지는 값을 그대로 사용해야 한다. 이 것이 필자가 설명한 방식의 한계이다. 개발자들은 보통 "Y" 혹은 "delete"와 같은 명확한 코드 형식의 단어를 사용하고 싶어할 것이다. 하지만 자바스크립트를 사용할 수 없는 사용자들의 불평을 듣고 싶지 않다면 현재로서는 어쩔 수 없다. IE(IE7 포함) 사용자는 submit 타입의 input 태그 외에 submit 타입의 button 태그나 image 타입의 input 혹은 button 태그에 name 속성을 통해 제출 값을 구분할 수 없기 때문이다.
이미지 버튼일 경우는 어떻게 하나? image 타입의 input 태그를 사용할 수 없다면? 답은 Image Replacement이다. Image Replacement를 사용할 수 없는 상황이라면 폼 제출 버튼을 이미지 - 배경 이미지 제외 - 로 하지 않는 디자인을 고려해보아야 할 것이다.
<style type="text/css">
input.delete-selected {
width: 100px;
height: 20px;
background: url(delete_selected.gif) no-repeat;
text-indent: -5000px;
}
input.delete-selected {
width: 100px;
height: 20px;
background: url(move_selected.gif) no-repeat;
text-indent: -5000px;
}
</style>
<!-- 중략 -->
<p>
<input type="submit" class="delete-selected"
name="delete_selected" value="선택된 글 삭제" />
<input type="submit" class="move-selected"
name="move_selected" value="선택된 글 이동" />
</p>
글의 코드는 아래의 첨부파일을 다운로드를 통해 실행해볼 수 있다.
페이징 기능을 포함한 게시물 리스트 화면이나 Breadcrumb 구조 등 다수의 공통적인 파라미터를 가지고 다녀야 하는 경우가 있다. 이 경우에 쓰이는 방법이 여러가지가 있는데 일반적으로 서버 사이드 스크립트를 통해 공통적인 파라미터를 묶어서 여러 개의 관련 링크에서 일관적으로 적용하도록 하는 방법이다. 그런데 다음과 같은 HTML 코드를 만들어내는 경우가 있다. (common1~3을 공통적인 파라미터라고 가정한 게시물 보기 화면) Breadcrumb 구조 등 다수의 공통적인 파라미터를 가지고 다녀야 하는 경우가 있다. 이 경우에 쓰이는 방법이 여러가지가 있는데 일반적으로 서버 사이드 스크립트를 통해 공통적인 파라미터를 묶어서 여러 개의 관련 링크에서 일관적으로 적용하도록 하는 방법이다. 그런데 다음과 같은 HTML 코드를 만들어내는 경우가 있다. (common1~3을 공통적인 파라미터라고 가정한 게시물 보기 화면)
<script type="text/javascript">
function goDelete(id) {
var form = document.forms["blahform"];
form.id.value = id;
form.action = "delete";
form.submit();
}
function goUpdate(id) {
var form = document.forms["blahform"];
form.id.value = id;
form.action = "updateForm";
form.submit();
}
function goList() {
var form = document.forms["blahform"];
form.action = "list";
form.submit();
}
</script>
<a href="javascript:goDelete(1)">삭제</a>
<a href="javascript:goUpdate(1)">수정</a>
<a href="javascript:goList()">리스트</a>
<form name="blahform" method="post">
<input type="hidden" name="common1" value="1" />
<input type="hidden" name="common2" value="2" />
<input type="hidden" name="common3" value="3" />
<input type="hidden" name="id" value="" />
</form>
프로그램 적으로 생각하자면 공통 파라미터의 일관성을 유지할 수 있는 한가지 방법이라고 할 수 있겠지만, 결과적으로 HTML 태그가 의미에 맞지 않고 자바스크립트 의존적인 코드가 되었다. 기본적으로 form 태그는 사용자 입력 양식을 뜻하는데 위에 쓰인 form 태그는 프로그램 내부적인 용도 그 이상의 의미를 지니지 않는다.
앞서 언급한 것과 같이 공통 파라미터를 한 변수에 할당하는 방법으로도 일관성을 충분히 얻을 수 있고 그 이외에도 서버 사이드 스크립트 단에서 위의 코드에서 얻으려고 했던 이득을 놓치지 않을 수 있는 방법이 많이 있다. 이와 같은 오류를 범하지 않으려면 HTML의 구조화를 해치지 않고 자바스크립트 의존적인 페이지를 피하는 자세가 필요하다.
(그림1. 전송 버튼이 적용되지 않은 select 태그)
그림1은 현재 게시판의 분류나 바로가기 메뉴 등에서 선택 시 바로 폼을 전송시키거나 자바스크립트를 이용하여 페이지 전환을 하는 용도로 쓰이고 있다. 그러나 키보드 사용자나 자바스크립트를 사용할 수 없는 사용자를 고려하였을 때 위와 같은 사용은 불가하다. 자바스크립트가 불가능한 사용자를 위해 <noscript> 태그를 이용하여 서브밋 버튼을 추가하면 되지 않느냐? 그것은 반쪽짜리 접근성이다. 마우스 기능을 사용할 수 없는 사용자의 접근성이 상당히 저하되기 때문이다. 키보드 사용자는 select 태그의 목록을 활성화 시킨 후 아래 방향키를 한 번 누르는 순간 select 태그의 자바스크립트가 활성화되어 마치 목록 두 번째 요소를 선택한 듯한 결과를 보게 될 것이다.
(그림2. 전송 버튼이 적용된 select 태그)
전송 버튼을 넣고 select 태그의 onchange 이벤트를 제거하여 모든 사용자에 대한 접근성을 확보할 수 있다. 마우스 사용자들의 편의성 문제는 어떻게 하는가? 결국 판단은 제작하는 사람의 몫이지만 누군가의 접근성을 저해하면서 얻는 편의는 기능에 대한 남용이다.
이밖에 장애인이 공공부분의 인터넷 사이트를 손쉽게 이용할 수 있도록 `웹 접근성 준수'를 제도화하기 위해 올해안에 웹 접근성 국가표준을 개정하기로 했으며 공공기관은 물론 민간기관들의 참여를 이끌어내기 위해 `웹 접근성 품질 마크'를 적극적으로 부여하기로 했다.
정부 차원에서 장애인들의 IT 활용 활성화를 추진하고 있다는 기사가 났다. 웹 접근성에 대해 국가 차원의 관심과 필요성이 더욱 늘어나게 되었다는 이야기이다. 좋던 싫던 관심이 있던 없던 웹 표준과 접근성은 점점 피할 수 없는 필수요소가 되어가고 있다. 장애인의 인터넷 접근 장치는 점점 늘어가는데 정보를 얻는 통로인 웹사이트가 그들을 소외시킨다면 정부의 이런 정책은 아무런 의미가 없을 것이다.
기사대로라면 2012년에는 접근성을 보장 여부가 13만명의 잠재 이용자를 잡느냐 놓치느냐를 판가름한다. 웹표준과 웹접근성의 가치가 보다 빠르게 늘어날 것이라는 기대를 해본다.
"파일을 원하는 갯수만큼 올릴 수 있는 폼으로 구성해주세요!"
웹을 업으로 하는 사람이라면 이 말 싫어하는 사람 참 많을게다. 몇 개의 파일 입력 상자를 고정해놓는다면 모를까? 입력 상자의 갯수를 동적으로 해달라는 요구는 그 처리의 귀찮음에 혀를 내두르지 않는 사람이 드물것이다. 귀찮고 오류가 일어날 소지가 많은 부분이다 보니, 관련 자바스크립트 라이브러리 라든지 Flash를 이용한 경우 라든지 심지어 ActiveX를 사용하는 경우(너무 많아서;;)까지 관련 라이브러리나 기술이 많이 생기게 되었다. 요즘은 오히려 훌륭한 공개 라이브러리가 많아서 - AJAX로 Progress Bar까지 구현해주는 라이브러리도 있다. - 불편함이 없다고 얘기해도 무방한 정도다.
하지만 HTML5는 자바스크립트라든지 외부 기술(Flash, ActiveX 등)에 구애없는 - 접근성을 보장하는 - 다중 입력폼을 지원한다! 바로 반복 모델이 그것이다. 말 보다는 코드로! 다음 html 코드를 보자.
<!DOCTYPE html>
<html>
<head>
<title>Sample Order Form</title>
</head>
<body>
<form>
<table>
<thead>
<tr>
<th>Product</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" name="row0.product" value=""></td>
<td><input type="text" name="row0.quantity" value="1"></td>
</tr>
<tr>
<td><input type="text" name="row1.product" value=""></td>
<td><input type="text" name="row1.quantity" value="1"></td>
</tr>
<tr>
<td><input type="text" name="row2.product" value=""></td>
<td><input type="text" name="row2.quantity" value="1"></td>
</tr>
</tbody>
</table>
<p><button type="submit">Submit</button></p>
</form>
</body>
</html>
3개의 반복 입력 블럭을 가진 페이지이다. 예전 같으면 여기서 사용자가 원할 때 블럭을 더 보여주거나 하는 동작을 하려면 위에 언급한 것처럼 외부 기술이 없다면 입력 페이지를 매번 리로드하지 않으면 불가능 할 것이다. 말이 리로드지 다른 파라미터들을 생각해보면 외부 기술 없이는 힘들고 생각하기도 싫어져 버린다. 다음 코드는 HTML5에서 이것을 어떻게 구현하는지를 보여준다.
<!DOCTYPE html>
<html>
<head>
<title>Sample Order Form</title>
</head>
<body>
<form>
<table>
<thead>
<tr>
<th>Product</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
<tr id="order" repeat="template">
<td><input type="text" name="row[order].product" value=""></td>
<td><input type="text" name="row[order].quantity" value="1"></td>
<td><button type="remove">Remove This Row</button></td>
<td><button type="move-up">Move This Row Up</button></td>
<td><button type="move-down">Move This Row Down</button></td>
</tr>
</tbody>
</table>
<p><button type="add" template="order">Add Row</button></p>
<p><button type="submit">Submit</button></p>
</form>
</body>
</html>
repeat="template" 선언이 되어있는 block - 여기서는 tr 태그 - 이 사용자의 요청에 따라 늘어나고 줄어들게 된다. 어떻게 늘리고 어떻게 줄이느냐? 바로 button type="add"와 button type="remove"가 그것이다. add 버튼에 반복 블럭의 id를 template 속성에 선언해주면 반복 블럭과 add 버튼이 연결되어 add 버튼이 눌릴 때 반복 블럭이 하나 생기게 된다. 여기서 새로 생긴 블럭에서 product에 해당하는 개체의 이름은 row[order].product를 따라 - 여기서 [order]가 블럭의 인덱스에 해당하는 숫자가 된다. - row1.product라는 이름을 갖게 된다(시작값이 0임). move-up, move-down 타입은 블럭의 표시 순서를 바꿔준다. 정말 꼭 필요하던 기능이라는 생각이 드는 예제인 것 같다!
반복의 시작값을 지정하는 repeat-start 속성, 최소·최대 반복값을 지정하는 repeat-min과 repeat-max 등 반복 모델은 다중 입력에 필요한 기능을 충분하게 지원하도록 설계되었다.
HTML5의 반복 모델, 자바스크립트나 Flash 등의 외부 기술을 사용할 수 있는 사용자의 편의를 위한 기능이 충분히 덧붙여질 수 있겠지만, 누구나에게 접근성을 보장하는 다중 입력 폼을 설계가 참 쉽고 즐거운 작업이 될 듯 하다.