【解決法】tableをstickyで固定すると罫線が消える問題を直す方法

【解決法】tableをstickyで固定すると罫線が消える問題を直す方法 HTML/CSS

テーブルの見出し行や左端列を position: sticky で固定すると、ブラウザによっては罫線が消えたり、スクロール中に途切れて見えることがあります。主因は「border-collapse: collapse と sticky の相性」「描画順序(z-index)」「背景色未指定による透過」の三つです。ここでは実務で安定する順に対策を提示します。

最優先の安定策:border-collapse をやめて separate+border-spacing:0 に切り替える

多くのブラウザで、collapseposition: sticky の組み合わせが再描画の不具合を誘発します。separate に切り替え、余白はゼロにすれば見た目はほぼ同じで、罫線の欠落を避けられます。

table.stickyfix {
  border-collapse: separate;   /* ← collapse をやめる */
  border-spacing: 0;           /* 見た目を維持 */
  width: 100%;
}

.stickyfix th,
.stickyfix td {
  border: 1px solid #d0d7de;
  padding: .5rem .75rem;
}

/* ヘッダー固定(横スクロール対応) */
.stickyfix thead th {
  position: sticky;
  top: 0;
  z-index: 2;                  /* セルの上に重ねる */
  background: #fff;            /* 透け防止。ダークなら適宜変更 */
}

/* 左列固定がある場合の例 */
.stickyfix td:first-child,
.stickyfix th:first-child {
  position: sticky;
  left: 0;
  z-index: 1;                  /* ヘッダーよりは低く、通常セルより高く */
  background: #fff;
}

z-index は必ず指定します。ヘッダーと左列を両方固定する場合は、ヘッダー左セルにだけより高い z-index を与えると角の重なりが綺麗に揃います。

/* 交差セル(左上)を最前面に */
.stickyfix thead th:first-child {
  z-index: 3;
}

collapse を維持したいときの回避策:擬似要素で罫線を描く

どうしても border-collapse: collapse を外せない事情がある場合、sticky セルの罫線だけ擬似要素で別レイヤーとして描く方法が有効です。実体の border が消えても、擬似要素は残ります。

table.collapsefix {
  border-collapse: collapse;
  width: 100%;
}

.collapsefix th,
.collapsefix td {
  border: 1px solid #d0d7de;
  padding: .5rem .75rem;
}

/* sticky 化 */
.collapsefix thead th {
  position: sticky;
  top: 0;
  background: #fff;
  z-index: 2;
}

/* 下罫線を擬似要素で補強(スクロール中の欠落対策) */
.collapsefix thead th::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;               /* 実線と重ねる */
  height: 1px;
  background: #d0d7de;
  pointer-events: none;
}

左列を固定する場合も同様に、右罫線を ::after で描けば途切れを最小化できます。背景色は sticky セルに明示して透過を避けます。

背景透過と描画順序が原因のケース:背景と z-index の明示

罫線が「消えている」のではなく、下のセルに飲み込まれて見えなくなっている場合があります。sticky セルに背景色、z-index を必ず与えて重なり順を制御してください。

thead th[style*="position: sticky"],
thead th.sticky {
  background: #fff;  /* 透け止め */
  z-index: 2;        /* 前面へ */
}

スクロールコンテナ由来の不具合:親要素の transform と overflow を見直す

親要素に transformfilter が付与されていると新しいコンテキストが生成され、sticky の描画が不安定になることがあります。必要がなければ外し、横スクロール用のラッパーは overflow をテーブルではなく外側の div に与えます。

<div class="table-scroller">
  <table class="stickyfix">…</table>
</div>
.table-scroller {
  overflow: auto;     /* 横スクロールは外側で処理 */
  -webkit-overflow-scrolling: touch;
}

実装テンプレート:横スクロール+ヘッダー固定+左列固定

もっともトラブルが少ない構成の最小一式です。まずはこれをベースに、配色や余白だけ調整すると素早く安定します。

<div class="table-scroller">
  <table class="stickyfix">
    <thead>
      <tr>
        <th>項目</th>
        <th>Jan</th>
        <th>Feb</th>
        <th>Mar</th>
      </tr>
    </thead>
    <tbody>
      <tr><th>Product A</th><td>10</td><td>20</td><td>30</td></tr>
      <tr><th>Product B</th><td>15</td><td>25</td><td>35</td></tr>
    </tbody>
  </table>
</div>
.table-scroller { overflow: auto; }

table.stickyfix {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  font-size: 14px;
}

.stickyfix th,
.stickyfix td {
  border: 1px solid #d0d7de;
  padding: .5rem .75rem;
  white-space: nowrap;
}

/* ヘッダー固定 */
.stickyfix thead th {
  position: sticky;
  top: 0;
  background: #fff;
  z-index: 2;
}

/* 左列固定(行見出し) */
.stickyfix tbody th {
  position: sticky;
  left: 0;
  background: #fff;
  z-index: 1;
}

/* 交差セル(左上)を最前面に */
.stickyfix thead th:first-child {
  left: 0;
  z-index: 3;
}

最後の手段:border の代わりに box-shadow や outline を使う

特定の環境でどうしても border が欠落する場合は、視覚的な罫線を影やアウトラインで置き換えると安定します。outline はレイアウトに影響せず、box-shadow は擬似罫線として描けます。

/* 下罫線を影で表現(ヘッダー用) */
.stickyfix thead th {
  box-shadow: inset 0 -1px 0 #d0d7de;
}

/* 左罫線をアウトラインで補強(左列用) */
.stickyfix tbody th {
  outline: 1px solid #d0d7de;
  outline-offset: -1px;
}

まとめ

罫線の欠落は collapse+sticky の組み合わせが引き金になることが多いため、まずは border-collapse: separateborder-spacing: 0 に切り替えます。次に sticky セルへ背景色と z-index を与えて重なり順を確定し、必要なら擬似要素で罫線を補強します。スクロールは外側ラッパーで処理し、親の transform を避けると再描画の不具合を抑えられます。以上の順で対処すれば、主要ブラウザで安定した固定表示と罫線表示を両立できます。