tr 要素は「表の“1行分”をまとめるための行コンテナ」
<tr> は
「table の中で、横一列のセルをひとかたまりにする“行の箱”」
です。
table が「表全体の箱」だとしたら、tr は「その中の 1 行分の枠」、
さらにその中に th や td(セル)が並ぶ、という三層構造になります。
- table … 表全体
- tr … 行(row)
- th / td … 各セル
この「入れ子構造」をイメージできると、一気に理解が進みます。
tr の基本構造と役割をイメージでつかむ
「1 行の中にセルが横に並ぶ」ための枠
シンプルな表を例にします。
<table>
<tr>
<th>プラン名</th>
<th>月額料金</th>
<th>ユーザー数</th>
</tr>
<tr>
<th>ベーシック</th>
<td>1,000円</td>
<td>1人</td>
</tr>
<tr>
<th>スタンダード</th>
<td>2,000円</td>
<td>5人</td>
</tr>
</table>
ここでの tr の役割はこうです。
1 行目の tr
「ヘッダー行(列の見出し)が横に並ぶ枠」
2 行目の tr
「ベーシックプランの情報が横に並ぶ枠」
3 行目の tr
「スタンダードプランの情報が横に並ぶ枠」
tr は「この横一列はセットですよ」と示すための箱
と捉えると分かりやすいです。
th / td と tr の関係をもう少し深掘りする
tr は「行」、th / td は「その行の中のセル」
さっきの例を、構造だけで見るとこうなります。
- table
- tr(1 行目)
- th(列見出し)
- th(列見出し)
- th(列見出し)
- tr(2 行目)
- th(行見出し)
- td(データ)
- td(データ)
- tr(3 行目)
- th(行見出し)
- td(データ)
- td(データ)
- tr(1 行目)
tr は「横方向のまとまり」
th / td は「その中の 1 マス 1 マス」
という役割分担です。
ここで大事なのは、
tr の中には必ずセル(th / td)が並ぶ
ということ。
tr 自体にテキストを書き込むのではなく、
必ずセル要素を子として置きます。
行ごとに意味を持たせる:ヘッダー行とデータ行
1 行目を「ヘッダー行」として扱う
多くの表では、
1 行目が「列の見出し」になります。
<tr>
<th>プラン名</th>
<th>月額料金</th>
<th>ユーザー数</th>
</tr>
この tr は、
「この表の列が何を意味するか」をまとめている行です。
CSS でこの行だけスタイルを変えると、
視覚的にも“ヘッダー行”として分かりやすくなります。
table tr:first-child {
background-color: #f5f5f5;
font-weight: bold;
}
2 行目以降は「データ行」
<tr>
<th>ベーシック</th>
<td>1,000円</td>
<td>1人</td>
</tr>
この tr は、
「ベーシックプランの情報一式」を表しています。
1 行が 1 レコード(1 件のデータ)
1 列が 1 項目(プラン名・料金・ユーザー数)
という関係になっているわけです。
tr は「1 レコード分の情報を横一列にまとめる箱」
と考えると、データベースや配列との対応も見えてきます。
CSS と tr:行単位でスタイルを変える
偶数行・奇数行で背景色を変える(ストライプ)
表を見やすくする定番テクニックが、
「行ごとに背景色を交互に変える」ストライプ表示です。
table tr:nth-child(even) {
background-color: #fafafa;
}
これで、2 行目・4 行目・6 行目…の tr にだけ
薄い背景色が付きます。
行単位でホバーさせることもできます。
table tr:hover {
background-color: #e3f2fd;
}
ユーザーがマウスを乗せた行全体がハイライトされるので、
「今どの行を見ているか」が分かりやすくなります。
ここでも、
「行」という単位を tr が持っているからこそ、
行ごとのスタイル変更が簡単にできる
というのがポイントです。
JavaScript と tr:配列の「1 要素 → 1 行」という対応
配列データから tr を量産する
JavaScript で表を作るとき、
よくあるのが「配列の 1 要素を 1 行(tr)にする」パターンです。
データのイメージ:
const plans = [
{ name: "ベーシック", price: "1,000円", users: "1人" },
{ name: "スタンダード", price: "2,000円", users: "5人" },
{ name: "プレミアム", price: "5,000円", users: "無制限" },
];
JavaScriptこれを table に描画するイメージ:
const table = document.querySelector("#planTable");
plans.forEach((plan) => {
const tr = document.createElement("tr");
const nameCell = document.createElement("th");
nameCell.textContent = plan.name;
const priceCell = document.createElement("td");
priceCell.textContent = plan.price;
const usersCell = document.createElement("td");
usersCell.textContent = plan.users;
tr.appendChild(nameCell);
tr.appendChild(priceCell);
tr.appendChild(usersCell);
table.appendChild(tr);
});
JavaScriptHTML 側:
<table id="planTable">
<tr>
<th>プラン名</th>
<th>月額料金</th>
<th>ユーザー数</th>
</tr>
</table>
ここでの対応関係は、
- 配列の 1 要素(1 プラン) → 1 行(tr)
- オブジェクトの各プロパティ → その行のセル(th / td)
という形になっています。
「1 データ → 1 行(tr)」というマッピングを意識できると、
JS で表を扱うのが一気に楽になります。
tr を使うか迷ったときの判断基準
「これは“表の 1 行分”として意味があるか?」
自分にこう聞いてみてください。
「このまとまりは、表の中で“横一列の 1 行”として扱えるか?」
「この行だけを抜き出しても、1 件のデータとして意味が通るか?」
YES なら tr。
NO なら、そもそも table ではなく別の構造(ul / dl / div など)を検討する。
時間割の 1 行
料金表の 1 行
成績表の 1 行
こういった「1 行 = 1 件の情報」という構造になっているなら、
tr が自然にハマります。
初心者として「tr タグ」で絶対に掴んでほしいこと
<tr> は、
「table の中で、“1 行分のセルをまとめる箱”」 です。
table … 表全体
tr … 行
th / td … セル
1 行目はヘッダー行として th を並べることが多い
2 行目以降は「1 レコード分のデータ」を tr にまとめる
CSS では tr 単位でストライプやホバーなどの行スタイルを付けられる
JavaScript では「配列の 1 要素 → 1 tr」という対応で表を生成する
あなたが tr を書くときに、
「この tr は“1 件分の情報を横一列にまとめたもの”と言えるか?」
と一度自問できるようになったら、
もう tr を“なんとなく table の中に書くタグ”ではなく、
“データの 1 行を表すための、意味のあるコンテナ”として扱えている状態です。
