1. ホーム
  2. HTML

【HTML】テーブル(table)の作り方|thead・tbody・colspan・rowspan を解説

Share

料金プランや成績表のように「行と列で整理されたデータ」を Web ページに載せたいとき、HTML では <table> を使ってテーブル(表)を作ります。この記事では、<table><tr><th><td> の基本から、<thead><tbody><tfoot> による構造化、表のタイトルを付ける <caption>colspanrowspan によるセルの結合、そして見出しセルにアクセシビリティを与える scope 属性までを、初心者の方にも分かるよう順を追って解説します。基本の表から少しずつ機能を足していくので、コピーして手元で試しながら読み進めてみてください。

テーブルは何のために使うのか

HTML のテーブルは、行(横方向)と列(縦方向)のマス目でデータを整理して見せるための仕組みです。表計算ソフトの一覧表をイメージすると分かりやすいでしょう。料金表、商品スペックの比較、時間割、成績表のように「縦横の見出しがあって、その交点に値が入る」データはテーブルの得意分野です。

ここで最初に押さえておきたい大切な原則があります。テーブルは「表形式のデータ」を表すための要素であり、ページのレイアウト(段組みや横並び)を組む目的では使いません。かつては <table> でページ全体の枠組みを作る手法もありましたが、今では非推奨です。要素を横に並べたり段組みにしたりしたいときは、CSS の Grid や Flexbox を使います。テーブルはあくまで「これは表データです」という意味を持つ要素だと考えてください。

テーブルを構成する基本のタグ

テーブルは、いくつかのタグを入れ子にして組み立てます。まずは中心となる4つのタグと、本記事で扱う構造化・結合のためのタグの役割を一覧で確認しておきましょう。

タグ役割
<table>表全体を囲む大枠。この中に行やセルを入れていく。
<tr>表の1行(table row)。この中に見出しセルやデータセルを並べる。
<th>見出しセル(table header)。列や行のタイトルに使う。既定では太字・中央寄せで表示される。
<td>データセル(table data)。実際の値を入れる通常のセル。
<caption>表のタイトル(説明)。<table> の先頭に書く。
<thead> / <tbody> / <tfoot>それぞれ表の「ヘッダー行」「本体行」「フッター行」をまとめるグループ。

覚え方としては、<table> という箱の中に <tr>(行)を縦に積み、各 <tr> の中に <th><td>(セル)を横に並べていく、という入れ子の構造です。セルが「列」を作るのではなく、各行の中で同じ位置にあるセルが結果的に縦の列になる、という点を意識すると組み立てやすくなります。

基本の表を作ってみる

まずは最小構成のテーブルを作ってみましょう。1行目に列の見出し(<th>)を並べ、2行目以降にデータ(<td>)を入れます。次の例は、3つのプランの料金を並べた簡単な表です。

index.html
<table>
  <!-- 1行目:列の見出し -->
  <tr>
    <th>プラン</th>
    <th>月額料金</th>
    <th>容量</th>
  </tr>
  <!-- 2行目以降:データ -->
  <tr>
    <td>フリー</td>
    <td>0円</td>
    <td>1GB</td>
  </tr>
  <tr>
    <td>スタンダード</td>
    <td>980円</td>
    <td>50GB</td>
  </tr>
  <tr>
    <td>プレミアム</td>
    <td>1,980円</td>
    <td>200GB</td>
  </tr>
</table>

<tr> の中に同じ数のセルを並べているのがポイントです。1行目の <th> が3つ、データ行の <td> も3つずつなので、きれいな3列の表になります。<th> は見出しセルなので、ブラウザの初期表示では太字で中央に寄って表示され、データの <td> と見分けやすくなります。

thead・tbody・tfoot と caption で構造化する

行数が増えてくると、「どこが見出し行で、どこが本体のデータか」を構造として明示したくなります。そこで使うのが <thead>(ヘッダー)、<tbody>(本体)、<tfoot>(フッター)の3つのグループです。それぞれ複数の <tr> をまとめる役割を持ちます。さらに <caption><table> の先頭に置くと、その表のタイトル(何の表なのか)を示せます。

