1

You can scroll to an element using a url with a hashtag and the elements ID:

window.location.href = "#ID"

This will scrol so that the top of the element is at the top of the browser. How would I scroll to an element so that it's vertically centered?

3 Answers3

1

you can scroll up right after the navigation happens:

addEventListener("hashchange", function(){
    setTimeout(function(){ 
          document[
             document.documentElement.scrollTop ? 
             "documentElement":
             "body"
          ].scrollTop-= (innerHeight/2.1);
     }, 1); 
}, false);

this will cause the focused element to appear half-way up the screen, vertically centered. the 2.1 causes it to scroll just under half the screen, since there will be some room at the top already. you can adjust the ".1" to match your desired effect (baseline, middle, etc).

obligatory fiddle link: http://jsfiddle.net/ckhafLzq/2/

dandavis
  • 16,370
  • 5
  • 40
  • 36
  • innerHeight is the height in pixels of the current viewport, what's not to understand? – dandavis Oct 29 '14 at 08:28
  • dandavis in that case I've misunderstood your answer cause `(innerHeight/2.1)` will not center an item in the viewport. The math is really simple: scrollToElement - ((viewportHeight - elementHeight) / 2) ... or I'm missing something? – Roko C. Buljan Oct 29 '14 at 08:33
  • hm... your fiddle does not work in FF and also the OP asked for `" to an element so that it's vertically centered?"` – Roko C. Buljan Oct 29 '14 at 08:51
  • @RokoC.Buljan: silly quirks, here's one that works in firefox and chrome: http://jsfiddle.net/ckhafLzq/2/ , thanks for the head's up! – dandavis Oct 29 '14 at 08:58
1

This is what I have achieved:

function centerScroll(element) {
    if (!(element instanceof Element)) {
        throw new TypeError("Element expected");
    }

    var bodyRect = document.body.getBoundingClientRect();
    var elementRect = element.getBoundingClientRect();

    var left = elementRect.left - bodyRect.left;
    var top = elementRect.top - bodyRect.top;

    var windowWidth = window.innerWidth;
    var windowHeight = window.innerHeight;

    var elementWidth = element.offsetWidth;
    var elementHeight = element.offsetHeight;

    var x = left - Math.max(0, (windowWidth - elementWidth) / 2);
    var y = top - Math.max(0, (windowHeight - elementHeight) / 2);

    window.scrollTo(x, y);

    return [x, y];
}
0

No, there's no built-in way, you'd have to write that yourself:

function center_element_vertically(elt) {
    var rect = elt.getBoundingClientRect();
    window.scrollTo(0, rect.top + window.pageYOffset - 
        (window.innerHeight - rect.height)/2);
}

Alternatives without writing your own code: you could scroll so that the element was at the bottom by passing false to scrollIntoView, or scroll only if the element is not already visible by calling scrollIntoViewIfNeeded, available only in Chrome AFAIK.

  • And like how would I write such function? –  Oct 29 '14 at 08:16
  • By doing some computation involving the size and current position of the element (use `getBoundingClientRect`). Is your question literally "is there any way?", or is it actually "how do i?"? –  Oct 29 '14 at 08:19
  • Shouldn't ` + window.pageYOffset` be ` - document.getBoundingClientRect().top`? –  Oct 29 '14 at 13:44
  • `document` does not have a `getBoundingClientRect` method, it's a method on `HTMLElement`. Is there something wrong with `window.pageYOffset`? –  Oct 29 '14 at 15:47
  • Sorry, I meant document.body I wondered since I saw this: http://stackoverflow.com/questions/442404/retrieve-the-position-x-y-of-an-html-element (See the most upvoted answer) –  Oct 29 '14 at 16:07
  • I think `window.pageYOffset` and `document.body.getBoundingClientRect().top` are the same (except the signs are reversed). –  Oct 29 '14 at 16:18
  • WHAT!??! YOU GET 10 REP FOR AN UPVOTE ON AN ANSWER?!?!?!?!?!?!?!? –  Oct 29 '14 at 18:27
  • An upvote is an upvote. Your solution was quite clean and also handles the X-direction. –  Oct 29 '14 at 18:58
  • Srsly I've been member a year, never knew that –  Oct 29 '14 at 18:59