319

I’d like to make the browser to scroll the page to a given anchor, just by using JavaScript.

I have specified a name or id attribute in my HTML code:

 <a name="anchorName">..</a>

or

 <h1 id="anchorName2">..</h1>

I’d like to get the same effect as you’d get by navigating to http://server.com/path#anchorName. The page should be scrolled so that the anchor is near the top of the visible part of the page.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Juha Syrjälä
  • 33,425
  • 31
  • 131
  • 183

17 Answers17

408
function scrollTo(hash) {
    location.hash = "#" + hash;
}

No jQuery required at all!

Dean Harding
  • 71,468
  • 13
  • 145
  • 180
280

Way simpler:

var element_to_scroll_to = document.getElementById('anchorName2');
// Or:
var element_to_scroll_to = document.querySelectorAll('.my-element-class')[0];
// Or:
var element_to_scroll_to = $('.my-element-class')[0];
// Basically `element_to_scroll_to` just have to be a reference
// to any DOM element present on the page
// Then:
element_to_scroll_to.scrollIntoView();
Armando Pérez Marqués
  • 5,661
  • 4
  • 28
  • 45
  • 33
    I at first thought Mandx was trolling, then I tried this and it worked. Beyond me how I never came across this method before. [Mozilla Docs for this method](https://developer.mozilla.org/en-US/docs/DOM/element.scrollIntoView). Also, it appears that this will be very well supported in browsers. – Jonathan Dumaine Apr 11 '13 at 05:19
  • 2
    I've had a lot of issues with jquery solutions not scrolling. This saved me a lot of frustration. – NuclearPeon Jul 16 '14 at 21:05
  • 3
    **WARNING!** This method can have problems if a div above it contains floating elements and cannot determine its size easily. – vogomatix Jan 03 '17 at 14:30
  • 6
    This is a clean solution, however as of now it doesn't allow any tweaking, it does a hard scroll. There is an experimental parameter `scrollIntoViewOptions` that has a `behavior: "smooth"` option, but it is currently compatible with Firefox only. – nunop Jan 12 '17 at 10:10
  • How to animate this? – Lying_cat Jun 21 '19 at 02:32
  • @SkuraZZ Best to ask a new question for this, since I just came across this coincidentally. But in any case, you can use `scroll-behavior: smooth`. See https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior – Vincent Nov 16 '19 at 14:55
  • I don't see any animation here – Nathan B Jan 05 '21 at 14:40
  • 1
    If you think you want smooth scroll you should use `document.getElementById("xyz").scrollIntoView({block:"nearest", behavior:"smooth"});` so that the user doesn't get forced smooth scroll if they have disabled that in browser settings. Safari doesn't support this so it will just snap into correct position without animation. You should use this instead of scrolling to given pixel offset because this honors e.g. `scroll-margin` properties automatically. Reimplementing support for `scroll-margin` would be pretty complex. – Mikko Rantalainen Sep 23 '21 at 08:53
127

You can use jQuery's .animate(), .offset() and scrollTop. Like

$(document.body).animate({
    'scrollTop':   $('#anchorName2').offset().top
}, 2000);

Example link: http://jsbin.com/unasi3/edit

If you don't want to animate, use .scrollTop() like:

$(document.body).scrollTop($('#anchorName2').offset().top);

Or JavaScript's native location.hash like:

location.hash = '#' + anchorid;
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jAndy
  • 231,737
  • 57
  • 305
  • 359
81

2018-now Pure JavaScript:

There is a very convenient way to scroll to the element:

el.scrollIntoView({
  behavior: 'smooth', // smooth scroll
  block: 'start' // the upper border of the element will be aligned at the top of the visible part of the window of the scrollable area.
})

But as far as I understand, it does not have such good support as the options below.

Enter image description here

Learn more about the method.


If it is necessary that the element is in the top:

const element = document.querySelector('#element')
const topPos = element.getBoundingClientRect().top + window.pageYOffset

window.scrollTo({
  top: topPos, // scroll so that the element is at the top of the view
  behavior: 'smooth' // smooth scroll
})

Demonstration example on CodePen


If you want the element to be in the center:

const element = document.querySelector('#element')
const rect = element.getBoundingClientRect() // get rects(width, height, top, etc)
const viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);

window.scroll({
  top: rect.top + rect.height / 2 - viewHeight / 2,
  behavior: 'smooth' // smooth scroll
});

Demonstration example on CodePen


Support:

введите сюда описание изображения

They write that scroll is the same method as scrollTo, but support shows better in scrollTo.

