표(table)는 줄과 열을 맞춰 읽는 자료를 적는 요소입니다. table 안에 제목 caption, 머리 묶음 thead, 몸통 묶음 tbody가 들고, 묶음 안에는 줄 tr, 줄 안에는 칸 th · td가 듭니다. 열은 따로 적지 않고, 줄마다 칸 개수로 맞춰집니다.
영양 정보처럼 '열량'과 '550 kcal'가 한 줄로 짝을 이루는 자료는 목록으로 쓰면 짝이 흐트러집니다. 시간표나 가격표도 같은 모양입니다.
표는 여러 요소가 층층이 모여 만들어져, 한 겹이라도 빠지거나 칸 수가 어긋나면 화면에 빈 자리가 생깁니다.
이 레슨에서는 표를 바깥에서 안으로 짓는 차례, 칸 개수로 맞춰지는 열, 머리 칸 th를 봅니다.
1바깥에서 안으로 — table · caption · 묶음 · 줄 · 칸
<table>
<caption>영양 정보</caption>
<thead>
<tr>
<th>항목</th>
<th>양</th>
</tr>
</thead>
<tbody>
<tr>
<td>열량</td>
<td>550 kcal</td>
</tr>
</tbody>
</table>table의 읽는 이름영양 정보th의 역할columnheadertd의 역할cell
바깥에서 안으로 읽습니다. table 안에 표 제목 caption이 맨 처음 오고, 머리 줄들의 묶음 thead, 몸통 줄들의 묶음 tbody가 이어집니다. 묶음 안에는 줄 tr가, 줄 안에는 칸이 있습니다.
| 요소 | 원래 영어 | 뜻 |
|---|---|---|
caption | caption | 표 제목 — table 안 맨 처음 |
thead · tbody | table head · table body | 머리 줄 묶음 · 몸통 줄 묶음 |
tr | table row | 가로 한 줄 |
th · td | table header · table data | 머리 칸 · 자료 칸 |
caption의 글은 표의 읽는 이름(화면 읽기 프로그램이 이 표를 부르는 이름)이 됩니다. 잰 값의 역할 columnheader는 '그 열의 머리', cell은 '자료 칸'입니다 — 화면 읽기 프로그램은 칸을 읽을 때 그 열의 머리를 함께 알려 줄 수 있습니다(브라우저 규칙 3).
2열은 칸 개수로 맞춰진다 — 선은 없다
<table>
<tr>
<th>항목</th>
<th>양</th>
</tr>
<tr>
<td>열량</td>
<td>550 kcal</td>
</tr>
</table>table의 나무<tbody><tr> <th> 항목</th> <th> 양</th> </tr> <tr> <td> 열량</td> <td> 550 kcal</td> </tr> </tbody>
열은 코드 어디에도 없습니다. 줄마다 칸을 같은 개수로 쓰면 브라우저가 첫째 칸끼리, 둘째 칸끼리 세로로 맞춰 열을 짓습니다. 결과 화면에서 머리 칸은 굵게 가운데에, 자료 칸은 왼쪽에 놓이고(크롬 기준), 칸 사이에 선은 없습니다. 선은 CSS가 그립니다 — 10단원 '박스 모델'에서 자세히.
이 코드에는 tbody를 쓰지 않았는데, 잰 값의 나무에는 tbody가 있습니다. 브라우저가 줄들을 오류 없이 몸통 묶음에 넣어 나무를 고쳐 지은 것입니다(브라우저 규칙 2). 그래도 머리 줄과 몸통 줄이 갈리도록 thead · tbody를 직접 씁니다.
3머리 칸 th — 열의 머리, 줄의 머리
맨 위 줄의 th는 그 열의 머리입니다. 줄의 맨 앞 칸이 그 줄의 이름일 때는 th에 scope="row"를 붙여 '이 줄의 머리'라고 적습니다.
<table>
<tr>
<th scope="row">열량</th>
<td>550 kcal</td>
</tr>
<tr>
<th scope="row">나트륨</th>
<td>1550 mg</td>
</tr>
</table>th의 역할rowheader
역할이 rowheader(줄의 머리)로 바뀌었습니다. 화면에서는 위의 머리 칸처럼 굵게 그려질 뿐이지만, 화면 읽기 프로그램은 '550 kcal'를 읽을 때 그 줄의 머리 '열량'을 함께 알려 줄 수 있습니다.
예제
김치볶음밥 페이지의 영양 정보입니다. 열량과 나트륨 두 줄만 보였습니다 — 나머지 탄수화물 · 단백질 · 지방도 같은 꼴의 줄입니다.
<table>
<caption>1인분 기준</caption>
<thead>
<tr>
<th>항목</th>
<th>양</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">열량</th>
<td>550 kcal</td>
</tr>
</tbody>
</table>table의 읽는 이름1인분 기준thead th의 역할columnheadertbody th의 역할rowheader
잰 값의 thead th는 'thead 안의 th', tbody th는 'tbody 안의 th'라는 뜻입니다. 머리 줄의 '항목' · '양'은 열의 머리, 몸통 줄 앞의 '열량'은 줄의 머리입니다. 페이지에서는 이 표를 '영양 정보' 제목(h2) 아래에 둡니다.
자주 틀리는 곳
틀린 생각: 머리 칸은 td 안 글을 굵게 하면 된다.
굵게만 보이면 머리 칸처럼 보이니, td에 b를 넣어도 같아 보입니다.
<table>
<tr>
<td><b>항목</b></td>
<td><b>양</b></td>
</tr>
<tr>
<td>열량</td>
<td>550 kcal</td>
</tr>
</table>table의 역할(없음)td의 역할(없음)
화면에서는 머리 줄처럼 굵게 보이지만, 표와 칸의 역할이 모두 비었습니다. 크롬은 머리 칸 · 표 제목이 없는 이 표를 자료가 아니라 배치용 표로 짐작해, 표의 뜻을 지웠습니다. 읽는 쪽은 줄과 열이 있는 자료인 줄 모릅니다.
맞는 규칙: 머리 칸은 th로 씁니다. 모양(굵게 · 가운데)은 기본 스타일이 따로 입힐 뿐이고, 뜻은 요소 이름이 적습니다(브라우저 규칙 3).
틀린 생각: 표 제목은 표 위에 문단으로 쓴다.
화면에서 표 위에 글이 보이면 같아 보여, table 밖에 p로 제목을 씁니다.
<p>영양 정보</p>
<table>
<tr>
<th>항목</th>
<th>양</th>
</tr>
</table>table의 읽는 이름(없음)
표의 읽는 이름이 비었습니다. 문단은 표 밖의 따로 선 글이라, 읽는 쪽은 이 글이 아래 표의 제목인 줄 모릅니다.
맞는 규칙: 표 제목은 table 안 맨 처음에 caption으로 씁니다. 그 글이 표의 읽는 이름이 됩니다.
틀린 생각: 그림과 글을 나란히 놓으려면 표로 짠다.
표는 칸을 가로로 나란히 놓아 주니, 화면 배치에 쓰면 편해 보입니다. 예전 웹 페이지는 페이지 전체를 표로 짜기도 했습니다.
<table>
<tr>
<td>
<img
src="images/japchae.svg"
alt="잡채"
width="80"
height="60"
/>
</td>
<td>잡채 · 조리 45분</td>
</tr>
</table>table의 역할(없음)
그림과 글이 나란히 놓였고, 크롬은 머리 칸 · 표 제목이 없는 이 표를 배치용으로 짐작해 표의 뜻을 지웠습니다(역할 없음). 이 짐작은 브라우저가 하는 일이라, 다른 브라우저나 화면 읽기 프로그램은 자료 표로 읽을 수도 있습니다 — 그러면 몇 줄 몇 칸짜리 표라고 알리고 칸 단위로 읽어, 듣는 사람은 있지도 않은 자료를 따라갑니다.
맞는 규칙: 표는 줄과 열을 맞춰 읽는 자료에만 씁니다. 나란히 놓기는 CSS의 flex(12단원)와 grid(13단원)가 맡습니다.
확인 문제
1. 나트륨 줄 끝(9번 줄)에 칸 <td>많음</td>를 하나 더 넣었습니다. 결과 화면에서 머리 줄은 어떻게 될까요?
<table>
<tr>
<th>항목</th>
<th>양</th>
</tr>
<tr>
<td>나트륨</td>
<td>1550 mg</td>
<td>많음</td>
</tr>
</table>
- ① 셋째 열이 생기고, 머리 줄의 셋째 자리는 빈 자리다
- ② '많음'이 표 밖, 표 아래 줄에 따로 그려진다
- ③ 머리 줄의 '양' 칸이 넓어져 아래 두 칸을 덮는다
힌트
두 줄에 칸이 저마다 몇 개인지 세고, 브라우저가 열을 무엇으로 맞추는지 떠올립니다.
정답
① — 셋째 열이 생기고, 머리 줄의 셋째 자리는 빈 자리입니다.
th의 고른 글항목 · 양td의 고른 글나트륨 · 1550 mg · 많음
- 열은 줄마다의 칸 개수로 맞춰집니다. 칸이 셋인 줄이 생기면 표는 세 열이 되고, 칸이 둘뿐인 머리 줄의 셋째 자리는 빈 자리로 남습니다.
- ②는 칸이 넘치면 표 밖으로 밀려난다고 본 것입니다.
td안에 쓴 칸은 그 줄의 칸입니다. - ③은 머리 칸이 아래 칸 수에 맞춰 늘어난다고 본 것입니다. 칸은 쓴 개수만큼만 있습니다.
빈 9번 줄에 칸 <td>많음</td>를 넣어 보세요. 머리 줄의 오른쪽 끝을 보세요.
<table>
<tr>
<th>항목</th>
<th>양</th>
</tr>
<tr>
<td>나트륨</td>
<td>1550 mg</td>
</tr>
</table>여기서 고친 코드는 저장하지도 보내지도 않습니다. 새로 열면 처음 코드입니다.
2. 몸통 줄의 맨 앞 칸 '지방'은 그 줄의 이름입니다. ____ 자리에 알맞은 여는 태그를 쓰세요.
<tr>
____지방</th>
<td>30 g</td>
</tr>
힌트
맨 앞 칸이 자료가 아니라 머리라면 어느 칸 요소인지, 그리고 그 머리가 열의 머리인지 줄의 머리인지 봅니다.
정답
<th scope="row">
<table>
<tr>
<th scope="row">지방</th>
<td>30 g</td>
</tr>
</table>th의 역할rowheader
줄의 이름인 칸은 머리 칸 th이고, 줄의 머리라 scope="row"를 붙입니다. td로 쓰면 자료 칸 cell이 되어 머리라는 뜻이 사라집니다.
3. 플로우 카페 메뉴를 표로 썼습니다. 개발자 도구 Elements 패널에서 table을 펼치면 table 바로 안에 무엇이 보일까요?
<table>
<tr>
<th>메뉴</th>
<th>값</th>
</tr>
<tr>
<td>라테</td>
<td>4500원</td>
</tr>
</table>
- ① 쓴 대로
tr둘 - ②
tbody하나, 그 안에tr둘 - ③ 머리 줄은
thead에, 둘째 줄은tbody에
힌트
개발자 도구로 요소 나무 보기에서 Elements 패널이 무엇을 보이는 곳이었는지 떠올립니다.
힌트 둘
패널에 보이는 것이 파일의 글자인지, 브라우저가 지은 나무인지 가립니다.
정답
② — tbody 하나, 그 안에 tr 둘입니다.
table의 나무<tbody><tr> <th> 메뉴</th> <th> 값</th> </tr> <tr> <td> 라테</td> <td> 4500원</td> </tr> </tbody>
- 브라우저는
table바로 안의 줄들을 오류 없이 몸통 묶음tbody에 넣어 나무를 짓습니다. Elements 패널은 파일이 아니라 이 나무를 보입니다(브라우저 규칙 2). - ①은 나무가 늘 쓴 대로 지어진다고 본 것입니다.
- ③은 브라우저가
th가 든 줄을 알아서 머리 묶음으로 옮긴다고 본 것입니다. 머리 묶음은thead를 써야 생깁니다.
컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요.
hello.html의 body 안을 2절 코드로 바꿔 저장하고 엽니다. 그다음 열량 줄에서 <td>550 kcal</td> 줄을 지워 줄마다 칸 수를 다르게 하고, 저장 · 새로고침합니다. 열량 줄의 둘째 자리가 빈 자리로 남습니다. Elements 패널에서 table을 펼쳐 저절로 생긴 tbody도 봅니다.
파일을 만들고 여는 법은 준비: VS Code와 작업 폴더에 있습니다.