こんにちは、さち です。
サイトを作る時に「表 <table>」を使うことがあるんですが、行数が多いときはスクロールをしても見やすくするために「ヘッダー(項目名) <th>」を常に表示しておきたいことがあります。
そんな時に役立つのが、CSS の position: sticky; です。
ただ、ちゃんと実装しようとすると、意外と面倒な仕様が多かったので、備忘録も兼ねて position: sticky; の使い方を書いていきます。
表の項目名を固定する
サンプル
サンプルとして作った表がこちら。表をスクロールしても、ヘッダー(項目名)の「名前」「身長」が追従して常に表示されていますね。
| 名前 | 身長[cm] |
|---|---|
| 朝香 果林 | 167 |
| エマ・ヴェルデ | 166 |
| 鐘 嵐珠 | 165 |
| 宮下 愛 | 163 |
| 三船 栞子 | 160 |
| 上原 歩夢 | 159 |
| 近江 彼方 | 158 |
| 桜坂 しずく | 157 |
| 高咲 侑 | 156 |
| ミア・テイラー | 156 |
| 中須 かすみ | 155 |
| 優木 せつ菜 | 154 |
| 天王寺 璃奈 | 149 |
HTML
<div class="scroll">
<table>
<tr class="sticky"><th>名前</th><th>身長[cm]</th></tr>
<tr><td>朝香 果林</td><td>167</td></tr>
<tr><td>エマ・ヴェルデ</td><td>166</td></tr>
<tr><td>鐘 嵐珠</td><td>165</td></tr>
<tr><td>宮下 愛</td><td>163</td></tr>
<tr><td>三船 栞子</td><td>160</td></tr>
<tr><td>上原 歩夢</td><td>159</td></tr>
<tr><td>近江 彼方</td><td>158</td></tr>
<tr><td>桜坂 しずく</td><td>157</td></tr>
<tr><td>高咲 侑</td><td>156</td></tr>
<tr><td>ミア・テイラー</td><td>156</td></tr>
<tr><td>中須 かすみ</td><td>155</td></tr>
<tr><td>優木 せつ菜</td><td>154</td></tr>
<tr><td>天王寺 璃奈</td><td>149</td></tr>
</table>
</div>
<table> を <div> で囲んでスクロールさせています。
スクロール時に追従させたいヘッダーの <tr> に class="sticky" を追加してあります。
CSS
.scroll {
height: 250px;
overflow-y: scroll;
}
.sticky {
position: sticky;
top: 0;
z-index: 1;
}
ヘッダーを追従させるために、クラス sticky に position: sticky; を記述。
また、top: 0; によって追従時に固定する位置を指定しています。今回の場合は、スクロール時にトップ(上端)で固定されます。(もちろん、bottom left right などでもOK)
さらに、z-index: 1; でヘッダーが他の要素よりも上に重なるように調整しています。(値は状況に合わせて変更して下さい)
ちゃんと実装するためのコツ
position: sticky; を付けるだけでは、ちゃんと動かないことがありました。気をつけないといけないポイントを書いていきます。
【注意1】 「border-collapse」の値
表のセルを線(罫線)で区切る場合は、CSS で border-collapse: collapse; を設定していると、position: sticky; が付いている要素の罫線が消えてしまいます。
この問題の対処法は、次の2つのどちらかです。
- 罫線で区切るデザインをやめる
border-collapseの値をseparateに変える
ちなみに、border-collapse: separate; にすると、この設定の性質上、セルを区切る罫線のデザインが変わってしまいます。
この状態で 1px の罫線でセルを区切るには、各セルに対して「上・下」「左・右」ぞれぞれどちらか一方にだけ border を設定するようにします。
【注意2】 「overflow」の値
今回の例のように、小さい要素の高さでスクロールさせる場合は問題ありません。
しかし、大きな表でブラウザー自体のページスクロールに追従させたい場合は、親要素(祖先要素)に設定する overflow の値を visible にしないと上手くいきません。
ちなみに、overflow の初期値は visible なので自分で変えていない限り大丈夫ですが、問題の原因になる設定だと気付きにくいのが落とし穴です。
【おまけ】 比較対象を常に表示する
サンプル
position: sticky; を使って、特定の「行」のデータを常に表示させています。
| 名前 | 身長[cm] |
|---|---|
| 朝香 果林 | 167 |
| エマ・ヴェルデ | 166 |
| 鐘 嵐珠 | 165 |
| 宮下 愛 | 163 |
| 三船 栞子 | 160 |
| 上原 歩夢 | 159 |
| 近江 彼方 | 158 |
| 桜坂 しずく | 157 |
| 高咲 侑 | 156 |
| ミア・テイラー | 156 |
| 中須 かすみ | 155 |
| 優木 せつ菜 | 154 |
| 天王寺 璃奈 | 149 |
HTML
<div class="scroll">
<table>
<tr class="sticky"><th>名前</th><th>身長[cm]</th></tr>
<tr><td>朝香 果林</td><td>167</td></tr>
<tr><td>エマ・ヴェルデ</td><td>166</td></tr>
<tr><td>鐘 嵐珠</td><td>165</td></tr>
<tr><td>宮下 愛</td><td>163</td></tr>
<tr><td>三船 栞子</td><td>160</td></tr>
<tr><td>上原 歩夢</td><td>159</td></tr>
<tr class="sticky-row"><td>近江 彼方</td><td>158</td></tr>
<tr><td>桜坂 しずく</td><td>157</td></tr>
<tr><td>高咲 侑</td><td>156</td></tr>
<tr><td>ミア・テイラー</td><td>156</td></tr>
<tr><td>中須 かすみ</td><td>155</td></tr>
<tr><td>優木 せつ菜</td><td>154</td></tr>
<tr><td>天王寺 璃奈</td><td>149</td></tr>
</table>
</div>
ヘッダーに以外に、データの <tr> には class="sticky-row" を追加してあります。
CSS
.scroll {
height: 250px;
overflow-y: scroll;
}
.sticky {
position: sticky;
top: 0;
z-index: 1;
}
.sticky-row {
position: sticky;
top: 44px;
bottom: 0;
z-index: 1;
}
クラス sticky-row に position: sticky; を記述して追従させます。
top: 44px; によって上端から 44px の位置で固定されますが、bottom: 0; によって下端の位置でも固定されます。
さらに、z-index: 1; で他の要素よりも上に重なるように調整しています。(値は状況に合わせて変更して下さい)


コメント