index.html
<table>
  <!-- 表のタイトル -->
  <caption>料金プラン一覧(2026年版)</caption>

  <!-- 見出し行のグループ -->
  <thead>
    <tr>
      <th>プラン</th>
      <th>月額料金</th>
      <th>容量</th>
    </tr>
  </thead>

  <!-- 本体のデータ行のグループ -->
  <tbody>
    <tr>
      <td>フリー</td>
      <td>0円</td>
      <td>1GB</td>
    </tr>
    <tr>
      <td>スタンダード</td>
      <td>980円</td>
      <td>50GB</td>
    </tr>
  </tbody>

  <!-- 合計などをまとめるフッター行のグループ -->
  <tfoot>
    <tr>
      <td>合計</td>
      <td>980円</td>
      <td>51GB</td>
    </tr>
  </tfoot>
</table>

これらのグループ分けには見た目以上のメリットがあります。まずコードの意味が明確になり、どこが見出しでどこが本体なのかが一目で分かります。次に、長い表を印刷したときに <thead><tfoot> を各ページの上下に繰り返し表示する、といったブラウザの機能が働きます。また CSS で「本体行だけに縞模様を付ける」「ヘッダーだけ背景色を変える」といったスタイル指定もしやすくなります。<caption> はスクリーンリーダーが「この表は何の表か」を読み上げる手がかりにもなるため、表の内容を一言で表すタイトルを付けておくとよいでしょう。

なお HTML の仕様上、ソースコード内では <tfoot><tbody> より前や後ろのどちらに書いても、表示は表の最下部になります。迷ったら <thead><tbody><tfoot> の順に書いておけば、読み手にも分かりやすく安全です。

colspan・rowspan でセルを結合する

表を作っていると、「ここは隣のセルとひとまとめにしたい」という場面が出てきます。Excel でいう「セルの結合」です。HTML では、<th><td>colspan 属性と rowspan 属性を付けることで実現します。

colspan横方向(列方向)に何個分のセルをまとめるかを表します。colspan="2" なら、そのセルが横に2列分の幅を占めます。一方 rowspan縦方向(行方向)に何行分のセルをまとめるかを表し、rowspan="2" なら縦に2行分の高さを占めます。次の例では、上部に「2026年度」という見出しを横3列ぶち抜き(colspan)で置き、左端の「上半期」を縦2行ぶち抜き(rowspan)でまとめています。

index.html
<table>
  <caption>売上集計</caption>
  <tr>
    <!-- 横に3列ぶんを1つのセルに結合 -->
    <th colspan="3">2026年度</th>
  </tr>
  <tr>
    <th>期間</th>
    <th>月</th>
    <th>売上</th>
  </tr>
  <tr>
    <!-- 縦に2行ぶんを1つのセルに結合 -->
    <th rowspan="2">上半期</th>
    <td>4月</td>
    <td>120万円</td>
  </tr>
  <tr>
    <!-- 左端は上のセルに吸収されるので td を書かない -->
    <td>5月</td>
    <td>150万円</td>
  </tr>
</table>

注目してほしいのは最後の行です。直前の行で「上半期」のセルが rowspan="2" によって縦に伸びているため、この行ではその位置がすでに埋まっています。したがって最後の <tr> には先頭の <th> を書かず、「5月」と「150万円」の2つのセルだけを書きます。結合したぶんだけ、後続の行はセルの数を減らす——これが colspan / rowspan を使うときのいちばんのコツです。

th の scope 属性でアクセシビリティを高める

見た目だけなら <th> を置けば見出しらしく表示されますが、スクリーンリーダーを使う人にとっては「その見出しが列の見出しなのか、行の見出しなのか」が重要になります。これを明示するのが <th>scope 属性です。

scope="col" は「この見出しは縦の列全体に対する見出しである」ことを、scope="row" は「この見出しは横の行全体に対する見出しである」ことを表します。次の例のように、1行目の列見出しには scope="col"、各行の先頭にある行見出しには scope="row" を付けます。

index.html
<table>
  <caption>科目別の成績</caption>
  <thead>
    <tr>
      <!-- 空欄。右隣から各科目の列見出しが続く -->
      <td></td>
      <th scope="col">国語</th>
      <th scope="col">数学</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <!-- 行の先頭は、その行全体の見出し -->
      <th scope="row">1学期</th>
      <td>80点</td>
      <td>75点</td>
    </tr>
    <tr>
      <th scope="row">2学期</th>
      <td>85点</td>
      <td>90点</td>
    </tr>
  </tbody>
