单击锚点链接时平滑滚动


487

我的页面上有几个超链接。用户访问我的帮助部分时将阅读的常见问题解答。

使用锚链接,我可以使页面滚动到锚,并在那里引导用户。

有没有办法使滚动平滑?

但是请注意,他正在使用自定义JavaScript库。也许jQuery提供了类似的功能?


能否请您复习最佳答案?纯CSS一个在线解决方案是很难全部庞大的jQuery的建议中找到:stackoverflow.com/a/51588820/1422553
АлександрКиричек

Answers:


1158

2018年4月更新:现在有一种本地方法可以做到这一点

document.querySelectorAll('a[href^="#"]').forEach(anchor => {
    anchor.addEventListener('click', function (e) {
        e.preventDefault();

        document.querySelector(this.getAttribute('href')).scrollIntoView({
            behavior: 'smooth'
        });
    });
});

当前仅在最先进的浏览器中支持此功能。


对于较旧的浏览器支持,可以使用以下jQuery技术:

$(document).on('click', 'a[href^="#"]', function (event) {
    event.preventDefault();

    $('html, body').animate({
        scrollTop: $($.attr(this, 'href')).offset().top
    }, 500);
});

这是小提琴:http : //jsfiddle.net/9SDLw/


如果您的目标元素没有ID,并且您正在通过ID链接到它name,请使用以下命令:

$('a[href^="#"]').click(function () {
    $('html, body').animate({
        scrollTop: $('[name="' + $.attr(this, 'href').substr(1) + '"]').offset().top
    }, 500);

    return false;
});

为了提高性能,您应该缓存该$('html, body')选择器,以便它不会在每次单击定位器时都运行:

var $root = $('html, body');

$('a[href^="#"]').click(function () {
    $root.animate({
        scrollTop: $( $.attr(this, 'href') ).offset().top
    }, 500);

    return false;
});

如果您希望更新URL,请在animate回调中进行操作:

var $root = $('html, body');

$('a[href^="#"]').click(function() {
    var href = $.attr(this, 'href');

    $root.animate({
        scrollTop: $(href).offset().top
    }, 500, function () {
        window.location.hash = href;
    });

    return false;
});

10
这似乎从网址中删除了#extension,从而破坏了back函数。有没有解决的办法?
Fletch

2
@JosephSilber不应该scrollTop: $(this.hash).offset().top代替scrollTop: $(this.href).offset().top吗?
Gregory Pakosz

4
@CreateSean -scrollTop: $(href).offset().top - 72
约瑟夫·西尔伯

5
我认为html, body不需要在此处缓存对象,每次单击运行一次选择器的确不是很多。

2
第一个解决方案是最好的,最现代化的,您可以使用此填充工具以支持旧的浏览器这种行为与该填充工具
埃菲社

166

正确的语法是:

//Smooth scrolling with links
$('a[href*=\\#]').on('click', function(event){     
    event.preventDefault();
    $('html,body').animate({scrollTop:$(this.hash).offset().top}, 500);
});

// Smooth scrolling when the document is loaded and ready
$(document).ready(function(){
  $('html,body').animate({scrollTop:$(location.hash).offset().‌​top}, 500);
});

简化:干

function smoothScrollingTo(target){
  $('html,body').animate({scrollTop:$(target).offset().​top}, 500);
}
$('a[href*=\\#]').on('click', function(event){     
    event.preventDefault();
    smoothScrollingTo(this.hash);
});
$(document).ready(function(){
  smoothScrollingTo(location.hash);
});

的说明href*=\\#

  • *表示它匹配包含#char的内容。因此只匹配锚点。有关此含义的更多信息,请参见此处
  • \\是因为#在CSS选择器中,字符是特殊字符,因此我们必须对其进行转义。

8
我不得不改变$('a'),以$('a[href*=#]')服务于仅锚网址
okliv

2
@okliv这会提供太多服务,例如javascript链接<a href="javascript:$('#test').css('background-color', '#000')">Test</a>。您应该使用$('a[href^=#]')匹配所有以井号字符开头的网址。
马丁·布劳恩

3
同样,“#”是一个特殊字符,需要像这样进行转义:a[href^=\\#]
QuinnFreedman

