2022-02-14 13:22 작성
HTML TABLE 심화 기능과 접근성
Table of contents
Table에 <caption>
을 이용해 caption 더하기
<table>
element에 <caption>
element를 넣어 caption 기능을 넣을 수 있다.
Hello | World! |
<table>
<caption>
Dinosaurs in the Jurassic period
</caption>
...
</table>
상기의 간단한 에시에서 나타나는 것처럼, caption은 table 내용에 대해 기술하는 의미를 가진다. Caption은 사용자에게 필요한 정보가 있는지 빠르게 탐색할 수 있게 한다는 점에서 유용할 뿐 아니라 시각 장애를 가진 이용자들에게도 전체 내용을 간단하게 소개해준다는 점에서 유용하다.
Note:
summary
속성도 설명 용도로<table>
element에 사용할 수 있으며, Screenreaders가 읽을 수 있다. 그러나<caption>
element를 사용하기를 권장한다. 그 이유는 HTML5가 시작되고 난 이후에summary
는 폐기되었고 시각이 정상인 사용자들은 해당 항목을 읽을 수 없기 때문이다(Web page에 시각적으로 나타나지 않음).
<thead>
, <tfoot>
, 그리고 <tbody>
로 구조 더하기
Tables의 구조가 점점 더 복잡해질수록 구성요소에 좀 더 구조적인 정의를 사용해주는 것이 유용할 것이다. 이를 수행하는데 있어 깔끔한 방식 중 하나는 <thead>
, <tfoot>
, 그리고 <tbody>
를 이용하는 방법이다. 각각 table의 header, footer, 그리고 body section을 mark up 한다.
이러한 elements는 screenreaders 사용자들의 접근성을 더 향상시키지도, 그 자체로서는 시각적으로 향상(디자인)이 되지도 않는다. 다만, 이 elements를 이용하면 styling과 layout을 하는데 있어 매우 유용하다(CSS를 Table에 적용할 수 있는 갈고리 역할). 흥미로울 법한 예시를 들자면, 데이터가 많은 tables에서 매 page마다 header와 footer가 반복되고 contents만 표시되게 한다면 사용자 입장에서 보기 편할 것이며 한 눈에 데이터가 들어올 것이다.
이러한 기능들을 사용하기 위해:
-
<thead>
element는 table의 header 역할을 하는 부분을 감싸야 한다. 대개 열의 대표값을 포함하는 첫째 행이 되고는 하지만 항상 그렇지는 않다. 만약<col>
/<colgroup>
element를 사용하고 있다면, table header는<col>
/<colgroup>
element의 아래에 와야 한다. -
<tfoot>
element는 table의 footer 역할을 하는 부분을 감싸야 한다. 예를 들어, 이 부분은 이전의 행들의 값들이 더해진 마지막 행이 될 수 있다. Table footer는 table의 아래쪽에 포함할 수도 있고, table header의 바로 아래에 포함할 수도 있다(어느 곳에 위치시키던지 Browser는 footer를 table의 아래쪽에 배치). -
<tbody>
element는 table의 header와 footer에 포함되지 않는 table content의 다른 부분들을 감싼다. 이 부분은 때로의 table header의 아래에, 때로는 footer의 아래에 배치되는데 이 부분은 개발자가 구조를 어떻게 설계하는지에 따라 달려 있다.
Note:
<tbody>
element는 모든 table에 포함되는데, 이는 개발자가 code에 명시하지 않아도 절대적으로 포함된다. 이 부분을 확인하기 위해서<tbody>
가 포함되지 않은 table을 browser developer tools로 확인하면 browser가 이 tag를 추가한 것을 볼 수 있을 것이다.
Purchase | Location | Date | Evaluation | Cost (€) |
---|---|---|---|---|
SUM | 118 | |||
Haircut | Hairdresser | 12/09 | Great idea | 30 |
Lasagna | Restaurant | 12/09 | Regrets | 18 |
Shoes | Shoeshop | 13/09 | Big regrets | 65 |
Toothpaste | Supermarket | 13/09 | Good | 5 |
<table>
<caption>
How I chose to spend my money
</caption>
<thead>
<tr>
<th>Purchase</th>
<th>Location</th>
<th>Date</th>
<th>Evaluation</th>
<th>Cost (€)</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="4">SUM</td>
<td>118</td>
</tr>
</tfoot>
<tbody>
<tr>
<td>Haircut</td>
<td>Hairdresser</td>
<td>12/09</td>
<td>Great idea</td>
<td>30</td>
</tr>
<tr>
<td>Lasagna</td>
<td>Restaurant</td>
<td>12/09</td>
<td>Regrets</td>
<td>18</td>
</tr>
<tr>
<td>Shoes</td>
<td>Shoeshop</td>
<td>13/09</td>
<td>Big regrets</td>
<td>65</td>
</tr>
<tr>
<td>Toothpaste</td>
<td>Supermarket</td>
<td>13/09</td>
<td>Good</td>
<td>5</td>
</tr>
</tbody>
</table>
내포(Nesting) Tables
하나의 table 안에 다른 table을 내포하는 것도 가능하다. 물론 이 경우, <table>
element를 포함시켜 완전한 구조로서 포함해야 한다. Mark up 표시를 혼란스럽게하고 screenreaders 사용자들에게 덜 접근적이라는 점에서 일반적으로 조언하는 방법은 아니다. 게다가 많은 경우, 추가 cells/rows/columns를 이미 존재하는 table에 추가하는 형태로 해결되기 때문이다. 그럼에도 불구하고 필요하다면 이 기능을 사용할 수 있다. 예를 들어 다른 sources에서 content를 쉽게 가져오는 경우를 들 수 있다.
다음의 markup은 간단한 내포 table을 보여준다:
title1 | title2 | title3 | |||
---|---|---|---|---|---|
| cell2 | cell3 | |||
cell4 | cell5 | cell6 |
<table id="table1">
<tr>
<th>title1</th>
<th>title2</th>
<th>title3</th>
</tr>
<tr>
<td id="nested">
<table id="table2">
<tr>
<td>cell1</td>
<td>cell2</td>
<td>cell3</td>
</tr>
</table>
</td>
<td>cell2</td>
<td>cell3</td>
</tr>
<tr>
<td>cell4</td>
<td>cell5</td>
<td>cell6</td>
</tr>
</table>
시각적 손상을 입은 사용자를 위한 Tables
어떻게 data tables를 이용하는지 간단히 상기해보자. Table은 데이터에 빠르게 접근해 다른 값들을 찾을 수 있는 간편한 도구다. 예를 들어, 2016년 8월에 Gent에서 얼만큼의 반지가 팔렸는지 찾는 것은 한 번의 눈흘김으로도 찾을 수 있을 정도로 간단하다. 정보를 이해하기 위해서 우리는 table에 있는 data의 행과 열 headers 교차점을 시각적으로 연합한다.
Clothes | Accessories | |||||
---|---|---|---|---|---|---|
Trousers | Skirts | Dresses | Bracelets | Rings | ||
Belgium | Antwerp | 56 | 22 | 43 | 72 | 23 |
Gent | 46 | 18 | 50 | 61 | 15 | |
Brussels | 51 | 27 | 38 | 69 | 28 | |
The Netherlands | Amsterdam | 89 | 34 | 69 | 85 | 38 |
Utrecht | 80 | 12 | 43 | 36 | 19 |
그러나 이러한 시각적 연합을 사용할 수 없다면? 위의 table을 어떻게 읽을 것인가? 시각에 손상을 입은 이용자들은 종종 web pages에 있는 정보를 탐색하기 위해 screenreader를 사용한다. 해당 이용자들이 일반적인 text를 읽는 것에는 문제가 없다. 그러나 table을 해석하는 것은 꽤 도전을 요구하는 일일 것이다. 그럼에도 불구하고 적절한 markup을 사용해서 시각적 연합을 컴퓨터 연산을 통한 요소로 전환할 수 있다.
이 기사의 이번 section은 더 접근가능한 tables를 만들기 위한 기술에 대해 설명할 것이다.
행과 열 headers 사용하기
Screenreaders는 모든 headers를 인식하여, 관계된 각각의 headers와 cells 사이에서 프로그램적 연합을 만들어 낸다. 행과 열 headers의 연합은 각각의 cell에 있는 특정 data를 해석하고 인식하게 하므로, screenreader 사용자들은 정상 시각을 가진 사용자들과 비슷한 형태의 table을 해석할 수 있게 된다.
scope 속성
scope
속성은 <th>
element에 추가할 수 있는 속성으로, screenreaders가 특정 header가 어떤 형태의 header로 cells를 가리키고 있는지 알 수 있게 한다. 다시 말하자면, 한 header가 행의 header인지, 열의 header인지 구분한다. 이전에 사용했던 예시로 돌아가 이 속성을 사용하게 되면 열의 headers를 보다 명확하게 명시할 수 있게 된다.
<thead>
<tr>
<th scope="col">Purchase</th>
<th scope="col">Location</th>
<th scope="col">Date</th>
<th scope="col">Evaluation</th>
<th scope="col">Cost (€)</th>
</tr>
</thead>
각각의 열은 header를 아래와 같이 가질 수 있다.
<tr>
<th scope="row">Haircut</th>
<td>Hairdresser</td>
<td>12/09</td>
<td>Great idea</td>
<td>30</td>
</tr>
Screenreaders는 이렇게 구조화된 markup을 인식할 것이며, 사용자들이 전체 행과 열을 한 번에 인식할 수 있게 한다.
scope
는 두 가지 더 가능한 값을 가진다 - colgroup
과 rowgroup
. 이 값들은 복수의 행과 열을 대표하는 상위 headings에 사용된다. “Items Sold August 2016” table로 돌아가서 보면 “Clothes” cell이 “Trousers”, “Skirts”, 그리고 “Dresses” cells 위에 안착 되어 있는 것을 볼 수 있을 것이다. 이러한 cells 모두 headers(<th>
)로 markup 되어 있어야 한다. 그러나 “Clothes”는 세 개의 subheadings를 정의하는 상위 heading이다. 그러므로 “Clothes”는 ``scope=”col” 보다는
scope=”colgroup”`이라는 속성을 가져야 한다.
id와 headers 속성들
scope
속성의 대안은 id
와 headers
속성들을 사용하여, headers와 cells 간 연합을 생성해주는 방법이 있다. 사용하는 방법은 다음과 같다:
-
<th>
element에 고유한id
를 추가한다. -
각각의
<td>
element에headers
속성을 추가한다. 각각의headers
속성에 해당 cell의 header 역할을 하는 모든<th>
elements의id
들을 space로 구분하여 각각 포함시키도록 한다.
이 방법은 spreadsheet과 같이 HTML table이 각각의 cell 위치를 명확하게 정의할 수 있도록 해준다. 이 방법이 잘 작동하기 위해서는 행과 열의 headers가 모두 필요하다. 위에 제시된 두 개의 snippets는 아래와 같이 다시 작성할 수 있다:
<thead>
<tr>
<th id="purchase">Purchase</th>
<th id="location">Location</th>
<th id="date">Date</th>
<th id="evaluation">Evaluation</th>
<th id="cost">Cost (€)</th>
</tr>
</thead>
<tbody>
<tr>
<th id="haircut">Haircut</th>
<td headers="location haircut">Hairdresser</td>
<td headers="date haircut">12/09</td>
<td headers="evaluation haircut">Great idea</td>
<td headers="cost haircut">30</td>
</tr>
...
</tbody>
Note: 이 방법은 headers와 data cells 간에 매우 정확한 연합을 생성하지만, 더 많은 markup을 사용하며 errors에 대한 표시가 되지 않는다. 대개 대부분의 tables에는
scope
접근방식만으로 충분하다.
저작권
Mozilla 기여자가 작성한 MDN에 대해는 CC-BY-SA 2.5 라이선스에 따라 사용할 수 있습니다.
이 저작물은 크리에이티브 커먼즈 저작자표시-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.