More about the method.

  • 1
    This solution works very very well! Thanks for sharing! – gaborous Jun 06 '20 at 11:32
  • 1
    Note that `scrollIntoView` suffers from the same problem `scrollto(some px location)` does - if the location of the element changes as you scroll, you will scroll to the wrong position. This can easily happen if you, for example, have unknown-dimension images loading while you're scrolling, which will push the scroll target element down, and your nice fancy scroll will stop short in an over-dramatized epic fail. – goat Sep 14 '20 at 08:04
  • Note that if you use web fonts with `font-display: swap` you may end up with slightly incorrect scroll offset if you measure the scroll position before the fonts are swapped in. And when you use `font-display: swap` the swapping is asyncronous and depends on client network speed, DNS servers, web font hosting CDN and client CPU power so it's practically random. The best you can do is to try to detect the event for font loading: https://stackoverflow.com/a/66739727/334451 – Mikko Rantalainen Sep 23 '21 at 10:05
39

Great solution by jAndy, but the smooth scroll seems to be having issues working in Firefox.

Writing it this way works in Firefox as well.

(function($) {
    $(document).ready(function() {
         $('html, body').animate({
           'scrollTop':   $('#anchorName2').offset().top
         }, 2000);
    });
})(jQuery);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
5hahiL
  • 1,056
  • 16
  • 36
35

The easiest way to to make the browser to scroll the page to a given anchor is to add *{scroll-behavior: smooth;} in your style.css file and in your HTML navigation use #NameOfTheSection.

*{scroll-behavior: smooth;}
<a href="#scroll-to">Click to Scroll</a>

<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>

<section id="scroll-to">
<p>it will scroll down to this section</p>
</section>
Yuvraj Patil
  • 7,944
  • 5
  • 56
  • 56
eslam elameen
  • 429
  • 4
  • 6
30

In 2018, you don't need jQuery for something simple like this. The built in scrollIntoView() method supports a "behavior" property to smoothly scroll to any element on the page. You can even update the browser URL with a hash to make it bookmarkable.

From this tutorial on scrolling HTML Bookmarks, here is a native way to add smooth scrolling to all anchor links on your page automatically:

let anchorlinks = document.querySelectorAll('a[href^="#"]')
 
for (let item of anchorlinks) { // relitere 
    item.addEventListener('click', (e)=> {
        let hashval = item.getAttribute('href')
        let target = document.querySelector(hashval)
        target.scrollIntoView({
            behavior: 'smooth',
            block: 'start'
        })
        history.pushState(null, null, hashval)
        e.preventDefault()
    })
}
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
coco puffs
  • 1,040
  • 12
  • 8
29

Here is a pure JavaScript solution without jQuery. It was tested on Chrome and Internet Explorer, but not tested on iOS.

function ScrollTo(name) {
  ScrollToResolver(document.getElementById(name));
}

function ScrollToResolver(elem) {
  var jump = parseInt(elem.getBoundingClientRect().top * .2);
  document.body.scrollTop += jump;
  document.documentElement.scrollTop += jump;
  if (!elem.lastjump || elem.lastjump > Math.abs(jump)) {
    elem.lastjump = Math.abs(jump);
    setTimeout(function() { ScrollToResolver(elem);}, "100");
  } else {
    elem.lastjump = null;
  }
}

Demo: https://jsfiddle.net/jd7q25hg/12/

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Michael Whinfrey
  • 573
  • 4
  • 14
  • 1
    Apologies for commenting on an old topic but this works best for me as my project isn't using JQuery. Only issue I noticed is that it misses off 5 pixels or so if you scroll to the very top. – AntBirch Aug 04 '16 at 09:39
  • Very refreshing to see a pure js version. I teach students to always look under the hood and understand what JQuery does for them, so this is a nice example. – Dave Everitt Feb 11 '17 at 22:05
  • 2
    This should be the accepted answer: it is a pure js example AND it achieves the desired scrolling animation effect. I adjusted the timeout value to 20 and it works flawlessly. – Mark Barrasso Dec 02 '17 at 03:01
  • Thank you I love pure javascript solutions – R01010010 Jan 27 '18 at 12:34
  • I had to remove the multiplication by .2; it then went directly to my element. This works great if you are placing your data via document writes and you need to navigate after the page has completed loading. Straight hash navigation from the URL doesn't work in that case. Stick it in an event listener for page load. – TadLewis Jan 06 '20 at 21:57
  • 2
    Works in IOS just tested it. – Debbie Kurth Feb 18 '20 at 04:19
18

Smoothly scroll to the proper position