3
这导致指向其他页面上的锚点的链接停止工作。通过添加条件if($($(this(hash).selector).length){...平滑滚动来解决。}
Liren

1
初次进入新页面时如何设置动画?例如,通过单击:website.com/newpage/#section2。我希望它加载页面然后向下滚动。那可能吗?
萨耶

72

CSS3中的新热点。这比此页面上列出的每种方法都容易得多,并且不需要Javascript。只要在您的CSS中输入以下代码,所有指向您自己页面内位置的链接就会突然出现滚动动画。

html{scroll-behavior:smooth}

之后,任何指向div的链接都将平滑地转到这些部分。

<a href="#section">Section1</a>

编辑:对于那些对上面的标签感到困惑的人。基本上,这是一个可单击的链接。然后,您可以在网页中的某个位置添加另一个div标签,例如

<div classname="section">content</div>

在这方面,链接将是可单击的,并且将转到任何#section,在这种情况下,这就是我们称为div的div。

顺便说一句,我花了几个小时试图使它工作。在一些晦涩的注释部分找到了解决方案。这是越野车,无法在某些标签中使用。在体内没有作用。当我将它放在CSS文件的html {}中时,它终于可以工作了。


4
我可以非常方便,但是它们是缺点
Buzut

3
不错,但要小心,因为目前Safari浏览器不支持它,显然资源管理器不支持它(03/2019)
Marco Romano

2
不错的解决方案,仅覆盖范围为74.8%。也许在将来
iepur1lla

1
太神奇了 非常感谢。
Mikkel Fennefoss

1
这将是未来几年最现实的答案。
Nurul Huda

22
$('a[href*=#]').click(function(event){
    $('html, body').animate({
        scrollTop: $( $.attr(this, 'href') ).offset().top
    }, 500);
    event.preventDefault();
});

这对我来说很完美


1
“ event.preventDefault();” 可以代替“返回false”;
Andres Separ 2014年

抱歉,但无法正常运行,并且无法快速显示在名为anchor的页面上。
卡姆列什

18

令我惊讶的是,没有人发布过一种本机解决方案,该解决方案还负责更新浏览器位置哈希以进行匹配。这里是:

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

参见教程:http : //www.javascriptkit.com/javatutors/scrolling-html-bookmark-javascript.shtml

对于带有粘性标头的网站,scroll-padding-top可以使用CSS提供偏移量。


1
我最喜欢这个答案。但是,fais无法提供补偿。在固定标头的情况下,这是需要的。
bskool

Unfotunately,同样支持比较差为CSS滚动行为属性:developer.mozilla.org/en-US/docs/Web/CSS/...
梅德Nevzorov

15

只有CSS

html {
    scroll-behavior: smooth !important;
}

您只需要添加此内容。现在,您的内部链接滚动行为将像流一样平滑。

:所有最新的浏览器(OperaChromeFirefox等)支持此功能。

要了解详细信息,请阅读本文


1
真好!为什么这不是公认的答案?我们不需要所有的JavaScript!
Trevor de Koekkoek,

1
效果很好,这应该是公认的答案。


1
它的作品就像魅力。不需要js
Navbro,

这是有史以来平滑滚动的最佳解决方案!谢谢!
yehanny


6
$(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;
      }
    }
  });
});

官方:http : //css-tricks.com/snippets/jquery/smooth-scrolling/


1
这似乎仅适用于内部页面锚定链接,但其他页面的锚定链接不起作用,例如website.com/about-us/#who-we-are
rainerbrunotte

5

这里已经有很多好的答案-但是它们都缺少必须排除空锚的事实。否则,一旦单击空锚,这些脚本就会生成JavaScript错误。

我认为正确的答案是这样的:

$('a[href*=\\#]:not([href$=\\#])').click(function() {
    event.preventDefault();

    $('html, body').animate({
        scrollTop: $($.attr(this, 'href')).offset().top
    }, 500);
});

4

使用JQuery:

$('a[href*=#]').click(function(){
  $('html, body').animate({
    scrollTop: $( $.attr(this, 'href') ).offset().top
  }, 500);
  return false;
});


3

给出的答案有效,但禁用传出链接。在具有额外奖励的版本下,缓和(摆动)并尊重传出链接。

$(document).ready(function () {
    $('a[href^="#"]').on('click', function (e) {
        e.preventDefault();

        var target = this.hash;
        var $target = $(target);

        $('html, body').stop().animate({
            'scrollTop': $target.offset().top
        }, 900, 'swing', function () {
            window.location.hash = target;
        });
    });
});

+1,stop()但是url碎屑无法正常工作:“后退”按钮没有恢复原状,这是因为在动画完成后在url中设置了碎屑时。最好不要在URL中添加碎屑,例如airbnb就是这样做的。
艾瑞克(Eric)

3

的HTML

<a href="#target" class="smooth-scroll">
    Link
</a>
<div id="target"></div>

或使用绝对完整网址

<a href="https://somewebsite.com/#target" class="smooth-scroll">
    Link
</a>
<div id="target"></div>

jQuery的

$j(function() {
    $j('a.smooth-scroll').click(function() {
        if (
                window.location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '')
            &&  window.location.hostname == this.hostname
        ) {
            var target = $j(this.hash);
            target = target.length ? target : $j('[name=' + this.hash.slice(1) + ']');
            if (target.length) {
                $j('html,body').animate({
                    scrollTop: target.offset().top - 70
                }, 1000);
                return false;
            }
        }
    });
});

