実はもう <td> や <th> に position: relative; は普通に使える

#はじめに

「table系要素に position: relative; は使えない」というような話を聞いたことがないだろうか。
実は、今のブラウザ（IE9以降やAndroidとiOS含む）では使えるのだ。

な、なんだってー！？

#百聞は一見にしかず

適当に書いてみます。

```html:HTML
<table class="sampleTable">
  <tbody>
    <tr>
      <td class="cell01"></td>
      <td class="cell02"></td>
    </tr>
    <tr>
      <td class="cell03"></td>
      <td class="cell04"></td>
    </tr>
  </tbody>
</table>
```

```css:CSS
.sampleTable {
  border: none;
  table-layout: fixed;
  width: 400px;
  height: 400px;
}
.sampleTable td {
  position: relative;
  border: 1px #666 solid;
}
.sampleTable td::before {
  display: block;
  position: absolute;
  width: 20px;
  height: 20px;
  background: #f00;
  content: "";
}
.cell01::before {
  bottom: 0;
  left: 0;
}
.cell02::before {
  top: 0;
  right: 0;
}
.cell03::before {
  top: 40px;
  right: 80px;
}
.cell04::before {
  bottom: 40px;
  left: 80px;
}
```

これをブラウザで見るとこのように表示されているはずです。

![キャプチャ.png](https://qiita-image-store.s3.amazonaws.com/0/169473/a84f4c44-eae1-47d6-c4dc-ed0176401258.png)

セルに `position: relative;` が効いてるからセル内で位置指定ができた！

#`position: relative;` が効かないのはCSS2.1時代の仕様だった

確かに、ちょっと前の記憶では `<th>` や `<td>` の `display: table-cell;` な要素に `position: relative;` を指定しても、子要素がその要素を基準とした `position` にならずに、一番近い `position: static;` 以外の要素（なければルート）を基準に取ってしまっていた。
何故なのか。

W3Cの [CSS2.1の仕様書](https://www.w3.org/TR/CSS21/visuren.html#propdef-position) を見るとこう書いてある。

> relative
The box's position is calculated according to the normal flow (this is called the position in normal flow). Then the box is offset relative to its normal position. When a box B is relatively positioned, the position of the following box is calculated as though B were not offset. The effect of 'position:relative' on table-row-group, table-header-group, table-footer-group, table-row, table-column-group, table-column, table-cell, and table-caption elements is undefined.

最後の文章（The effect of ～）を意訳すると、

> `position:relative` は `table-row-group`, `table-header-group`, `table-footer-group`, `table-row`, `table-column-group`, `table-column`, `table-cell` および `table-caption` の要素では未定義です。

と書いてあります。未定義だったのです。

`position: relative;` が効かないのが仕様的には正解で、効いたブラウザは要するにバグだったわけです。

#CSS3で仕様が変更されていた

W3Cの [CSS3のpositionの仕様](https://www.w3.org/TR/css-position-3/#valdef-position-relative) を見るとこう書いてある。

> ‘relative’
>
- table-row-group, table-header-group, table-footer-group and table-row offset relative to its normal position within the table. If table-cells span multiple rows, only the cells originating in the relative positioned row is offset.
- table-column-group, table-column do not offset the respective column and has no visual affect when position: relative is applied.
- table-caption and table-cell offset relative to its normal position within the table. If a table cell spans multiple columns or rows the full spanned cell is offset.

箇条書きの最後の文章（table-caption and ～）を意訳すると、

> `table-caption` と `table-cell` はテーブル内の通常の位置に対して相対的に移動でき、テーブルのセルが複数の列・行にまたがっている場合はそれらも移動します。

という感じでしょうか……

そうです。CSS3では `table-cell` な要素は `position: relative;` で位置を動かせるのです。
ということは、`table-cell` な要素を基準として子要素の `position` を指定できるようになったのです。

CSS3に対応したブラウザならば仕様の通りになるはずです。
しかし、`table-row-group` `<tbody>` や `table-row` `<tr>` などにも有効と書いてありますが、Firefox 57 (Quantum) のみの対応でした。
現状は `table-cell` だけに使ったほうが良さそうです。