ページの途中から固定ナビゲーションへ切り替えた時にページ内リンクがずれる問題を解決した話

固定される前の状態からだと途中で固定ナビゲーションが出現してしまいアンカーリンクはズレる Web

レスポンシブウェブデザインでのサイト作成中に、今回僕がハマったことの備忘録です。

position:fixedでアンカーリンクがずれる」といった似たような問題と解決策の記事はたくさんあったのですが、僕のケースではそれだけでは解決しなかったので、同じような問題でハマって困ってる方の参考になれればいいなと思います。

▼とっととデモ見せやがれっていう方はこちら

ページの途中から固定ナビゲーションへ切り替えた時にページ内リンクがずれる問題を解決したデモ

 

やりたかったこと

  • 1ページ完結のサイト構成
  • PC、タブレット、スマホでヘッダー(ロゴ)の高さが変わる
  • 指定した距離をスクロールすると、上部に固定するナビゲーションを表示(ロゴは消える)
  • ナビゲーションをクリック(タップ)すると、同じページ内の指定した場所へアンカーリンク

ぶつかった問題点

スクロールする前(サイトが表示されたばかりの状態)でのアンカーリンクと、一定のスクロール後、ヘッダー(ロゴ)が消えてナビゲーションだけが固定された状態でのアンカーリンクとでは、同じアンカーリンクでも表示場所にズレが生じる。

うーん。日本語は難しい・・・。

つまり!

最初はヘッダーを固定していない状態でアンカーリンクを押すと、途中で固定ナビゲーションが表示されるので、その分の高さだけずれるという問題です。しかもレスポンシブデザインなので高さが可変でガチ指定できないというところがポイントです。

まず、固定ヘッダーを実現する為に、「220ピクセルスクロールしたら、ヘッダーの中のナビゲーションに fixed-header という固定する為のcssを付与」されるスクリプトを書きました。

/*****************************************
    ナビゲーション固定
*****************************************/
    $(window).on('scroll', function() {
        if ($(this).scrollTop() > 220) {//固定する距離進んだら
            $('.nav').addClass('fixed-header');//ナビに固定を指示したクラスが付与
        } else {//220px以内の場合
            $('.nav').removeClass('fixed-header');//固定クラスを外す
        }
    });

 

次に、最初からずっと同じ高さで固定されているヘッダーの場合は、以下のようなスクリプトとCSSで回避できますので書いておきます。HTMLは省略

[script]

/*****************************************
    固定ヘッダーでアンカーリンクがずれる対策
*****************************************/    
    $('a[href^=#]').click(function() {
        var headerHight = 100; //固定ヘッダーの高さ
        var speed = 800; // スクロールの速度ミリ秒
        var href= $(this).attr("href");// アンカーの値取得
        var target = $(href == "#" || href == "" ? 'html' : href);// 移動先を取得
        var position = target.offset().top-headerHight;// 移動先を数値で取得してヘッダーの高さ分ずらす
        $('body,html').animate({scrollTop:position}, speed, 'easeOutExpo');
        return false;
    });

[css]

#header {
  width: 100%;
  min-width: 960px;
  height: 100px;
  position: fixed;
  left:0;
  top:0;
  z-index: 10;
}
#content{
  padding-top: 100px;
}
#link01 {
  margin-top:-100px;
  padding-top:100px;
}

 

しかし今回のように途中から固定ヘッダーに切り替わる場合はこれだけでは直りません。

何度も言いますが、直らない理由は、固定ナビゲーションが、最初から固定されているわけではなく、途中から固定されるからです。

言葉で説明するのは難しいし、伝わりづらいので、こちらのキャプチャをご覧ください。

固定されてからのアンカーリンクはズレない

固定される前の状態からだと途中で固定ナビゲーションが出現してしまいアンカーリンクはズレる

 

解決策

固定される前の状態からアンカーリンクを押すと、スルスルっと遷移している途中で固定ナビゲーションが出現してしまい、アンカーリンクがずれたように見えるので、先ほどのスクリプトに以下の条件分岐を追記してスクロール位置をずらします。

[追加]

if ( !$(".fixed-header").is(":visible") ) {// 固定するクラスが見つからない(固定されていない場合は)
    headerHight = $(".nav").height();// スクロール後に固定されるナビの高さをヘッダーの高さにする
}

[スクリプト完成形]

/*****************************************
    固定ヘッダーでアンカーリンクがずれる対策
*****************************************/
$('a[href^=#]').click(function() {
    var headerHight = 0; //ヘッダーの高さ
    if ( !$(".fixed-header").is(":visible") ) {// 固定するクラスが見つからない(固定されていない場合は)
        headerHight = $(".nav").height();// スクロール後に固定されるナビの高さをヘッダーの高さにする
    }
    var speed = 800; // スクロールの速度ミリ秒
    var href= $(this).attr("href");// アンカーの値取得
    var target = $(href == "#" || href == "" ? 'html' : href);// 移動先を取得
    var position = target.offset().top-headerHight;// 移動先を数値で取得してヘッダーの高さ分ずらす
    $('body,html').animate({scrollTop:position}, speed, 'easeOutExpo');
    return false;
});

このスクリプトに修正します。

スクロール中に出現する可変ナビゲーションの高さを取得して、その高さ分ずらす

できた!(*゚∀゚)

これで意図した通りの動きが実現できました。

伝わりましたかね??

(・ω・。)キョロキョロ(。・ω・)

ま、いっか。

固定ヘッダーや固定ナビゲーションなどでサイトを制作する場合は、ページ内アンカーリンクのずれにご注意ください。

ということで、めでたしめでたし

ページの途中から固定ナビゲーションへ切り替えた時にページ内リンクがずれる問題を解決したデモはこちら

JavaScript本格入門 [ 山田祥寛 ]

JavaScript本格入門 [ 山田祥寛 ]
価格:3,218円(税込、送料込)

コメント

  1. 後藤 より:

    まさにこの件でずっと悩んでいたので、とても参考になりました!
    ありがとうございます。

    • ぴーくん より:

      コメントありがとうございます(^^)
      お役に立てたようで何よりです♪
      わざわざありがとうございましたm(_ _)m

  2. うえ より:

    私もこの件で悩んでおり、こちらのスクリプトを試したところ解消しました。
    ありがとうございます。
    ただ、私の場合階層のある開閉式のメニューを採用しており、aタグがhref=”#”になっていると、メニューを閉じる度にトップにスクロールで戻ってしまったり、2階層目のボタンが開閉しなくなったりしてしまうのですが、こういった場合の解決方法はあるのでしょうか?
    var target = $(href == “#” || href == “” ? ‘html’ : href);
    あたりを変更すれば良いのではと思い、いじってはみているのですが・・・。

    • うえ より:

      aタグがhref=”#”になっていると、開閉式で不具合が出る件について、
      $(‘a[href^=#]’ ).click(function() {

      $(‘a[href^=”#”]’ + ‘a:not(.xxx)’).click(function() {
      と不具合が出る箇所を除外することで解決しました。
      お騒がせして申し訳ございません。
      改めて本件について、本当に参考になりました。
      ありがとうございました。

      • ぴーくん より:

        うえさん、コメントありがとうございます!
        そして気付くの遅くてスミマセン(;^_^A
        解決できたようで何よりです!

タイトルとURLをコピーしました