admin管理员组

文章数量:1406926

I try to add the following functionality : when I type a URL with an anchor, I would like to be directly on the anchor. My problem is that I have a fixed header and my current JQuery code is not taking account of the offset that I have put (55, i.e the height of header).

Here's the code snippet :

 if ($(location.href.split("#")[1])) {
    var target = $('#'+location.href.split("#")[1]);
    if (target.length) {
       var hash = this.hash; 
       $('html,body').animate({ scrollTop: target.offset().top - 55 }, 300, function() {
       location.hash = hash;
       });
    }
  } 

This code snippet is located into [anchor.js][1] script.

I am well redirected to the anchor but, whatever offset value I take, this is not taken into account for the final result and so the anchor name is hidden by the fixed header after loading page.

If someone could help me to fix this issue,

Thanks in advance.

ps: I only want to make it work on Firefox and Chrome.

UPDATE

It seems that the solution could e from this link.

For this, I have to insert before the <a name="..."></a> tags a <span> tag with class='direct_anchor' (with .before Jquery function), so I include into my CSS the following rule :

.direct_anchor {
display: block;
height: 55px; // Height of fixed header
margin-top: -55px; 
visibility: hidden;
}

Finally, here's the code snippet for the case where I type directly into address bar a URL with hash extension :

var target = $('[name="'+location.href.split("#")[1]+'"]');
  var hash = location.href.split("#")[1];
  if (target.length) {
    location.hash = hash;
    $('html,body').animate({ scrollTop: target.offset().top - 55 }, 300);
    target.before( "<span class='direct_anchor'></span>" );
  }

Unfortunately, I can't get to make it work, class='direct_anchor' CSS rule doesn't seem to be applied on the span tag.

I am not an expert with Jquery, anyone could see what's wrong ?

Thanks for your help.

I try to add the following functionality : when I type a URL with an anchor, I would like to be directly on the anchor. My problem is that I have a fixed header and my current JQuery code is not taking account of the offset that I have put (55, i.e the height of header).

Here's the code snippet :

 if ($(location.href.split("#")[1])) {
    var target = $('#'+location.href.split("#")[1]);
    if (target.length) {
       var hash = this.hash; 
       $('html,body').animate({ scrollTop: target.offset().top - 55 }, 300, function() {
       location.hash = hash;
       });
    }
  } 

This code snippet is located into [anchor.js][1] script.

I am well redirected to the anchor but, whatever offset value I take, this is not taken into account for the final result and so the anchor name is hidden by the fixed header after loading page.

If someone could help me to fix this issue,

Thanks in advance.

ps: I only want to make it work on Firefox and Chrome.

UPDATE

It seems that the solution could e from this link.

For this, I have to insert before the <a name="..."></a> tags a <span> tag with class='direct_anchor' (with .before Jquery function), so I include into my CSS the following rule :

.direct_anchor {
display: block;
height: 55px; // Height of fixed header
margin-top: -55px; 
visibility: hidden;
}

Finally, here's the code snippet for the case where I type directly into address bar a URL with hash extension :

var target = $('[name="'+location.href.split("#")[1]+'"]');
  var hash = location.href.split("#")[1];
  if (target.length) {
    location.hash = hash;
    $('html,body').animate({ scrollTop: target.offset().top - 55 }, 300);
    target.before( "<span class='direct_anchor'></span>" );
  }

Unfortunately, I can't get to make it work, class='direct_anchor' CSS rule doesn't seem to be applied on the span tag.

I am not an expert with Jquery, anyone could see what's wrong ?

Thanks for your help.

Share Improve this question edited May 26, 2016 at 14:07 asked Apr 4, 2016 at 3:58 user1773603user1773603 6
  • What is this line if ($(location.href.split("#")[1])) supposed to achieve? – AKS Commented Apr 4, 2016 at 5:10
  • this is the case where I e from an external URL (not from my website) and I try to go directly to the anchor by typing in browser the URL "mywebsite./test.html#anchor" – user1773603 Commented Apr 4, 2016 at 5:30
  • But what will be the value of $(location.href.split("#")[1])? I mean what do you want to check here. – AKS Commented Apr 4, 2016 at 5:33
  • I check if there's a string after # symbol, i.e check if there's an anchor into the URL – user1773603 Commented Apr 4, 2016 at 5:53
  • What I am trying to say here is that you don't really need to use jquery $ for that. You can directly check the length of location.hash. – AKS Commented Apr 4, 2016 at 6:00
 |  Show 1 more ment