</table>

こうしておくと、スクリーンリーダーは「2学期・数学・90点」のように行と列の見出しをセルの値と関連付けて読み上げられるようになります。見出しと値の対応がはっきりするため、表のどこを読んでいるのか分からなくなる事態を防げます。縦横どちらにも見出しがあるような表では、scope を付ける習慣をつけておくと親切です。

罫線や余白は CSS で整える

ここまでの例をそのままブラウザで表示すると、罫線のない素っ気ない見た目になります。テーブルの罫線・余白・文字寄せといった見た目は、HTML ではなく CSS で整えるのが基本です。HTML はあくまでデータの構造を表し、装飾は CSS が担う、という役割分担です。

よく使うのは、セルに罫線を引く border、隣り合うセルの罫線を1本にまとめる border-collapse: collapse;、そしてセル内に余白を作る padding です。次のように指定すると、見慣れた表らしい見た目になります。

style.css
table {
  /* 隣り合うセルの罫線を1本に重ねる */
  border-collapse: collapse;
}

th,
td {
  border: 1px solid #ccc; /* セルに罫線 */
  padding: 8px 12px;      /* セル内に余白 */
}

テーブルの装飾には背景色の縞模様や角丸など奥が深いテクニックもありますが、まずは border-collapsepadding を覚えておけば、データが読みやすい表を作れます。CSS の詳しい指定は本記事の範囲を超えるので、ここでは「見た目は CSS で整える」という考え方だけ押さえておいてください。

セルがずれる・結合がおかしくなる原因

テーブルでつまずきやすいのは、表示したときにセルがガタガタにずれたり、結合が思った通りにならなかったりするケースです。原因の多くはいくつかのパターンに集約されるので、代表的なものを見ていきましょう。

各行のセル数が揃っていない

結合を使っていないのに表がずれる場合、まず疑うべきは行ごとのセルの数が揃っていないことです。ある行は <td> が3つなのに、別の行は2つしかない、といった状態だと列がぴったり並びません。<th><td> の閉じタグ(</td>)を書き忘れて隣のセルとくっついてしまうのもよくある原因です。各 <tr> の中のセルの数を、列数と一致しているか1行ずつ数えて確認してみてください。

colspan・rowspan の数とセル数が合っていない

結合を使ったときにレイアウトが崩れる原因は、ほとんどがcolspan / rowspan で指定した数と、実際に書いたセルの数のつじつまが合っていないことです。たとえば colspan="2" を付けたセルは横2列ぶんを占めるので、その行の他のセルはそのぶん減らさなければなりません。同様に rowspan="2" を付けたら、次の行ではそのセルの位置が埋まっているので、後続の行のセルを1つ減らします。「結合したぶんだけ、ぶつかる行・列のセルを書かない」というルールを守れているか、結合のたびに前後の行のセル数を数え直すのが確実です。

th と td の役割を取り違えている

見出しに <td> を使ってしまったり、逆にただのデータを <th> にしてしまうのも避けたい間違いです。見た目は CSS で何とでもなりますが、<th><td>「見出しか、データか」という意味の違いを持っています。見出しを <td> で書くと、スクリーンリーダーがそのセルを見出しとして扱えず、scope による行・列の関連付けも効きません。データの一覧で「行や列のタイトルになっているセル」は <th>、「実際の値」は <td> と、意味で使い分けてください。

まとめ

HTML のテーブルは、<table> の中に行(<tr>)を積み、その中に見出しセル(<th>)とデータセル(<td>)を並べて作ります。行数が増えたら <thead><tbody><tfoot> で構造を明示し、<caption> で表のタイトルを添えると、読み手にもプログラムにも分かりやすい表になります。セルをまとめたいときは横方向の colspan と縦方向の rowspan を使い、結合したぶんだけ後続のセルを減らすのがポイントです。見出しセルには scope="col" / scope="row" を付けると、見出しと値の対応がスクリーンリーダーに正しく伝わります。罫線や余白といった見た目は CSS の役割で、テーブル自体はレイアウト目的ではなく「表形式のデータ」を表すために使う——この基本を押さえれば、整理された読みやすい表を自信を持って作れるようになります。

参考ページ