ChatGPT解决这个技术问题 Extra ChatGPT

How to scroll an HTML page to a given anchor

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.


D
Dean Harding
function scrollTo(hash) {
    location.hash = "#" + hash;
}

No jQuery required at all!


That doesn't actually scroll though, it just jumps. At that point you might as well just link to the anchor <a href="#anchorName">link</a>
Note that this will only work once. Once the hash is set, the page won't scroll to the same hash unless you change it to a dummy one then set it again.
You should not use scrollTo, because it is already used by the global window object. Also the parameter should not be named hash, because location.hash is defined, too. You may use this code: function scrollToHash(hashName) { location.hash = "#" + hashName; }
@MarkusZeller, why shouldn't the parameter be called hash? It doesn't collide with location, does it?
this does scroll if you set "scroll-behavior: smooth;" on the html element
A
Armando Pérez Marqués

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();

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. Also, it appears that this will be very well supported in browsers.
I've had a lot of issues with jquery solutions not scrolling. This saved me a lot of frustration.
WARNING! This method can have problems if a div above it contains floating elements and cannot determine its size easily.
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.
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.
P
Peter Mortensen

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;

As far as creating a selector to find the <h1 id="anchorName"> or an <a name="anchorName">, use $('#'+hash+',a[name='+hash+']') or slightly optimized $(document.getElementById(hash) || 'a[name='+hash+']') which will search for the element by id first, and resort to searching the a's only if one isn't found.
@gnarf - There isn't any need to optimize the '#' selectors in jQuery - they're already optimized for you. It's fairly easy to see if you've read the jQuery source code.
@CodeJoust - I'm on the jQuery team, I've read it many times, and yes $("#selector") is optimized but $("#selector,a[name='selector']") won't go through the same optimizations as quickly. I suppose my 2.5 year old comment is a little strange sounding. The "optimization" is avoiding the a[name='selector'] search if it finds the id, not optimizing searching for the id.
I had some luck with this approach: About
sometimes this is not accurate... when the page has dynamic parts with lazy load
P
Peter Mortensen

2018-2020 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.

https://i.stack.imgur.com/GECAS.png

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:

https://i.stack.imgur.com/7etqH.png

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

More about the method.


This solution works very very well! Thanks for sharing!
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.
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: stackoverflow.com/a/66739727/334451
P
Peter Mortensen

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);

In the latest Chrome release this is the only method I have found that consistently works. Thanks for the tip!
Very sexy scroll
P
Peter Mortensen

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/


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.
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.
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.
Thank you I love pure javascript solutions
Works in IOS just tested it.
A
Aadit M Shah

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()
    })
}

Excellent answer that removes dependency on jQuery
Wow! Works awesome!
What is "relitere"? Is there a typo?
R
Rich

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;} Click to Scroll

other sections

other sections

other sections

other sections

other sections

other sections

other sections

other sections

other sections

other sections

other sections

other sections

other sections

it will scroll down to this section


This CSS method works great for me and is super elegant!
A
Arseniy-II

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'});

I think you should add the following to CSS style file: css html { scroll-behavior: smooth; }
d
dakab

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;
    }
  }
 });
});

P
Peter Mortensen

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.


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.
Yes, clearly the OP was already aware of anchor link functionality.
A
Adam Pery

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


P
Peter Mortensen

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>

P
Peter Mortensen

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;
      }
    }
  });
});

The selector is throwing an exception in jquery 2.2.0. 0x800a139e - JavaScript runtime error: Syntax error, unrecognized expression: a[href*=#]:not([href=#])
P
Peter Mortensen

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;
 }