HTML
CSS

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

はじめに

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

な、なんだってー!?

百聞は一見にしかず

適当に書いてみます。

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
.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

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

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

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

W3Cの CSS2.1の仕様書 を見るとこう書いてある。

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:relativetable-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の仕様 を見るとこう書いてある。

‘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-captiontable-cell はテーブル内の通常の位置に対して相対的に移動でき、テーブルのセルが複数の列・行にまたがっている場合はそれらも移動します。

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

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

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