3

如今,现代浏览器的速度要快一些。setInterval可能有效。如今,此功能在Chrome和Firefox上运行良好。(Safari的浏览速度有点慢,对IE没什么麻烦)

function smoothScroll(event) {
    if (event.target.hash !== '') { //Check if tag is an anchor
        event.preventDefault()
        const hash = event.target.hash.replace("#", "")
        const link = document.getElementsByName(hash) 
        //Find the where you want to scroll
        const position = link[0].getBoundingClientRect().y 
        let top = 0

        let smooth = setInterval(() => {
            let leftover = position - top
            if (top === position) {
                clearInterval(smooth)
            }

            else if(position > top && leftover < 10) {
                top += leftover
                window.scrollTo(0, top)
            }

            else if(position > (top - 10)) {
                top += 10
                window.scrollTo(0, top)
            }

        }, 6)//6 milliseconds is the faster chrome runs setInterval
    }
}

3

使用滚动行为可以做到这一点。添加以下属性。

    scroll-behavior: smooth;

就是这样。不需要JS。

a {
  display: inline-block;
  width: 50px;
  text-decoration: none;
}
nav, scroll-container {
  display: block;
  margin: 0 auto;
  text-align: center;
}
nav {
  width: 339px;
  padding: 5px;
  border: 1px solid black;
}
scroll-container {
  display: block;
  width: 350px;
  height: 200px;
  overflow-y: scroll;
  scroll-behavior: smooth;
}
scroll-page {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  font-size: 5em;
}
<nav>
  <a href="#page-1">1</a>
  <a href="#page-2">2</a>
  <a href="#page-3">3</a>
</nav>
<scroll-container>
  <scroll-page id="page-1">1</scroll-page>
  <scroll-page id="page-2">2</scroll-page>
  <scroll-page id="page-3">3</scroll-page>
</scroll-container>

PS:请检查浏览器兼容性。


我应该在哪个容器上使用scroll-behavior:smooth;
CraZyDroiD

如有疑问,请将其添加到正文标签@CraZyDroiD
Santosh

2

添加:

function () {
    window.location.hash = href;
}

在某种程度上抵消了垂直偏移

top - 72

在Firefox和IE中,而不是在Chrome中。基本上,页面会根据偏移量平滑滚动到应停止的位置,然后再跳至没有偏移量的页面位置。

它确实将哈希值添加到url的末尾,但是按回去并不会使您回到顶部,它只是从url中删除哈希值,并将其保留在查看窗口中。

这是我正在使用的完整js:

var $root = $('html, body');
$('a').click(function() {
    var href = $.attr(this, 'href');
    $root.animate({
        scrollTop: $(href).offset().top - 120
    }, 500, function () {
        window.location.hash = href;
    });
    return false;
});

2

此解决方案也适用于以下URL,而不会中断指向不同页面的锚链接。

http://www.example.com/dir/index.html
http://www.example.com/dir/index.html#anchor

./index.html
./index.html#anchor

等等

var $root = $('html, body');
$('a').on('click', function(event){
    var hash = this.hash;
    // Is the anchor on the same page?
    if (hash && this.href.slice(0, -hash.length-1) == location.href.slice(0, -location.hash.length-1)) {
        $root.animate({
            scrollTop: $(hash).offset().top
        }, 'normal', function() {
            location.hash = hash;
        });
        return false;
    }
});

我尚未在所有浏览器中对此进行测试。


2

这将使jQuery能够轻松识别目标哈希并知道何时何地停止。

$('a[href*="#"]').click(function(e) {
    e.preventDefault();
    var target = this.hash;
    $target = $(target);

    $('html, body').stop().animate({
        'scrollTop': $target.offset().top
    }, 900, 'swing', function () {
        window.location.hash = target;
    });
});

2
$("a").on("click", function(event){
    //check the value of this.hash
    if(this.hash !== ""){
        event.preventDefault();

        $("html, body").animate({scrollTop:$(this.hash).offset().top}, 500);

        //add hash to the current scroll position
        window.location.hash = this.hash;

    }



});

2

经过测试和验证的代码

<script>
jQuery(document).ready(function(){
// Add smooth scrolling to all links
jQuery("a").on('click', function(event) {

// Make sure this.hash has a value before overriding default behavior
if (this.hash !== "") {
  // Prevent default anchor click behavior
  event.preventDefault();

  // Store hash
  var hash = this.hash;

  // Using jQuery's animate() method to add smooth page scroll
  // The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area
  jQuery('html, body').animate({
    scrollTop: jQuery(hash).offset().top
  }, 800, function(){

    // Add hash (#) to URL when done scrolling (default click behavior)
    window.location.hash = hash;
  });
} // End if
});
});
</script>

