우리가 데이터 테이블을 어떻게 사용하는지 잠시 복습해 보겠습니다. 테이블은 데이터에 빠르게 접근하고 다양한 값을 찾아보는 데 매우 유용한 도구예요. 예를 들어, 아래 테이블을 쓱 보기만 해도 2016년 8월 헨트(Ghent) 지역에서 반지가 몇 개 팔렸는지 바로 알 수 있죠. 정보를 이해하기 위해 우리는 테이블 안의 데이터와 열(column) 및 행(row)의 헤더를 시각적으로 연결시킵니다.
| 의류 (Clothes) | 액세서리 (Accessories) | |||||
|---|---|---|---|---|---|---|
| 바지 (Trousers) | 치마 (Skirts) | 원피스 (Dresses) | 팔찌 (Bracelets) | 반지 (Rings) | ||
| 벨기에 (Belgium) | 안트베르펜 (Antwerp) | 56 | 22 | 43 | 72 | 23 |
| 헨트 (Ghent) | 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 |
그런데 만약 시각적으로 이런 연결을 할 수 없다면 어떨까요? 위와 같은 테이블을 어떻게 읽어낼 수 있을까요?
시각 장애가 있는 분들은 종종 웹페이지의 정보를 소리로 읽어주는 스크린 리더(Screen reader)를 사용합니다. 단순한 텍스트를 읽을 때는 문제가 없지만, 시각장애인에게 테이블을 해석하는 것은 상당히 까다로운 과제입니다. 하지만 걱정하지 마세요! 올바른 마크업(HTML)을 사용하면 시각적인 연결을 프로그래밍적인 연결로 훌륭하게 대체할 수 있답니다.
참고(Note): > 2017년 WHO 데이터에 따르면, 전 세계적으로 약 2억 5,300만 명의 사람들이 시각 장애를 안고 살아가고 있습니다. 접근성을 고려한 마크업은 선택이 아닌 필수랍니다!
스크린 리더는 모든 헤더를 식별하고, 해당 헤더와 관련된 데이터 셀 사이에 프로그래밍적인 연관성을 만듭니다. 열 헤더와 행 헤더의 조합을 통해 각 셀의 데이터를 식별하고 해석하여, 시각 장애가 있는 사용자도 비장애인 사용자와 거의 비슷하게 테이블을 이해할 수 있도록 도와줍니다.
헤더에 대한 내용은 이전 글인 요소로 헤더 추가하기에서 이미 다루었으니 참고해 주세요!
<caption>으로 테이블에 캡션 추가하기 (Adding a caption to your table with <caption>)테이블 콘텐츠 전체를 <caption> 요소로 감싸고, 이를 <table> 요소 안에 중첩시켜 테이블에 캡션(제목이나 설명)을 달 수 있습니다. <caption> 태그는 반드시 여는 <table> 태그 바로 아래에 배치해야 합니다.
<table>
<caption>
쥬라기 시대의 공룡들 (Dinosaurs in the Jurassic period)
</caption>
</table>
위의 간단한 예제에서 유추할 수 있듯이, 캡션은 테이블의 내용에 대한 설명을 담고 있습니다. 이는 문서를 훑어보면서 테이블이 자신에게 유용한지 빠르게 파악하고자 하는 모든 사용자에게 유용하지만, 특히 시각 장애가 있는 사용자에게 절대적으로 유용합니다. 사용자가 이 테이블이 대체 무슨 내용인지 알기 위해 스크린 리더로 수많은 셀의 내용을 일일이 읽어보는 대신, 캡션만 듣고 이 테이블을 자세히 읽을지 말지 바로 결정할 수 있으니까요. 시간을 엄청나게 아껴주는 배려 깊은 태그입니다!
강사의 꿀팁 💡: > React 기반 환경에서도 컴포넌트 단위로 개발할 때, Table 컴포넌트의 props로
caption텍스트를 받아 처리하도록 설계하면 접근성을 강제할 수 있어서 아주 좋은 패턴이 됩니다!
다시 한번 강조하자면, 캡션은 <table> 태그 바로 아래에 위치해야 합니다.
참고(Note):
<table>요소의summary속성도 설명을 제공하는 데 사용할 수 있으며, 스크린 리더가 이 내용도 읽어줍니다. 하지만summary속성은 웹 표준에서 사용 중단(deprecated) 되었고, 일반 시각적 사용자에게는 화면에 보이지 않기 때문에 대신<caption>요소를 사용하는 것을 강력히 권장합니다.
이제 이전 글에서 보았던 학교 시간표를 사용하여 HTML 테이블에 캡션을 직접 추가해 보는 실습을 해볼까요?
<colgroup>과 <col>로 열 그룹화하기 에 있는 첫 번째 HTML 코드 블록을 컴퓨터의 HTML 파일이나 CodePen, JSBin과 같은 온라인 에디터에 복사하세요.완성된 HTML 코드는 대략 다음과 같은 모습일 것입니다
<table>
<caption>
성 위니프레드 학교의 주간 어학 수업 시간표 (St. Winnifred's weekly language lesson timetable)
</caption>
<colgroup>
<col span="2" />
<col class="column-background" />
<col class="column-fixed-width" />
<col class="column-background" />
<col class="column-background-border" />
<col span="2" class="column-fixed-width" />
</colgroup>
</table>
<thead>, <tbody>, <tfoot>으로 구조 더하기 (Adding structure with <thead>, <tbody>, and <tfoot>)테이블의 구조가 조금씩 복잡해질수록, 구조를 더 명확하게 정의해 주는 것이 좋습니다. 이를 위한 가장 깔끔한 방법은 <thead>, <tbody>, 그리고 <tfoot> 요소를 사용하는 것입니다. 이 요소들은 테이블의 헤더(header), 본문(body), 바닥글(footer) 영역을 명확히 구분하여 마크업할 수 있게 해줍니다.
이 요소들 자체가 테이블을 스크린 리더 사용자에게 곧바로 더 접근성 높게 만들어주거나 시각적인 변화를 일으키는 것은 아닙니다. 하지만, CSS를 통한 스타일링과 레이아웃 개선에 매우 유용하게 쓰이며, 이는 결과적으로 접근성을 향상시키는 데 기여합니다. 흥미로운 활용 예시를 하나 들어볼게요. 아주 긴 테이블을 인쇄해야 할 때, <thead>와 <tfoot>을 사용하면 인쇄되는 모든 페이지마다 테이블 헤더와 바닥글이 반복해서 출력되도록 만들 수 있습니다. 또한, 웹 화면에서는 본문(<tbody>) 영역만 스크롤이 되도록 만들어서 테이블 헤더는 항상 고정된 상태로 데이터를 편하게 볼 수 있게 레이아웃을 구성할 수도 있죠.
이 요소들을 사용할 때는 반드시 다음 순서를 지켜야 합니다:
<thead> 요소는 테이블의 헤더가 되는 부분을 감싸야 합니다. 보통 열의 제목이 들어가는 첫 번째 행이 되지만, 항상 그런 것은 아닙니다. 만약 <col>/<colgroup> 요소를 사용하고 있다면, 테이블 헤더는 그 바로 아래에 와야 합니다.<tbody> 요소는 테이블 헤더나 바닥글이 아닌 테이블 내용의 핵심(본문) 부분을 감싸야 하며, 반드시 <thead> 다음에 와야 합니다.<tfoot> 요소는 테이블의 바닥글 부분을 감싸야 합니다. 예를 들어, 이전 행들의 합계가 들어가는 마지막 줄이 될 수 있습니다. <tfoot>은 <tbody> 다음에 배치해야 합니다.참고(Note):
만약 코드에 명시적으로 적지 않더라도, 브라우저는 암묵적으로 테이블 안에 항상<tbody>를 포함시킵니다. 이를 확인하고 싶다면,<tbody>를 넣지 않은 예전 예제 중 하나를 열고 브라우저의 개발자 도구(Developer Tools)에서 HTML 코드를 살펴보세요. 브라우저가 알아서 이 태그를 추가해 둔 것을 볼 수 있을 것입니다.
"브라우저가 알아서 해주면 굳이 내가 적을 필요가 있나?"라고 생각하실 수도 있지만, 테이블의 구조와 스타일을 여러분이 완벽하게 통제하기 위해서는 반드시 명시적으로 작성하는 것이 좋습니다!
자, 이제 이 새로운 요소들을 실제로 어떻게 적용하는지 연습해 봅시다.
spending-record.html이라는 새로운 HTML 파일을 만들고 <body> 안에 다음 HTML 코드를 넣습니다:<h1>나의 지출 기록 (My spending record)</h1>
<table>
<caption>
내가 돈을 어디에 썼는가 (How I chose to spend my money)
</caption>
<tr>
<th>구매 항목 (Purchase)</th>
<th>장소 (Location)</th>
<th>날짜 (Date)</th>
<th>평가 (Evaluation)</th>
<th>비용 (€) (Cost)</th>
</tr>
<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>신발 가게 (Shoe shop)</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>
<tr>
<td>합계 (SUM)</td>
<td>118</td>
</tr>
</table>
minimal-table.css라는 CSS 파일을 만들고 다음 내용을 채워 넣습니다:html {
font-family: sans-serif;
}
table {
border-collapse: collapse;
border: 2px solid rgb(200 200 200);
letter-spacing: 1px;
font-size: 0.8rem;
}
td,
th {
border: 1px solid rgb(190 190 190);
padding: 10px 20px;
}
th {
background-color: rgb(235 235 235);
}
td {
text-align: center;
}
tr:nth-child(even) td {
background-color: rgb(250 250 250);
}
tr:nth-child(odd) td {
background-color: rgb(245 245 245);
}
caption {
padding: 10px;
}
HTML의 <head> 태그 안에 <link> 요소를 추가하여 CSS를 HTML에 적용하세요 (도움이 필요하다면 HTML에 CSS와 JavaScript 적용하기를 참고하세요).
누가 봐도 헤더인 첫 번째 행(row)을 <thead> 요소로 감싸고, "합계(SUM)"가 있는 행을 <tfoot> 요소로 감싼 뒤, 나머지 본문 내용 전체를 <tbody> 요소 안에 넣어보세요.
다음으로, colspan 속성을 추가하여 "합계(SUM)" 셀이 첫 번째부터 네 번째 열까지 가로지르게 만들어보세요. 그러면 실제 숫자(118)가 "비용(Cost)" 열의 맨 아래에 예쁘게 맞춰질 것입니다.
이 요소들이 CSS를 적용할 때 얼마나 유용한지 보여드리기 위해 간단한 스타일을 추가해 보겠습니다. CSS 파일에 다음 코드를 추가하세요:
tbody {
font-size: 95%;
font-style: italic;
}
tfoot {
font-weight: bold;
}
참고(Note):
지금 당장 이 CSS 코드를 완벽하게 이해하지 못해도 괜찮습니다. CSS 모듈(특히 테이블 스타일링에 초점을 맞춘 테이블 스타일링 문서가 포함된 CSS 스타일링 기초 과정)을 학습하면서 자연스럽게 알게 되실 거예요.
<tbody>와 <tfoot> 요소가 제자리에 없었다면, 이와 똑같은 스타일을 적용하기 위해 훨씬 더 복잡한 CSS 선택자와 규칙을 작성해야 했을 겁니다.완성된 예제의 모습은 다음과 같아야 합니다:
완성된 HTML 코드는 다음과 같아야 합니다
<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>
<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>신발 가게 (Shoe shop)</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>
<tfoot>
<tr>
<td colspan="4">합계 (SUM)</td>
<td>118</td>
</tr>
</tfoot>
</table>
scope 속성 (The scope attribute)scope 속성은 요소에 추가되어 스크린 리더에게 이 헤더가 정확히 어떤 셀들의 제목 역할을 하는지 (자신이 속한 행의 헤더인지, 아니면 열의 헤더인지)를 알려줍니다. 앞서 다루었던 '나의 지출 기록' 예제로 돌아가서, 열(Column) 헤더들을 열 헤더로 아주 명확하게 지정하려면 다음과 같이 작성할 수 있습니다:
<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>
그리고 만약 각 행(Row)에도 행 헤더가 존재했다면, 다음과 같이 정의할 수 있었을 것입니다:
<tr>
<th scope="row">이발 (Haircut)</th>
<td>미용실 (Hairdresser)</td>
<td>12/09</td>
<td>아주 좋음 (Great idea)</td>
<td>30</td>
</tr>
스크린 리더는 이처럼 꼼꼼하게 구조화된 마크업을 인식하여, 사용자가 전체 열이나 전체 행을 한 번에 소리로 읽어 내려갈 수 있도록 지원합니다.
강사의 꿀팁 💡: > React나 Next.js를 학습하셨다면 컴포넌트화를 고민하실 텐데요!
<TableHeader />같은 컴포넌트를 만들 때 내부적으로scope="col"을 기본값으로 뿌려주도록 설계하면, 매번 번거롭게 속성을 적지 않아도 접근성이 뛰어난 컴포넌트 시스템을 구축할 수 있습니다.
scope에는 두 가지 값을 더 사용할 수 있습니다. 바로 colgroup과 rowgroup입니다. 이 값들은 여러 열이나 여러 행의 상단에 걸쳐 있는 커다란 그룹 헤더에 사용됩니다.
이 섹션의 맨 처음에 보았던 "2016년 8월 판매 품목" 테이블을 다시 보면, "의류(Clothes)"라는 셀이 "바지(Trousers)", "치마(Skirts)", "원피스(Dresses)" 셀의 위쪽에 자리 잡고 있습니다. 이 모든 셀들은 헤더(<th>)로 마크업 되어야 하지만, "의류"는 다른 세 가지 하위 헤더들을 아우르고 정의하는 상위 헤더입니다. 따라서 "의류"에는 scope="colgroup"을 부여하고, 나머지 하위 항목에는 scope="col"을 지정해야 합니다.
<thead>
<tr>
<th colspan="3" scope="colgroup">의류 (Clothes)</th>
</tr>
<tr>
<th scope="col">바지 (Trousers)</th>
<th scope="col">치마 (Skirts)</th>
<th scope="col">원피스 (Dresses)</th>
</tr>
</thead>
여러 행이 그룹화된 헤더의 경우도 마찬가지입니다. 다시 "2016년 8월 판매 품목" 테이블로 돌아가서, 이번에는 "암스테르담(Amsterdam)"과 "위트레흐트(Utrecht)" 헤더(<th>)가 있는 행을 보세요. 이 두 하위 헤더를 묶어주는 "네덜란드(The Netherlands)" 헤더 역시 <th>로 마크업 되어 있으며 두 개의 행에 걸쳐 있습니다. 이럴 때는 scope="rowgroup"을 지정하여 스크린 리더가 행 그룹의 연관성을 올바르게 연결할 수 있도록 도와줘야 합니다:
<tr>
<th rowspan="2" scope="rowgroup">네덜란드 (The Netherlands)</th>
<th scope="row">암스테르담 (Amsterdam)</th>
<td>89</td>
<td>34</td>
<td>69</td>
</tr>
<tr>
<th scope="row">위트레흐트 (Utrecht)</th>
<td>80</td>
<td>12</td>
<td>43</td>
</tr>
id와 headers 속성 (The id and headers attributes)scope 속성을 사용하는 대신 id와 headers 속성을 조합하여 데이터 셀과 헤더 셀 간의 관계를 만들 수도 있습니다.
<th> 요소는 데이터 셀(<td>)의 제목이 될 수도 있고, 더 복잡한 테이블에서는 다른 헤더 셀(<th>)의 제목이 될 수도 있습니다. 이를 통해 하나의 헤더가 여러 다른 헤더들을 묘사하는 계층적이거나 그룹화된 헤더를 만들 수 있습니다.
headers 속성은 셀(<td> 또는 <th>)을 하나 또는 여러 개의 헤더 셀과 연결하는 데 사용됩니다. 이 속성에는 공백으로 구분된 문자열(Strings) 목록이 값으로 들어가며, 문자열의 순서는 중요하지 않습니다. 각 문자열은 이 셀과 연관된 <th> 요소의 고유한 id 값과 반드시 일치해야 합니다.
이 방법은 테이블의 각 셀이 어느 열과 어느 행에 속하는지 마치 엑셀 스프레드시트처럼 훨씬 더 명시적이고 엄격하게 위치를 정의해 줍니다. 이것이 잘 작동하려면 테이블에 반드시 열 헤더와 행 헤더가 모두 포함되어 있어야 합니다.
"2016년 8월 판매 품목" 예제 중 일부분을 살펴보며 id와 headers 속성을 어떻게 사용하는지 알아보겠습니다:
<th> 요소에 고유한 id를 추가합니다.<th> 요소에 headers 속성을 추가합니다. 값으로는 최상위 헤더의 id를 적습니다. 우리 예제에서는 열 헤더의 경우 "clothes", 행 헤더의 경우 "belgium"이 됩니다.<td> 요소에 headers 속성을 추가하고, 해당 셀을 설명해 주는 연관된 <th> 요소들의 id를 공백으로 구분하여 쭈욱 적어줍니다. 스프레드시트를 볼 때처럼 생각하시면 됩니다. 데이터 셀을 하나 짚은 다음, 그 셀을 설명하는 행과 열의 헤더를 찾아 올라가는 것이죠. 명시되는 id의 순서는 상관없지만, 일관성 있게 작성하면 코드를 깔끔하게 유지하고 가독성을 높일 수 있습니다.<thead>
<tr>
<th></th>
<th></th>
<th id="clothes" colspan="3">의류 (Clothes)</th>
</tr>
<tr>
<th></th>
<th></th>
<th id="trousers" headers="clothes">바지 (Trousers)</th>
<th id="skirts" headers="clothes">치마 (Skirts)</th>
<th id="dresses" headers="clothes">원피스 (Dresses)</th>
</tr>
</thead>
<tbody>
<tr>
<th id="belgium" rowspan="2">벨기에 (Belgium)</th>
<th id="antwerp" headers="belgium">안트베르펜 (Antwerp)</th>
<td headers="belgium antwerp clothes trousers">56</td>
<td headers="belgium antwerp clothes skirts">22</td>
<td headers="belgium antwerp clothes dresses">43</td>
</tr>
<tr>
<th id="ghent" headers="belgium">헨트 (Ghent)</th>
<td headers="belgium ghent clothes trousers">41</td>
<td headers="belgium ghent clothes skirts">17</td>
<td headers="belgium ghent clothes dresses">35</td>
</tr>
</tbody>
이 예제를 살펴보면:
"Belgium"의 <th>는 rowspan="2"를 사용해 "Antwerp"와 "Ghent"를 모두 덮고 있습니다."Antwerp"와 "Ghent")은 headers 속성으로 "belgium"을 참조하여 자신들이 벨기에 그룹에 속해 있음을 보여줍니다.<td> 셀은 국가(belgium), 도시(antwerp 또는 ghent), 범주(clothes), 그리고 구체적인 옷 종류(trousers, skirts, dresses)를 모두 headers 속성 안에 나열하고 있습니다.참고(Note):
이 방식은 헤더와 데이터 셀 간의 아주아주 정밀한 연관 관계를 만들어냅니다. 하지만 보시다시피 엄청나게 많은 마크업 코드를 써야 하고, 오타 같은 실수가 발생할 여지도 너무 많습니다. 실무에서는 특별히 극도로 복잡한 테이블이 아닌 이상, 대부분의 경우scope방식을 사용하는 것만으로도 접근성 확보에 충분하답니다!
마지막 연습으로, 위에서 소개했던 샘플 테이블에 직접 scope와 headers를 적용해 보겠습니다.
scope 속성들을 직접 추가해 보세요.id와 headers 속성을 사용하여 정밀하고 명시적인 관계를 정의하여 테이블의 접근성을 높여 보세요.첫 번째 방식(scope 사용)의 완성된 HTML은 대략 다음과 같은 모습이어야 합니다
<table>
<caption>
2016년 8월 판매 품목 (Items Sold August 2016)
</caption>
<thead>
<tr>
<td colspan="2" rowspan="2"></td>
<th colspan="3" scope="colgroup">의류 (Clothes)</th>
<th colspan="2" scope="colgroup">액세서리 (Accessories)</th>
</tr>
<tr>
<th scope="col">바지 (Trousers)</th>
<th scope="col">치마 (Skirts)</th>
<th scope="col">원피스 (Dresses)</th>
<th scope="col">팔찌 (Bracelets)</th>
<th scope="col">반지 (Rings)</th>
</tr>
</thead>
<tbody>
<tr>
<th rowspan="3" scope="rowgroup">벨기에 (Belgium)</th>
<th scope="row">안트베르펜 (Antwerp)</th>
<td>56</td>
<td>22</td>
<td>43</td>
<td>72</td>
<td>23</td>
</tr>
<tr>
<th scope="row">헨트 (Ghent)</th>
<td>46</td>
<td>18</td>
<td>50</td>
<td>61</td>
<td>15</td>
</tr>
<tr>
<th scope="row">브뤼셀 (Brussels)</th>
<td>51</td>
<td>27</td>
<td>38</td>
<td>69</td>
<td>28</td>
</tr>
<tr>
<th rowspan="2" scope="rowgroup">네덜란드 (The Netherlands)</th>
<th scope="row">암스테르담 (Amsterdam)</th>
<td>89</td>
<td>34</td>
<td>69</td>
<td>85</td>
<td>38</td>
</tr>
<tr>
<th scope="row">위트레흐트 (Utrecht)</th>
<td>80</td>
<td>12</td>
<td>43</td>
<td>36</td>
<td>19</td>
</tr>
</tbody>
</table>
두 번째 방식(id와 headers 사용)의 완성된 모습은 다음과 같아야 합니다
<table>
<caption>
2016년 8월 판매 품목 (Items Sold August 2016)
</caption>
<thead>
<tr>
<td colspan="2" rowspan="2"></td>
<th colspan="3" id="clothes">의류 (Clothes)</th>
<th colspan="2" id="accessories">액세서리 (Accessories)</th>
</tr>
<tr>
<th id="trousers" headers="clothes">바지 (Trousers)</th>
<th id="skirts" headers="clothes">치마 (Skirts)</th>
<th id="dresses" headers="clothes">원피스 (Dresses)</th>
<th id="bracelets" headers="accessories">팔찌 (Bracelets)</th>
<th id="rings" headers="accessories">반지 (Rings)</th>
</tr>
</thead>
<tbody>
<tr>
<th rowspan="3" id="belgium">벨기에 (Belgium)</th>
<th id="antwerp" headers="belgium">안트베르펜 (Antwerp)</th>
<td headers="antwerp belgium clothes trousers">56</td>
<td headers="antwerp belgium clothes skirts">22</td>
<td headers="antwerp belgium clothes dresses">43</td>
<td headers="antwerp belgium accessories bracelets">72</td>
<td headers="antwerp belgium accessories rings">23</td>
</tr>
<tr>
<th id="ghent" headers="belgium">헨트 (Ghent)</th>
<td headers="ghent belgium clothes trousers">46</td>
<td headers="ghent belgium clothes skirts">18</td>
<td headers="ghent belgium clothes dresses">50</td>
<td headers="ghent belgium accessories bracelets">61</td>
<td headers="ghent belgium accessories rings">15</td>
</tr>
<tr>
<th id="brussels" headers="belgium">브뤼셀 (Brussels)</th>
<td headers="brussels belgium clothes trousers">51</td>
<td headers="brussels belgium clothes skirts">27</td>
<td headers="brussels belgium clothes dresses">38</td>
<td headers="brussels belgium accessories bracelets">69</td>
<td headers="brussels belgium accessories rings">28</td>
</tr>
<tr>
<th rowspan="2" id="netherlands">네덜란드 (The Netherlands)</th>
<th id="amsterdam" headers="netherlands">암스테르담 (Amsterdam)</th>
<td headers="amsterdam netherlands clothes trousers">89</td>
<td headers="amsterdam netherlands clothes skirts">34</td>
<td headers="amsterdam netherlands clothes dresses">69</td>
<td headers="amsterdam netherlands accessories bracelets">85</td>
<td headers="amsterdam netherlands accessories rings">38</td>
</tr>
<tr>
<th id="utrecht" headers="netherlands">위트레흐트 (Utrecht)</th>
<td headers="utrecht netherlands clothes trousers">80</td>
<td headers="utrecht netherlands clothes skirts">12</td>
<td headers="utrecht netherlands clothes dresses">43</td>
<td headers="utrecht netherlands accessories bracelets">36</td>
<td headers="utrecht netherlands accessories rings">19</td>
</tr>
</tbody>
</table>
GitHub에서도 완성된 예제를 확인할 수 있습니다: