웹표준이라는 커다란 화두가 던져 졌을때 많은 사람들이 Table 요소를 버리고, Div 요소를 사용할 것을 강조했습니다. 아직도 여러 커뮤니티 게시판의 예전 게시물을 살펴보면 그러한 흔적들을 살펴볼 수 있는데 다행스럽게도 지금은 그러한 논란의 소용돌이 속에서 Table 요소와 Div 요소를 분리하여 오해가 없이 사용하는 단계까지는 오게 된것 같습니다. Div 요소는 Table 요소가 레이아웃으로 오용되는 것을 확실히 대체해 가고 있고, Table 요소는 제자리를 찾아 데이터를 담는 표로써 올바르게 사용되기 시작한 것입니다. 그렇게 이 글에서는 Table 요소가 가진 진실과 오해를 풀어보고자 합니다.
* 가독성을 위해 요소(Element)의 첫 글자는 대문자로 표기하였고, 속성(Attribute)은 소문자로 표기했습니다.
1. Table for Layout
Table 요소와 관련된 가장 큰 이슈였습니다. 표준화 작업을 시작하면서 레이아웃을 위해 사용된 Table 요소를 포기시키는 일종의 운동(?) 내지는 유행이 번졌는데 우리들 스스로 Table 요소를 금지(descendant)해 버리는 실수를 범하기도 했습니다.
레이아웃(Layout)은 우리말로 배치 또는 판짜기 등의 의미를 가집니다. 집을 생각해 봅시다. 터를 닦고, 골격을 세운 뒤 방과 거실, 화장실과 테라스를 구분지어 짓습니다. 그리고 각종 가구를 들입니다. 침대와 옷장은 안방 벽면에 두고, 컴퓨터와 책장은 서재에 두고, TV와 쇼파는 거실에 두는 등 가구와 물건을 적당한 위치에 배치시킵니다. 여기서 가구와 물건은 요소(Element)가 될 것이고, 가구를 담은 집은 Table 요소가 될 것입니다. 집을 세운 땅은 브라우저와 운영체제가 되겠네요. 아마도 이것이 우리가 그동안 생각해 왔던 레이아웃이었을 것입니다. 그런 의미에서 Table 요소는 너무나 적절했습니다. Table 요소는 우리에게 틀어지지 않는 레이아웃을 제공하였고, 어떤 내용(요소)이든 자유자재로 담아낼 수 있다고 생각했습니다. 아마도 CSS가 만들어지지 않았다면 이러한 우리의 사고는 변함없었을 것이고, Table 요소는 최고의 설계도구가 되어 주었을 것입니다.
그런데 시간이 지나자 사람들은 거실을 넓히고, 테라스를 확장하기를 바랬습니다. 오래된 집을 리모델링 하기를 원하기 시작했습니다. TV와 세탁기, 냉장고는 점차로 커졌고, 새로 홈시어터를 들여놔야 했습니다. 하지만 우리의 집은 너무나 견고해서 벽을 허물고, 새로 설계를 하고 리모델링을 하기에는 너무나 많은 비용이 들었고, 시간과 인력이 낭비되는 일이었습니다. 아버지는 아내와 아들, 딸을 모아놓고 가족회의를 해야 했고, 아파트의 주민들은 투표를 해야 했습니다. 그리고 구청과 시청의 허락을 받아야 했습니다. 집을 본따 만든 수 많은 웹사이트들 역시 똑같은 시련을 겪는 순간이 왔습니다. 한번 만든 웹사이트는 디자인을 변경하기가 너무나 어려웠습니다. 결국 그들은 모든걸 허물고 새로 만들어야 했습니다.
이 문제를 풀기 위해서 우리는 홈페이지(Homepage)에 대한 고정관념부터 버려야 할 것 같습니다. 우리는 인터넷에 집(Home)을 짓는 것이 아니라, 정보(Content)를 설계(Design)하고, 제공(출판, Publishing)하는 공간(Site)을 만드는 것이라고 말입니다. 내용을 잘 담아내고, 어떻게 표현해서 보여줄 것인지를 고민해야 합니다. 여기서 우리는 내용과 표현의 분리를 생각합니다. 이는 CSS(Cascading Style Sheet)가 해결해 줄 수 있습니다.
CSS는 HTML과 XHTML, XML 등 마크업 언어를 어떻게 표시할 것인가? 하는 문제를 해결하기 위해 W3C에서 1996년에 발표한 언어입니다. Table for Layout에서도 이미 CSS는 사용되고 있었지만 대부분 글꼴과 링크를 다루는 정도로만 사용되었습니다. 그것 역시 HTML문서 내에 직접 작성되는 방식이 대부분이었습니다. 하지만 CSS 2.1 이후 우리는 거의 모든 요소에 대해서 표현을 독립적으로 처리할 수 있는 기술을 가지게 되었습니다. 현실공간에서 불가능하게 여겼던 배치가 웹에서는 CSS를 통해서 가능하게 되었습니다. 둘 이상의 요소를 얼마든지 하나의 영역안에 포함시키거나 겹쳐 보이게 할 수 있고, 숨기거나 보이게도 할 수 있습니다. 논리적으로 서술된 내용(CSS를 걷어 내었을 경우 내용이 선형적으로 제공되는 내용)를 고치지 않고도 사용자에게 다양한 표현양식으로 보여줄 수 있게 되었습니다.
우리는 여기서 Table for Layout의 대체자로서 Div 요소가 설명되지 않은 배경을 이해해야 합니다. Div 요소는 내용(Content)을 논리적으로 그루핑(Grouping)하는 요소입니다. 머릿글 영역과 본문, 바닥글을 구분짓고, 개별적인 섹션을 나누는 역활을 해 줍니다. 여기서 다시 Div 요소가 단순히 레이아웃을 위한(Div for Layout) 요소가 아님을 이해해야 합니다. Img 요소와 p 요소를 직접 배치할 수도 있고, Ul 요소와 Dl 요소를 가지고 표를 만들어 낼 수도 있습니다. 거의 모든 요소가 레이아웃을 가질 수 있습입니다. 단지 Table 요소가 '표'로써가 아닌 레이아웃을 만드는 목적으로 잘못 사용되었기 때문에 지양하는 것이며, Div 요소가 내용을 논리적으로 그루핑한다고 볼 때 레이아웃을 만드는 대체자로써 가장 적합하다고 판단되기 때문에 권장되는 것입니다. HTML 5나 XHTML 2 등 새롭게 준비되고 있는 마크업 언어에서는 또 다른 요소를 통해서 레이아웃을 설계할지도 모릅니다. 다시 말하지만 레이아웃은 요소가 아니라 CSS가 만들어 내는 것입니다.
우리는 위에서 HTML문서의 내용과 표현의 분리를 이야기 했고, 표현을 위한 도구로 CSS를 이야기 했습니다. 그리고 HTML을 순수하게 내용을 담아내는 도구로써 이해해야 함을 강조합니다. 논리적으로 잘 작성된 HTML문서는 CSS에 의해서 자유로운 레이아웃을 가질 수 있습니다. Table 요소나 Div 요소와 같이 어느 특정 요소 하나에 의해서 레이아웃이 결정된다면 우리는 여전히 경직되고, 멍청한 웹사이트를 만드는 일을 계속 하게 되는 것입니다.
* 'Table for Layout'이라는 표현은 정찬명씨의 글 '웹 표준 코딩의 장점. Table for Layout 과 CSS Layout의 비교 실험'에서 가져왔습니다.
2. Table 요소를 표로써 활용하자
위에서 Table 요소가 레이아웃을 위한 요소로써 적당하지 않음을 설명했습니다. 그럼 Table 요소를 어떻게 써야 잘 썼다고 소문이 날 수 있는지를 알아보겠습니다. W3C의 HTML 4.01 권고안을 살펴보면
The HTML table model allows authors to arrange data -- text, preformatted text, images, links, forms, form fields, other tables, etc. -- into rows and columns of cells.
라고 되어 있는데 저작자들(Authors)에게 데이터를 줄(rows)과 컬럼(columns)의 셀(cells)에 텍스트와 양식화된 텍스트, 이미지 등을 넣을 수 있는 것이라고 합니다. Table 요소를 데이터가 있는 표로써 활용하라는 것인데 성적표와 가계부, 각종 통계 자료를 담은 표 등이 적절한 예가 될 것입니다.
표는 열(column)과 행(row) 그리고 셀(cell)로 이루어져 있습니다. 개인적으로 열과 행을 자주 헷갈리곤 하는데 열을 분단(교실에서 1,2,3,4 분단으로 나누었던 것)으로 생각하고, 행을 줄로, 셀은 각각의 책상으로 생각하면 쉽습니다. 그리고 표와 각 셀에는 각자의 선(Border)이 있습니다. 표의 선은 교실 자체로 생각하고, 셀의 선은 바닥에 그어진 선(보통 바닥의 네모난 선 안에 책상 하나가 들어가죠)으로 연상하면 좋을것 같습니다. 여기에 Table 요소는 Caption 요소와 Thead 요소, Tbody 요소, Tfoot 요소를 가지는데 Caption 요소는 교실의 팻말이라고 생각하시면 됩니다. 3-2반 이렇게 말이죠. 그리고 Tbody 요소는 책상 전체를 묶어놓은 단위로 생각하시면 됩니다. Thead 요소와 tfoot 요소는 표의 정보를 담고 있는 영역이라고 생각하시면 됩니다. 다음은 Table 요소에서 사용되는 요소입니다.
- Table 요소 : Table을 정의
- Caption 요소 : 표의 제목 정의
- Thead 요소 , Tbody 요소, Tfoot 요소 : 행 그루핑 요소
- Tr 요소 : 행을 정의
- Td 요소 : 데이터 셀을 정의
- Th 요소 : 제목 셀을 정의
- Colgroup 요소 / Col 요소 : 열 그루핑 요소
하나의 예를 들어보겠습니다. K리그 2라운드에 수원 블루윙즈와 성남 일화가 경기를 갖게 되어 선발 출전 명단을 다음과 같이 공개했습니다.
포지션 | 배번 | 선수명 | 출전 | 득점 | 도움 | 실점 | 파울 | 경고 | 퇴장 | |
---|---|---|---|---|---|---|---|---|---|---|
※ 2008 삼성 하우젠 K리그 2라운드 | ||||||||||
수원 블루윙즈 | GK | 1 | 이운재 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
DF | 2 | 마토 | 1 | 0 | 0 | 0 | 4 | 0 | 0 | |
DF | 29 | 곽희주 | 1 | 0 | 0 | 0 | 2 | 0 | 0 | |
DF | 14 | 이정수 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | |
DF | 3 | 양상민 | 1 | 0 | 0 | 0 | 2 | 1 | 0 | |
MF | 6 | 조원희 | 1 | 0 | 0 | 0 | 3 | 1 | 0 | |
MF | 8 | 송종국 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
MF | 5 | 박현범 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
FW | 13 | 이관우 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | |
FW | 9 | 에두 | 1 | 2 | 0 | 0 | 2 | 1 | 0 | |
FW | 27 | 서동현 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
성남 일화 | GK | 30 | 정성룡 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
DF | 14 | 김상식 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | |
DF | 5 | 조병국 | 1 | 0 | 0 | 0 | 2 | 0 | 0 | |
DF | 2 | 박진섭 | 1 | 0 | 0 | 0 | 2 | 0 | 0 | |
DF | 33 | 장학영 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | |
MF | 6 | 손대호 | 1 | 0 | 0 | 0 | 4 | 0 | 0 | |
MF | 17 | 김철호 | 1 | 0 | 0 | 0 | 2 | 1 | 0 | |
MF | 10 | 두두 | 1 | 0 | 0 | 0 | 2 | 0 | 0 | |
FW | 15 | 한동원 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | |
FW | 9 | 김동현 | 1 | 0 | 0 | 0 | 3 | 0 | 0 | |
FW | 11 | 모따 | 1 | 0 | 1 | 0 | 2 | 1 | 0 |
그리고 다음은 선수명과 득점, 경고를 시각적으로 표현하기 위한 스타일 정의입니다.
<style type="text/css">
#tb_kleage { border-collapse: collapse; }
.name { font-weight: bold; }
.goal { color: blue; }
.red_card { color: red; }
</style>
마크업을 살펴보면 Table 요소에는 summary 속성과 border 속성을 가지고 있고, Caption, Colgroup, Thead, Tfoot, Tbody 요소를 차례대로 가지고 있음을 알 수 있습니다. Table 요소내 요소 정의 순서는 Caption 요소, Colgroup / Col 요소, Thead 요소, Tfoot 요소, Tbody 요소 순인데 이는 프린터로 표를 출력했을 때 Tbody 요소 내의 컨텐츠가 길어져 두 페이지 이상으로 끊어질 때 Tfoot 요소가 페이지마다 출력될 수 있도록 하기 위함입니다. 아울러 HTML 4.01 에서는 Thead 요소와 Tfoot 요소는 종료태그의 생략이 가능하며, Tbody 요소의 경우 시작태그와 종료태그 모두 선택적으로 정의하지 않아도 됩니다.
summary 속성은 표의 요약 정보를 담아내는 것으로써 표의 제목과 각 열의 제목을 정확하고 간략하게 표기해 주는 것이 좋습니다. Caption 요소는 표의 제목을 정의하는데 사용하며 많은 브라우저에서 가운데 정렬을 기본값으로 하고 있습니다. CSS의 table-caption 속성으로 상/하,좌/우로의 배치가 가능하나 IE 에서는 지원하지 않습니다. rules 속성은 셀의 구분선 표시형식을 정의하는 것으로 행 사이의 구분선을 표시할 경우에 'rows', 열 사이에 구분선을 표시할 경우에 'cols', 그루핑 단위로 구분선을 표시할 경우에는 'groups'를 지정합니다. 이 때 그루핑의 단위는 Colgroup 요소와 Thead, Tfoot, Tbody 요소가 되며, 위와 같이 둘 이상의 Tbody 요소를 사용할 경우 Tbody 요소간에도 구분선이 표시됩니다.
border 속성의 경우 CSS를 통해서도 표현이 가능합니다. 하지만 CSS가 지원되지 않는 경우 border 속성이 없는 Table 요소는 구분선이 없는 형태의 표를 보여주게 되는데 이는 오히려 시각적인 가독성을 떨어뜨리는 문제를 갖게 됩니다. 때문에 Table 요소에 border 속성의 기본값을 1로 정의하고, CSS를 통해서 표시 방법을 재정의하는 것을 추천합니다.
Colgroup 요소는 열의 그루핑을 위한 요소로써 Col 요소를 포함할 수 있습니다. 둘 이상의 열을 그루핑 할 경우 span 속성을 통해서 갯수를 정의할 수 있습니다. Table 요소의 rule 속성에서 'groups'로 정의했다면 Colgroup 요소만큼 구분선이 표시됩니다.
Colgroup / Col 요소에서는 위와 같이 class를 지정함으로써 스타일을 공유할 수 있지만 현재 IE에서만 지원되고 있으며, Firefox와 Safari, Opera 등에서는 지원되지 않고 있습니다.
Thead 요소는 Colgroup 요소 다음으로 나오는 것으로 표의 제목 영역을 정의합니다. 제목 영역의 셀은 Th 요소로 논리적으로 제목임을 정의하며 많은 브라우저에서 가운데 정렬의 굵은체로 표시됩니다. 제목 셀에서는 특별히 abbr 속성을 통해서 표 안의 행과 열이 어떤 의미를 가지고 있는지를 간략하게 표시하는데 이용되는데 Abbr 요소가 약자의 전체 이름을 표시해주는 것과는 다릅니다. 위 예제에서도 소속명 '수원 블루윙즈'와 '성남 일화'를 각각 '수원'과 '성남'으로 약자 기술하였습니다. 이렇게 정의된 abbr 속성은 음성 장치(스크린리더)에서 '수원 블루윙즈'대신 '수원'으로 읽어주는 역활을 할 수 있습니다.
Table 요소에는 셀과 셀 사이의 관계를 설정하기 위해 scope와 headers 속성을 지원하고 있습니다. scope 속성은 Th 요소로 제목정보를 제공하는 Td 요소의 범위를 지정할 수 있는데 'col' 값은 현재 열의 모든 셀들을 의미합니다. 마찬가지로 'row' 값은 현재 행의 모든 셀들을 범위로 지정함을 의미합니다. headers 속성은 scope 속성과 달리 th 요소와 td 요소를 직접 연결하는 기능을 제공합니다. id 속성으로 정의된 th 요소를 td 요소가 headers 속성을 통해서 직접 접근할 수 있으며, 둘 이상의 th 요소를 지정할 수 있습니다. 따라서 일반적으로 규칙적이고 복잡도가 낮은 경우에는 scope 속성을 이용해서 열과 행의 범위를 지정해서 사용할 수 있고, 데이터의 위치가 불규칙하여 scope 속성으로 영역을 설정하기 곤란한 경우 headers 속성을 사용합니다.
잘 사용되지는 않지만 셀의 카테고리를 설정할 수 있는 axis 속성이 있습니다. axis 속성은 id 속성와 headers 속성으로 연결된 셀들을 카테고리화(categorizing) 할 수 있어서 사용자가 표로부터 원치 않는 정보(셀)를 제외한 보다 정확한 정보를 제공받을 수 있도록 처리하는데 도움을 줍니다.
3. Table 요소의 현재와 또 다른 이슈
간단하게 Table 요소에 대한 내용을 정리해 보았습니다. 위의 내용은 W3C의 HTML 4.01 Specification 에서 보다 상세하게 설명해 주고 있는데 실제로 프로젝트에 적용하기에는 어려움이 많은 것이 사실입니다.
첫째로 Table 요소는 Div 요소 등 여타의 요소들에 비해서 비교적 브라우저간의 차이가 거의 없는 요소이기는 하지만 Firefox와 Safari, Opera 등 일부 브라우저에서는 여전히 Colgroup/Col 요소의 스타일 공유를 지원하지 않는 것(width 속성은 적용되지만 이 역시 값이 지정된 셀과 같은 열의 나머지 셀들이 함께 적용되었다기보다는 기준 셀의 너비 크기에 따라 강제로 적용된 것이라고 생각됨)과 IE에서 Body 요소 내 폰트 속성이 Table 요소에는 상속되지 않는 등의 문제를 가지고 있습니다.
둘째로 음성 도구(스크린리더 등)에서의 지원이 미비하여 높은 수준의 접근성을 확보하기 어렵습니다. 국내 스크린리더인 드림보이스(DreamVoice 6.21)의 경우 '곽희주'에 포커스가 위치해 있을 경우 "수원 블루윙즈 포지션 DF, 배번 29, 선수명 곽희주 ..."와 같이 읽지 않고 "DF, 29, 곽희주 ... "와 같이 마크업된 상태 그대로 읽어주고 있습니다. 또한, 논리적으로 Tfoot 요소를 마지막에 위치시켜 읽어주지 않고 Thead 요소 다음에 읽어 주는 것 또한 볼 수 있었습니다.
셋째로 현실세계에서 사용하는 복잡한 표를 HTML 문서로 그대로 재현하는데에는 어려움이 많습니다. 표가 복잡해질 수록 표 내에 표가 중첩되어 사용되거나 지나치게 많은 셀 결합(colspan, rowspan)을 하게 되는데 이는 웹접근성을 상당히 떨어뜨리는 문제가 되기도 합니다. 또한, 대중적인 디스플레이 장치인 17"/19" 모니터의 일반적인 해상도(1280*1024)에서도 표를 완벽하게 보여주기에는 부족함을 느끼는 경우가 많습니다. 더구나 핸드폰과 PDA 등 소형 디스플레이를 통한 인터넷 환경은 표의 표현이 만만치 않은 작업임을 예상케 합니다.
넷째로 시각적으로 표로 보이는 모든 컨텐츠에 대해서 Table 요소를 사용할 수 있는가? 하는 문제에 대한 고민이 생길 수 있습니다. 많은 경우 당연히 Table 요소로 작성되는 게시판의 목록은 한동안 Div 요소와 Ul 요소로도 수차례 테스트되고, 논의가 되기도 했습니다. 더불어 게시판의 보기와 쓰기 화면도 Table 요소로 가능한가에 대한 논의가 필요할 것이고, 가입 양식 등 폼 영역 역시 마찬가지일 것입니다.
다섯번째로 그림자와 같이 비주얼이 강한 표를 처리하는 문제입니다. 다음과 같이 Thead 요소가 서로 붙어(구분선의 두께가 다름) 있고, Tbody 요소와 Tfoot 요소가 시각적으로 분리되어 있으면서 그림자 효과를 포함할 경우 가변적인 표의 작성이 쉽지만은 않습니다.
이상과 같은 경우 현실세계의 표를 그대로 가져올 것이 아니라 HTML 문서에 최적화된 표를 새롭게 작성하는 것이 좋습니다. 즉, 복잡한 표를 논리적으로 분리하여 둘 이상의 표로 나누어 Table 요소의 중첩을 피하고, 셀간의 결합을 최소화 하는 것입니다. 분리된 표는 시각적 표현에 있어서도 좀 더 쉽고 유연한 방법을 찾을 수 있을 것입니다.
4. 끝맺음
Table 요소는 가장 많이, 그리고 가장 쉽게 사용하는 요소중 하나일 것입니다. 하지만 과거의 경우에 Table 요소를 'for Layout'으로 잘못 이해하여 사용하였던 것처럼 우리는 충분한 이해 없이 Table 요소를 사용해 온 것이 사실입니다. Table 요소를 표로써 제대로 사용하는 것. 쉬운 결정이지만 결코 만만치 않은 일이라고 생각합니다. 여전히 현실세계의 복잡한 표를 HTML 문서에 그대로 포함시키려 들거나, 때로는 복잡한 표를 이미지로 대체해 버리기도 합니다. 접근성을 살린 표를 마크업 하는 일이 시간과 노력이 많이 들기 때문입니다. 표는 표 자체로 많은 정보를 포함하고 있는 컨텐츠입니다. 하나의 표를 올바르게 마크업 하는 것은 웹 표준을 위한 큰 걸음 하나가 될 것입니다.
댓글 없음:
댓글 쓰기