長年の悩みがこれで解決! CSSのposition: stickyの仕様が変わり、上部固定と左端固定が同時に実装できるようなります

テーブルのヘッダを上部に固定し、さらに列の1つを左端に固定する、これを実装するのは非常に大変です。

一見、position: sticky;を使って、top: 0;left: 0;で実装できそうですが、実際にはどちらか一方しか固定されません。JavaScriptを使用してもかなりの量になります。

ここで朗報です、9年間続いていたCSS仕様の問題が解決されます!
position: sticky;がアップデートされ、軸ごとにもっとも近いスクロール位置に追従できるようになったため、このヘッダと列を上部と左端にそれぞれ固定するのが簡単に実装できるようになります。

サイトのキャプチャ
CSS position: sticky now sticks to the nearest scroller on a per axis basis!
by Bramus!

下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。

はじめに

テーブルを固定ヘッダと固定列にしようとしたことがある人であれば、その苦労がよく分かると思います。position: sticky;top: 0;left: 0;を設定するだけで実装できると思いきや、実際にはどちらか一方しか固定されません。

この問題は最近のCSSの変更により、解決されました!
position: sticky;は単軸スクロールバーとの互換性が向上し、異なる軸上の異なるスクロールコンテナに合わせて固定要素を移動させることが可能になりました。Chromeでは、4月にリリース予定の148からサポートされます。

現状のposition: sticky;

position: sticky;の変更の影響を理解するために、レスポンシブ対応のテーブルの標準的な実装を簡単に見てましょう。

まず、データで埋め尽くされた幅の広いHTML要素の<table>から始めます。この幅の広いテーブルが小さいスクリーンのスマホでもページレイアウトが崩れないようにするためには、通常はoverflow-x: auto;を設定したコンテナで囲みます。

ドキュメントを垂直方向にスクロールしても列ヘッダ(<thead>)を表示したままにするには、列ヘッダにposition: sticky; top: 0;を設定します。同時に、データを水平方向にスクロールしても最初の列を表示したままにするには、position: sticky; left: 0;を設定します。

しかし、これは期待通りに動作しません。最初の列は水平スクロール時にテーブルの左端に固定されますが、ヘッダは他の部分と一緒にスクロールアウトしてしまいます。

なぜこうなるかというと、.table-wrapperが両方の軸に対してスティッキーの参照となるためです。ラッパーは水平方向にしかスクロールしないため、垂直方向の固定は完全に無効になります。top: 0;に設定されたヘッダは、他の部分と一緒にスクリーン外にスクロールしてしまいます 😭

この問題を解決するには、スクロール位置を同期させるために大量のJavaScriptを記述するか、ヘッダと複製するしかありませんでした。

ヘッダを.table-wrapper内に固定するピュアCSSによる解決方法はありますが、ここで説明している問題とは異なります。つまり、ヘッダを同じスクロール内に固定するのではなく、ヘッダを別のスクロール領域に固定したいのです。具体的には、水平方向のい固定する要素については.table-wrapperに、垂直方向に固定する要素についてはドキュメントのスクロール領域に固定します。

最近のCSSによるposition: sticky;の変更点

最近のCSSの変更により、この問題は解決されました。
position: sticky;は各軸ごとにもっとも近いスクロール可能なコンテナに追従できるようになりました。

たとえば、幅の広いテーブルの場合、以下が可能になります。

  • 最初の列は、テーブルのラッパーに対して水平方向に固定できます。
  • ヘッダは、ドキュメント自体などまったく異なるスクロール要素に対して垂直方向に固定できます。

これでヘッダを重複させる必要も、スクロール同期用にJavaScriptを使用する必要もなくなります。期待通りの動作をシンプルなCSSだけで実装できます。

position: sticky;の新しい動作

position: sticky;の新しい動作は、デモページで確認できます。
※Chrome 148+でご覧ください。

See the Pen
CSSのposition: sticky:シングル軸のスクロールコンテナ
by coliss (@coliss)
on CodePen.

対応しているブラウザでデモページを表示すると、水平スクロール時には最初の列がテーブルラッパーの左端に固定され、垂直スクロール時には上部のヘッダがビューポートの上部に固定されます。

重要なポイント: オーバーフローに注意

デモページのCSSを見ると、.table-wrapperに見慣れないCSSがあることに気がつくかもしれません。

ラッパーを水平方向にスクロールさせるには、overflow-x: scroll;を使いたくなるかもしれません。しかし、それを設定してしまうと、垂直方向の固定が機能しなくなります!

なぜでしょう? その答えは、CSSではoverflow-xscrollまたはautoに設定すると、ブラウザは自動的にoverflow-yautoとして設定するからです(値がvisibleの場合)。これにより、ラッパーは垂直方向にもスクロール可能なコンテナとして機能し、ヘッダを再び囲みこんでヘッダのスティッキー参照点となってしまいます。

この問題を解決するには、ブラウザにブロック軸上にスクロールコンテナを作成しように明示的に指示する必要があります。これはclipキーワードを使用することで実現できます。

overflow-yclipを設定することで(overflowのショートハンド)、ラッパーは垂直軸上でスクロールポートにはなりません。そのため、ヘッダはビューポートに追従できるようになります。

ブラウザのサポート

2026年4月現在、ブラウザのサポートは下記の通りです。

  • Chromium (Blink)
    Chromium 148.0.7742.0から利用可能です。
  • Firefox (Gecko)
    サポートされていません。最新情報はBug #2023702をご覧ください。
  • Safari (WebKit)
    サポートされていません。

古いブラウザへの対応

古いブラウザでは、依然として両軸のスティッキー参照として内部コンテナが使用されているため、この新しい動作を機能検出してJavaScriptベースのフォールバックを提供したり、特定のスタイルを条件付きで読み込むといったことが推奨されます。

現時点では、CSSの@supportsクエリでこのレイアウト動作を検出することはできません(CSSWGのイシューには提出済み)が、JavaScriptを使用すれば機能検出は可能です。前述のデモページではまさにその機能を実現するスクリプトが含まれています。

そのスクリプトは、スクロール可能なラッパー内でスティッキー配置のオフセットをブラウザがどのように処理するかを評価し、検出をします。デモページのJSタブをクリックして、JavaScriptを入手してください。

sponsors

top of page

©2026 coliss