scroll-padding-topがsafariでうまく効かない問題と現状のワークアラウンド

公開:2020/12/13
更新:2020/12/13
2 min読了の目安(約1800字TECH技術記事

Webサイトにおいてヘッダーを上部に固定したいというケースはよくあると思います。その際に問題になるのがページ内リンクが固定ヘッダーで隠れてしまうというものです。

Zennでは記事の表示ページでヘッダーを固定しており、なおかつページ内リンクの集合である目次を使っているため、この問題に対処しなければなりません。

scroll-padding-top

CSSには上記の問題を簡単に解決できるscroll-padding-topというプロパティがあります。これを使うとページ内リンクの表示位置を調整できます。

CSS
html {
  scroll-padding-top: 60px;
}

ヘッダーの高さをCSS変数で指定しておけばもっと楽ですね。

CSS
html {
  scroll-padding-top: var(--header-height);
}

ちょうど良さそうなCodePenのサンプルがあったのでそのまま貼らせていただきます。

ChromeやFireFoxをお使いの場合は、ページ上部に固定されたリンクをクリックすると、ヘッダーに隠れずに表示されることが分かると思います。

ただしscroll-padding-top2020年12月の時点ではSafari(モバイル・デスクトップの両方)でイメージ通りに動きません。リンク先に遷移したときに固定ヘッダーに隠れてしまいます。

詳しくはWebKit Bugzillaの投稿をチェックしてみてください。

scroll-margin-topというものもありますが、同様に上記の日付時点ではSafariでイメージ通りに動きません。

「固定ヘッダーに遷移先が隠れてしまう問題」にSafariでも対応するには

Safariを含めて対応するためにはCSSで泥臭い方法を用いる必要があります。dirty workaroundってやつです。

具体的には遷移先の要素(ヘッダーに隠れさせたくない要素)に対して、CSSで以下のように指定します。

.example:before {
	display: block;
	content: ' '; /* 完全に空だとなぜか効かないことがあったので半角スペースだけ入れる */
	margin-top: -60px; /* ヘッダーの高さ */
	height: 60px; /* ヘッダーの高さ */
	visibility: hidden;
	pointer-events: none;
}

何をやっているかというと、要素に対して疑似要素をくっつけて、その要素をヘッダーの高さぶんだけ上にずらして配置するようにします(margin-top: -60px;の部分)。実際の表示位置がずれることはないように、height: 60pxで帳尻合わせをしています。

2020年にこんな書き方をしないといけないだなんて………………

なお、疑似要素を使わずに直接要素に対してmargin-top: -60px; padding-top: 60px;のように指定してスクロール位置を調整することもできます。ただ、疑似要素で指定しておけば、Safariでscroll-padding-topが使えるようになったとき.example:before {}の部分をまるっと消せば済むため楽なのではないかと思っています。


上記の対処法だと要素自体にpaddingbackground-colorなどの装飾があるときに微調整が必要だったり、疑似要素が上部にある要素と重なってしまったりと色々大変だったりはします。

しかし、現状これ以外に方法はないような気がしています……(僕はかなり試行錯誤しましたし、ネットの奥の奥の奥まで探したりもしました)。早くこの記事自体が不要になることを願います。