1

我对“ / xxxxx#asdf”和“ #asdf” href锚均执行了此操作

$("a[href*=#]").on('click', function(event){
    var href = $(this).attr("href");
    if ( /(#.*)/.test(href) ){
      var hash = href.match(/(#.*)/)[0];
      var path = href.match(/([^#]*)/)[0];

      if (window.location.pathname == path || path.length == 0){
        event.preventDefault();
        $('html,body').animate({scrollTop:$(this.hash).offset().top}, 1000);
        window.location.hash = hash;
      }
    }
});

1

这是我为多个链接和锚点实现的解决方案,以实现平滑滚动:

http://www.adriantomic.se/development/jquery-localscroll-tutorial/ 如果您在导航div中设置了导航链接,并使用以下结构声明了此链接:

<a href = "#destinationA">

以及您相应的锚标记目的地:

<a id = "destinationA">

然后将其加载到文档的头部:

    <!-- Load jQuery -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>

<!-- Load ScrollTo -->
<script src="http://flesler-plugins.googlecode.com/files/jquery.scrollTo-1.4.2-min.js"></script>

<!-- Load LocalScroll -->
<script src="http://flesler-plugins.googlecode.com/files/jquery.localscroll-1.2.7-min.js"></script>

<script type = "text/javascript">
 $(document).ready(function()
    {
        // Scroll the whole document
        $('#menuBox').localScroll({
           target:'#content'
        });
    });
</script>

感谢@Adriantomic


1

如果页面上有一个简单的按钮可向下滚动到div,并希望通过跳到顶部来使后退按钮起作用,则只需添加以下代码:

$(window).on('hashchange', function(event) {
    if (event.target.location.hash=="") {
        window.scrollTo(0,0);
    }
});

通过读取哈希值,并像约瑟夫·西尔伯斯(Joseph Silbers)回答一样滚动,可以扩展到不同的div。


1

永远不要忘记offset()函数会赋予您元素在文档中的位置。因此,当需要相对于其父级滚动元素时,应使用此元素;

    $('.a-parent-div').find('a').click(function(event){
        event.preventDefault();
        $('.scroll-div').animate({
     scrollTop: $( $.attr(this, 'href') ).position().top + $('.scroll-div').scrollTop()
     }, 500);       
  });

关键是获取scroll-div的scrollTop并将其添加到scrollTop。如果您不这样做,position()函数将始终为您提供不同的位置值。


1

可以window.scroll()与锚标记的偏移顶部配合使用behavior: smoothtop设置其位置,以确保锚标记位于视口的顶部。

document.querySelectorAll('a[href^="#"]').forEach(a => {
    a.addEventListener('click', function (e) {
        e.preventDefault();
        var href = this.getAttribute("href");
        var elem = document.querySelector(href)||document.querySelector("a[name="+href.substring(1, href.length)+"]");
        //gets Element with an id of the link's href 
        //or an anchor tag with a name attribute of the href of the link without the #
        window.scroll({
            top: elem.offsetTop, 
            left: 0, 
            behavior: 'smooth' 
        });
        //if you want to add the hash to window.location.hash
        //you will need to use setTimeout to prevent losing the smooth scrolling behavior
       //the following code will work for that purpose
       /*setTimeout(function(){
            window.location.hash = this.hash;
        }, 2000); */
    });
});

演示:

您只需将CSS属性设置scroll-behaviorsmooth(大多数现代浏览器都支持)即可,从而无需使用Javascript。


0

感谢您的分享,Joseph Silber。这是2018年的ES6解决方案,仅作了少许改动以保持标准行为(滚动到顶部):

document.querySelectorAll("a[href^=\"#\"]").forEach((anchor) => {
  anchor.addEventListener("click", function (ev) {
    ev.preventDefault();

    const targetElement = document.querySelector(this.getAttribute("href"));
    targetElement.scrollIntoView({
      block: "start",
      alignToTop: true,
      behavior: "smooth"
    });
  });
});

0

在将哈希添加到浏览器url时,需要jquery并进行动画处理以使用指定的名称(而不是ID)锚定标记。还可修复大多数使用jquery的答案中的错误,该错误中的#号没有以转义的反斜杠作为前缀。不幸的是,后退按钮无法正确导航回先前的哈希链接...

$('a[href*=\\#]').click(function (event)
{
    let hashValue = $(this).attr('href');
    let name = hashValue.substring(1);
    let target = $('[name="' + name + '"]');
    $('html, body').animate({ scrollTop: target.offset().top }, 500);
    event.preventDefault();
    history.pushState(null, null, hashValue);
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.