Adding an automatic offset to the scroll position

2019-01-25 07:59发布

问题:

I have the following problem:

Like on Facebook, I have a menu bar at the top of the page that is always visible (position: fixed;). When I now click hash-links on my page (or load a new page with a hash in the url) to jump to a certain element on the page, the browser always scrolls this element to the very top of the page, meaning that the element is behind the top menu bar, afterwards.

I'd like to add some Javascript (jQuery or normal Javascript) that automatically adds a (negative) offset to this scroll position, so that the linked element is positioned right under the top menu bar when a link is clicked or the page is loaded. But I don't just want to add event listeners to all links that take care of this. I also want a solution that works, if the page is loaded with a hash portion in the url using the browser's address bar (or when linking to a different page with a hash at the end of the url).

You can find a clickdummy of my page at http://loud.fm/tmp/details.html. Click on the comments-bubble on the top right of the image on the left side to jump to the comments. If your browser window is small enough, you should jump to the grey "COMMENTS" headline and pagination right before the comments are listed. I'd want the headline and pagination to be displayed right under the top menu, after the jump link was clicked.

Can you help me with this, please? Thanks in advance! :)

Regards, René

回答1:

I actually found a solution myself that worked for me, using only css:

I added a margin-top: -40px; and padding-top: 40px; to the element that the jump-link was pointing to. This works for all major browsers: IE (7-9), Firefox, Opera, Chrome and Safari.

Only problem: In case that this element is after a floated element, the negative margin doesn't work (meaning the positive padding becomes visible). Please comment, if anyone knows a solution/workaround for this. I'll update my post then. Thank you!



回答2:

To add to the solution on this, I found that setting the display to none solved the issue of padding being visible when used amongst floated elements.

So:

.symbol-target {
    padding-top: 40px;
    margin-top: -40px;
    width: 1px; /* '0' will not work for Opera */
    display: hidden;
}

I also included this style as an empty div right above my target content.



回答3:

As an example consider D's bootDoc solution that works in all major browsers:

CSS (insert your titlebar height instead of 40px):

.symbol-target {
    padding-top: 40px;
    margin-top: -40px;
    width: 1px; /* '0' will not work for Opera */
    display: inline-block;
}

HTML:

<h3>
    <span class="symbol-target" id="myTarget">&nbsp;</span>
    <a href="#myTarget">My text</a>
</h3>

Real page example:

std.array.uninitializedArray documentation using bootDoc

Note:

It doesn't work for IE 6.



回答4:

I found this way of adding a :before in the css seems to work well.

h2:before { 
  display: block; 
  content: " "; 
  margin-top: -285px; 
  height: 285px; 
  visibility: hidden; 
}

More at CSS Tricks website



回答5:

The thing that worked best for me was to do this:

  1. Give the designated ID (what you want in the URL) to a different element within the required element.
  2. Make that new element absolute and move it X pixels above the required element, where X is the height of the fixed header.


回答6:

Unfortunately (at least using Firefox) neither padding nor margin helps here (putting them on a 'main' div containing everything but the menubar); scrolling to an anchor always puts it at the very top of the page, fixed elements be damned.

I think you're going to have to go with your original idea, but remember that by using delegation you can set just one handler that will work with all the links in your menubar, including ones dynamically added.



回答7:

Try putting a padding at the top of you page to occupy the area behind the menubar. Something like: padding-top:80px; (instead of 80px you should put the height of your menubar).



回答8:

With pure javascript you can do the following. It will listen to a click event to all anchor tag and do scrolling to your desired position in the page (It is using jquery):

/* go to specific position if you load the page directly from address bar */
var navbarHeight = document.getElementById('mynavbar').clientHeight;
function gotoSpecificPosition() {
  if (window.location.hash.length !== 0) {
    window.scrollTo(window.scrollX, window.scrollY - navbarHeight );
  }
}

/* Captures click events on all anchor tag with a hash tag */
$(document).on('click', 'a[href^="#"]', function(event) {
  // Click events are captured before hashchanges. Timeout
  // causes offsetAnchor to be called after the page jump.
  window.setTimeout(function() {
    offsetAnchor();
  }, 0);
});

window.setTimeout(offsetAnchor, 0);

The above code will handle all the tricks.