Get correct y coordinate and use window.scrollTo({top: y, behavior: 'smooth'})

const id = 'anchorName2';
const yourElement = document.getElementById(id);
const y = yourElement.getBoundingClientRect().top + window.pageYOffset;

window.scrollTo({top: y, behavior: 'smooth'});
Arseniy-II
  • 8,323
  • 5
  • 24
  • 49
5

Most answers are unnecessarily complicated.

If you just want to jump to the target element, you don't need JavaScript:

# the link:
<a href="#target">Click here to jump.</a>

# target element:
<div id="target">Any kind of element.</div>

If you want to scroll to the target animatedly, please refer to 5hahiL's answer.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brian
  • 30,156
  • 15
  • 86
  • 87
  • Sometimes, you need to do it dynamically, though; i.e., through no direct action of the user. I believe that's what the OP wants. – jpaugh Jul 03 '15 at 19:13
  • 1
    Yes, clearly the OP was already aware of anchor link functionality. – isherwood Dec 05 '16 at 20:38
5

The solution from CSS-Tricks no longer works in jQuery 2.2.0. It will throw a selector error:

JavaScript runtime error: Syntax error, unrecognized expression: a[href*=#]:not([href=#])

I fixed it by changing the selector. The full snippet is this:

$(function() {
  $("a[href*='#']:not([href='#'])").click(function() {
    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) {
      $('html,body').animate({
        scrollTop: target.offset().top
      }, 1000);
      return false;
    }
  }
 });
});
dakab
  • 5,379
  • 9
  • 43
  • 67
Bill Shihara
  • 375
  • 7
  • 17
5
$(document).ready ->
  $("a[href^='#']").click ->
    $(document.body).animate
      scrollTop: $($(this).attr("href")).offset().top, 1000
cactis
  • 205
  • 5
  • 5
  • An explanation would be in order. E.g., what is the idea/gist? Please respond by [editing (changing) your answer](https://stackoverflow.com/posts/9271279/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Jul 28 '21 at 21:12
4

This works:

$('.scroll').on("click", function(e) {

  e.preventDefault();

  var dest = $(this).attr("href");

  $("html, body").animate({

    'scrollTop':   $(dest).offset().top

  }, 2000);

});

https://jsfiddle.net/68pnkfgd/

Just add the class 'scroll' to any links you wish to animate

Chuck Le Butt
  • 47,570
  • 62
  • 203
  • 289
3

This is a working script that will scroll the page to the anchor. To set it up, just give the anchor link an id that matches the name attribute of the anchor that you want to scroll to.

<script>
    jQuery(document).ready(function ($){
        $('a').click(function (){
            var id = $(this).attr('id');
            console.log(id);
            if ( id == 'cet' || id == 'protein' ) {
                $('html, body').animate({ scrollTop: $('[name="' + id + '"]').offset().top}, 'slow');
            }
        });
    });
</script>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mr.Lister
  • 422
  • 3
  • 11
3

jQuery("a[href^='#']").click(function(){
    jQuery('html, body').animate({
        scrollTop: jQuery( jQuery(this).attr('href') ).offset().top
    }, 1000);
    return false;
});
Adam Pery
  • 1,924
  • 22
  • 21
1

I found an easy and simple jQuery solution on CSS-Tricks. That's the one I'm using now.

$(function() {
  $('a[href*=#]:not([href=#])').click(function() {
    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) {
        $('html,body').animate({
          scrollTop: target.offset().top
        }, 1000);
        return false;
      }
    }
  });
});
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Horacio
  • 1,794
  • 1
  • 16
  • 23
  • 1
    The selector is throwing an exception in jquery 2.2.0. 0x800a139e - JavaScript runtime error: Syntax error, unrecognized expression: a[href*=#]:not([href=#]) – Bill Shihara Jan 10 '16 at 00:04
1

A Vue.js 2 solution ... add a simple data property to simply force the update:

  const app = new Vue({
  ...

  , updated: function() {
           this.$nextTick(function() {
           var uri = window.location.href
           var anchor = ( uri.indexOf('#') === -1 ) ? '' : uri.split('#')[1]
           if ( String(anchor).length > 0 && this.updater === 'page_load' ) {
              this.updater = "" // only on page-load !
              location.href = "#"+String(anchor)
           }
         })
        }
     });
     app.updater = "page_load"

 /* Smooth scrolling in CSS - it works in HTML5 only */
 html, body {
     scroll-behavior: smooth;
 }
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Yordan Georgiev
  • 5,114
  • 1
  • 56
  • 53