テーブルの見出し行や左端列を position: sticky
で固定すると、ブラウザによっては罫線が消えたり、スクロール中に途切れて見えることがあります。主因は「border-collapse: collapse
と sticky の相性」「描画順序(z-index)」「背景色未指定による透過」の三つです。ここでは実務で安定する順に対策を提示します。
最優先の安定策:border-collapse をやめて separate+border-spacing:0 に切り替える
多くのブラウザで、collapse
と position: 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 を見直す
親要素に transform
や filter
が付与されていると新しいコンテキストが生成され、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: separate
と border-spacing: 0
に切り替えます。次に sticky セルへ背景色と z-index
を与えて重なり順を確定し、必要なら擬似要素で罫線を補強します。スクロールは外側ラッパーで処理し、親の transform
を避けると再描画の不具合を抑えられます。以上の順で対処すれば、主要ブラウザで安定した固定表示と罫線表示を両立できます。