5 Answers 5

Reset to default 3 +50

I debugged and got that the script doesn't get executed inside the if statement while re-loading.

$(window).bind("load", function () {

      $('a[href*="#"]:not([href="#SECTION"]):not([href*="wikipedia"]):not([href*="mjx-eqn"])').click(function(event) {
        event.preventDefault();
        if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
        var target = $(this.hash);
      target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
      if (target.length) {
        var hash = this.hash; 
        $('html,body').animate({ scrollTop: target.offset().top - 55 }, 300, function() {
          href = window.location.href;
          history.pushState({page:href}, null, href.split('#')[0]+hash);
        });
        return false;
      }
      }
      });

      $(window).bind('popstate', function(event) {
        var state = event.originalEvent.state;
        var target = window.location.href.split('#');
        var href = target[0];
        if (state) {
          $('html,body').animate({ scrollTop: 0 }, 300, function() {
            history.replaceState({}, null, href);
          });
        }
      });

      // code changed here 
      var target = $("[name='"+location.href.split("#")[1]+"']");
      if (target.length) {
        $('html,body').animate({ scrollTop: target.offset().top-55},300);
      }
    });

Please see that you can fetch element using name not id as selector. This was creating issue which is solved now. I have checked by debugging so can't be sure of it but it worked fine in chrome. I couldn't check in firefox as I don't know how to edit script using debugger.

Try changing the location hash before the animation

location.hash = this.hash;
$('html, body').animate({scrollTop: target.offset().top -55 }, 300);

changing it after the animation causes the page to jump back to the target without the offset.

Funny enough I had the exact same issue a few days ago on my blog. The problem is not the code, but the browser implementation which waits a bit and/or tries multiple times to match the hash to an id on the page. In my case, the ids were generated in Javascript and still the browser would go to them. Your code may get executed and then the browser goes to that point anyway.

My solution involved inserting an invisible element that actually carried the id in the hash and making it position relative and top -50px. As a generic solution I think your only (ugly) option is to check the offset of the element with the id same as the hash and only scroll the container after you detect the browser moved it or after a timeout.

Here is a demo of the solution (wouldn't work in a jsfiddle). Note that here I execute the script immediately, so if the page takes longer to load, you might want to increase the timeout. Another solution is to run it at DOMready, but I think that will give you an awkward delay.

<html>
<script src='https://ajax.googleapis./ajax/libs/jquery/1.11.1/jquery.min.js'></script>
<style>
header {
  height:50px;
  width:100%;
  background:wheat;
  position:fixed;
  top:0;
}
#target {
    color:red;
}
#topHalf, #bottomHalf {
    margin-left:20%;
    width:50%;
    height:2000px;
    background-color:gray;
}
</style>
<script>
(function() {
    if (!location.hash) return;
    var timeout=1000; //1 second. You may want to wait more
    var done=false;
    var interval=setInterval(function() {
        var elem=document.getElementById(location.hash.substr(1));//hash can be '#id,div.aClass' or similar
        if (!elem) return;
        elem=$(elem);
        var ofs=elem.offset();
        if (!ofs||!ofs.top) return;
        timeout-=100; //interval time
        var scrollY=$(window).scrollTop(); //window to get scrollTop, not html,body which yields 0 on Chrome
        if (Math.abs(ofs.top-scrollY)<55) { //header size, just to be sure
            done=true; // if we are close, then probably the browser did its thing
            clearInterval(interval);
            $('html,body').animate({ scrollTop: ofs.top - 55 }, 300);
        }
        if (timeout<=0) { //otherwise, just do it on timeout
            clearInterval(interval);
            if (!done) $('html,body').animate({ scrollTop: ofs.top - 55 }, 300);
        }
    },100);
})();
</script>
<header></header>
<content>
<div id="topHalf"></div>
<a id="target">This is the target</a>
<div id="bottomHalf"></div>
</content>
<script>
var k=0;
for (var i=0; i<100000000; i++) {
    //some slow running code
    k+=Math.random();
}
document.write('K:',k); // using k so that it doesn't get optimized away
</script>
  End
</html>

Just create above the h4 a div for the anchor. For example:

<div id="simulation"></div>

with:

#simulation {
 position: relative;
 bottom: 50px;
}

I am not sure if JavaScript is the best way to do that. If your header is fixed you can just add 55px padding-top to the main content wrapper in your CSS and that should do the trick.

本文标签: javascriptJQueryGet an offset when loading and going directly to a URL with anchorStack Overflow