position: fixed;でページ内リンクの頭出しがずれる件の解決策を考えてみる

最近の流行りかは分かりませんが、ヘッダー、もしくはナビゲーションだけが スクロールの途中から固定するサイトをつくる機会が増えてきました。

そのデザインを見た時の毎回の悩みは、「ページ内リンクの頭出しがずれるのをどうしよう...」ということでした。

今日もまた同じことで悩んだので少し調べつつ、解決策を考えてみました。

この状況が発生するシチュエーション

  • コンテンツより前に存在する要素(ヘッダー・ナビなど)をposition: fixed;で固定している

ネットに載っていた解決策

CSSで解決する方法

頭出しの対象となる要素(見出しなど)に以下のCSSを指定する

padding-top: 100px; /* 固定するもののheightと同じpx値 */
margin-top: -100px; /* 固定するもののheightと同じpx値 */

JavaScriptで解決する方法

  • ページ表示時にズレた分のscrollTopを調整する
  • smoothScrollなどページ内リンクを制御するjsのスクロール位置を調整する

コーディングを変えたくなかったため、Javascriptが有力とは思ったのですが パソコンだけでなく様々な環境で閲覧されることを想定するとscrollTopをJSで 調整するのはいささか怖い...と思い見送りました。

そこで対処方法はCSSでの対策一本に絞りました。

margin / paddingを使用した解決方法の問題点

結論から言いますと上記の方法で治りました。

ただ、margin / paddingは普通であればスタイリングにすでに 使用していることが多いと思います。

今回の案件でもかなりコーディングが進んでいたので影響が広範囲に及びました。
(padding-topのせいで背景がズレる、border-leftの長さがpadding分伸びる、marginの相殺が起きる...などなど)

そこで思い出したのがアンカータグ(aタグ)です。
昔、aタグはリンクURLを指定するだけの用途ではなく、飛び先を指定することにも 使用されていました。

<a name="xxx" id="xxx" />

margin / paddingのスタイルをこの対策のために変更しても影響範囲を狭くしたい、と思い 以下のようなコーディングに変更を行ってみました。

変更前

<h5 id="xxx">aaa</h5>

変更後(HTML)

<h5 class="m-txt-ttl5"><a id="xxx" />aaa</h5>

変更後(CSS/差分のみ)

.m-txt-ttl5 > a {
    display: block; padding-top: 100px; margin-top: -100px;
}

問題は解決し、CSSはクリーンになりましたがHTMLが...ということで 今ひとつモヤモヤが残っています。

これまでに上げた理由からこのようなコーディングで一旦は凌ぎつつ、 様々なサイトの実装例を見て勉強してみようと思います。

JavaScriptを使用せずにCSSの範囲だけでこの問題を解決する方法を ご存知の方がいらっしゃいましたら、アドバイスいただけると幸いです。