Cuộn mượt mà khi nhấp vào liên kết neo


487

Tôi có một vài siêu liên kết trên trang của tôi. Câu hỏi thường gặp mà người dùng sẽ đọc khi họ truy cập phần trợ giúp của tôi.

Sử dụng các liên kết Anchor, tôi có thể làm cho trang cuộn về phía neo và hướng dẫn người dùng ở đó.

Có cách nào để làm cho cuộn di chuyển trơn tru?

Nhưng lưu ý rằng anh ta đang sử dụng một thư viện JavaScript tùy chỉnh. Có lẽ jQuery cung cấp một số thứ như thế này nướng trong?


Bạn có thể vui lòng xem lại câu trả lời tốt nhất có thể? Tinh khiết giải pháp css một dòng là khó để tìm thấy trong tất cả các gợi ý jquery cồng kềnh: stackoverflow.com/a/51588820/1422553
Александр Киричек

Câu trả lời:


1159

Cập nhật tháng 4 năm 2018: Hiện tại có một cách riêng để làm điều này :

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

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

Điều này hiện chỉ được hỗ trợ trong các trình duyệt cạnh chảy máu nhất.


Để hỗ trợ trình duyệt cũ hơn, bạn có thể sử dụng kỹ thuật jQuery này:

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

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

Và đây là câu đố: http://jsfiddle.net/9SDLw/


Nếu phần tử mục tiêu của bạn không có ID và bạn đang liên kết với nó name, hãy sử dụng phần tử này:

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

    return false;
});

Để tăng hiệu suất, bạn nên lưu trữ bộ $('html, body')chọn đó để nó không chạy mỗi khi nhấp vào neo:

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

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

    return false;
});

Nếu bạn muốn URL được cập nhật, hãy thực hiện trong vòng animategọi lại:

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
Điều này dường như để loại bỏ #extension khỏi URL, phá vỡ chức năng trở lại. Có cách nào để giái quyết vấn đề này không?
Fletch

2
@JosephSilber không nên scrollTop: $(this.hash).offset().topthay thế scrollTop: $(this.href).offset().top?
Gregory Pakosz

4
@CreateSean -scrollTop: $(href).offset().top - 72
Joseph Silber

5
Tôi cho rằng việc lưu trữ html, bodyđối tượng ở đây là không cần thiết, chạy bộ chọn một lần cho mỗi lần nhấp không thực sự nhiều.

2
Giải pháp đầu tiên là tốt nhất và hiện đại nhất, bạn có thể sử dụng polyfill này để hỗ trợ hành vi này trên các trình duyệt cũ với polyfill
Efe

166

Cú pháp đúng là:

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

Đơn giản hóa : KHÔ

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

Giải thích về href*=\\#:

  • *có nghĩa là nó phù hợp với những gì có chứa #char. Do đó chỉ phù hợp với neo . Để biết thêm về ý nghĩa của điều này, xem tại đây
  • \\là bởi vì #một char đặc biệt trong bộ chọn css, vì vậy chúng ta phải thoát nó.

8
tôi đã phải thay đổi $('a')để $('a[href*=#]')chỉ phục vụ các url neo
okliv

2
@okliv Điều này sẽ phục vụ quá nhiều, ví dụ như một liên kết javascript như <a href="javascript:$('#test').css('background-color', '#000')">Test</a>. Bạn nên sử dụng $('a[href^=#]')để khớp với tất cả các url bắt đầu bằng ký tự băm.
Martin Braun

3
Ngoài ra, '#' là một nhân vật đặc biệt và nó cần phải được trốn thoát như thế này:a[href^=\\#]
QuinnFreedman

3
Điều này khiến các liên kết đến các neo trên các trang khác ngừng hoạt động. Giải quyết bằng cách thêm một điều kiện if ($ ($ (this.hash) .selector) .length) {... cuộn trơn tru. }
Liren

1
Làm thế nào tôi có thể làm động điều này khi lần đầu tiên đi đến một trang mới? Ví dụ: bằng cách nhấp vào: website.com/newpage/#section2. Tôi muốn nó tải trang và sau đó cuộn xuống. Điều đó có thể không?
Samyer

72

Độ nóng mới trong CSS3. Điều này dễ dàng hơn nhiều so với mọi phương pháp được liệt kê trên trang này và không yêu cầu Javascript. Chỉ cần nhập mã dưới đây vào css của bạn và tất cả các liên kết bất ngờ trỏ đến các vị trí bên trong trang của bạn sẽ có một hình ảnh động cuộn mượt mà.

html{scroll-behavior:smooth}

Sau đó, bất kỳ liên kết nào hướng tới một div sẽ lướt qua các phần đó một cách trơn tru.

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

Chỉnh sửa: Đối với những người nhầm lẫn về các thẻ ở trên. Về cơ bản đó là một liên kết có thể nhấp. Sau đó, bạn có thể có một thẻ div khác ở đâu đó trong trang web của mình như

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

Về vấn đề này, một liên kết sẽ thể nhấp chuột và sẽ đi đến bất cứ điều gì #section là, trong trường hợp này đó là div, chúng ta gọi là phần.

BTW, tôi đã dành hàng giờ cố gắng để làm việc này. Tìm thấy giải pháp trong một số ý kiến ​​mơ hồ. Đó là lỗi và sẽ không hoạt động trong một số thẻ. Không hoạt động trong cơ thể. Cuối cùng nó cũng hoạt động khi tôi đặt nó vào html {} trong tệp CSS.


4
Tôi có thể rất tiện dụng nhưng chúng là nhược điểm
Buzut 13/03/19

3
tốt, nhưng hãy cẩn thận vì hiện tại nó không được Safari hỗ trợ và rõ ràng là Explorer (03/2019)
Marco Romano

2
giải pháp tốt đẹp, chỉ có phạm vi bảo hiểm với giới hạn 74,8%. có thể trong tương lai
iepur1lla

1
Điều đó thật tuyệt vời. Cảm ơn rất nhiều.
Mikkel Fennefoss

1
Đây sẽ là câu trả lời phù hợp nhất trong những năm tới.
Nurul Huda

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

điều này làm việc hoàn hảo cho tôi


1
"event.preventDefault ();" có thể thay thế "trả về false;"
Andres tách

Xin lỗi để nói, nhưng không hoạt động và hiển thị trên trang có tên neo nhanh chóng mà không có bất kỳ sự trơn tru.
Kam Meat

18

Tôi ngạc nhiên không ai đã đăng một giải pháp riêng mà cũng quan tâm đến việc cập nhật hàm băm vị trí trình duyệt cho phù hợp. Đây là:

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

Xem hướng dẫn: http://www.javascriptkit.com/javatutors/scrolling-html-bookmark-javascript.shtml

Đối với các trang web có tiêu đề dính, scroll-padding-topCSS có thể được sử dụng để cung cấp phần bù.


1
Tôi thích câu trả lời này nhất. Tuy nhiên afais không có cách nào để cung cấp một sự bù đắp. Như sẽ cần trong trường hợp tiêu đề cố định.
bskool

Thật không may, sự hỗ trợ kém tương tự như đối với thuộc tính hành vi cuộn CSS: developer.mozilla.org/en-US/docs/Web/CSS/
mẹo

15

Chỉ CSS

html {
    scroll-behavior: smooth !important;
}

Tất cả bạn chỉ cần thêm điều này. Bây giờ hành vi cuộn liên kết nội bộ của bạn sẽ trơn tru như luồng.

Lưu ý : Tất cả các trình duyệt mới nhất ( Opera, Chrome,Firefox vv) hỗ trợ tính năng này.

để hiểu chi tiết, đọc bài viết này


1
đẹp! Tại sao đây không phải là câu trả lời được chấp nhận? chúng tôi không cần tất cả các javascript đó!
Trevor de Koekkoek

1
Nó hoạt động tuyệt vời, đây nên là câu trả lời được chấp nhận.
ngôi mộ

Kiểm tra hỗ trợ trình duyệt tại đây
Ryan Zhou

1
nó hoạt động như một nét duyên dáng không cần js
Navbro

Đây là giải pháp tốt nhất để di chuyển mượt mà EVER! Cảm ơn!
yehanny

10

Tôi đề nghị bạn tạo mã chung này:

$('a[href^="#"]').click(function(){

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

    $('html, body').animate({
        scrollTop:$(the_id).offset().top
    }, 'slow');

return false;});

Bạn có thể thấy một bài viết rất hay ở đây: jquery-effet-smooth-scroll-defilement-fluide


9
Đây không phải là chung chung, đây là jQuery.
AnrDaemon

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

Chính thức: http://css-tricks.com/snippets/jquery/smooth-scrolling/


1
điều này dường như chỉ hoạt động đối với các liên kết neo trang bên trong, nhưng các liên kết neo từ các trang khác không hoạt động, ví dụ: website.com/about-us/#who-we-are
rainerbrunotte

5

Đã có rất nhiều câu trả lời hay ở đây - tuy nhiên tất cả chúng đều thiếu thực tế là các mỏ neo trống phải được loại trừ . Mặt khác, các tập lệnh này tạo ra các lỗi JavaScript ngay khi nhấp vào một neo trống.

Theo tôi câu trả lời đúng là như thế này:

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

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

4

Sử dụng JQuery:

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


3

Câu trả lời đưa ra hoạt động nhưng vô hiệu hóa các liên kết đi. Bên dưới một phiên bản có thêm phần thưởng dễ dàng (swing) và tôn trọng các liên kết gửi đi.

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

stop()Tuy nhiên, +1 cho phần vụn url không hoạt động như mong đợi: nút Quay lại không mang lại, điều này là do khi phần vụn được đặt trong url sau khi hoạt ảnh hoàn tất. Sẽ tốt hơn nếu không có mẩu tin trong url, ví dụ như cách airbnb làm.
Eric

3

HTML

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

hoặc với URL đầy đủ tuyệt đối

<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

Các trình duyệt hiện đại ngày nay nhanh hơn một chút. Một setInterval có thể hoạt động. Chức năng này hoạt động tốt trong Chrome và Firefox hiện nay. (Một chút chậm trong safari, không bận tâm với 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

Có một cách css để làm điều này bằng cách sử dụng hành vi cuộn. Thêm thuộc tính sau.

    scroll-behavior: smooth;

Và đó là nó. Không yêu cầu 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: vui lòng kiểm tra tính tương thích của trình duyệt.


Tôi nên sử dụng hành vi cuộn nào: trơn tru;
CraZyDroiD

Trong trường hợp nghi ngờ, hãy thêm nó vào thẻ body @CraZyDroiD
Santosh

2

Thêm điều này:

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

bằng cách nào đó vô hiệu hóa bù dọc

top - 72

trong Firefox và IE, không có trong Chrome. Về cơ bản, trang cuộn trơn tru đến điểm mà nó sẽ dừng dựa trên phần bù, nhưng sau đó nhảy xuống nơi trang sẽ đi mà không có phần bù.

Nó không thêm băm vào cuối url, nhưng nhấn trở lại sẽ không đưa bạn trở lại đầu trang, nó chỉ xóa băm khỏi url và rời khỏi cửa sổ xem nơi nó nằm.

Dưới đây là toàn bộ js tôi đang sử dụng:

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

Giải pháp này cũng sẽ hoạt động cho các URL sau, mà không phá vỡ các liên kết neo đến các trang khác nhau.

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

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

Vân vân.

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

Tôi chưa thử nghiệm điều này trong tất cả các trình duyệt.


2

Điều này sẽ giúp dễ dàng cho phép jQuery phân biệt băm mục tiêu của bạn và biết khi nào và nơi dừng lại.

$('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

Mã đã được kiểm tra và xác minh

<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

Tôi đã làm điều này cho cả neo "/ xxxxx # asdf" và "#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

Đây là giải pháp tôi đã triển khai cho nhiều liên kết và neo, để cuộn mượt mà:

http://www.adriantomic.se/development/jquery-localscroll-tutorial/ nếu bạn có các liên kết điều hướng của mình được thiết lập trong div điều hướng và được khai báo với cấu trúc này:

<a href = "#destinationA">

và đích thẻ neo tương ứng của bạn như vậy:

<a id = "destinationA">

Sau đó chỉ cần tải cái này vào phần đầu của tài liệu:

    <!-- 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>

Cảm ơn @Adriantomic


1

Nếu bạn có một nút đơn giản trên trang để cuộn xuống div và muốn nút quay lại hoạt động bằng cách nhảy lên trên cùng, chỉ cần thêm mã này:

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

Điều này có thể được mở rộng để chuyển sang các div khác nhau, bằng cách đọc giá trị băm và cuộn như câu trả lời của Joseph Silbers.


1

Không bao giờ quên rằng hàm offset () đang cung cấp vị trí cho phần tử của bạn. Vì vậy, khi bạn cần cuộn phần tử của bạn so với cha mẹ của nó, bạn nên sử dụng phần tử này;

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

Điểm mấu chốt là lấy scrollTop của scroll-div và thêm nó vào scrollTop. Nếu bạn sẽ không làm chức năng vị trí đó () luôn cung cấp cho bạn các giá trị vị trí khác nhau.


1

Bạn có thể sử dụng window.scroll()với behavior: smoothtopthiết lập để đầu bù đắp thẻ neo của đảm bảo rằng thẻ neo sẽ được ở trên cùng của khung nhìn.

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

Bản giới thiệu:

Bạn chỉ có thể đặt thuộc tính CSS scroll-behaviorthành smooth(hầu hết các trình duyệt hiện đại hỗ trợ) mà không cần Javascript.


0

cảm ơn vì đã chia sẻ, Joseph Silber. Đây là giải pháp năm 2018 của bạn với tên ES6 với một thay đổi nhỏ để giữ hành vi tiêu chuẩn (cuộn lên trên cùng):

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

Yêu cầu jquery và hình động để gắn thẻ neo với tên được chỉ định thay vì id, trong khi thêm băm vào url trình duyệt. Cũng sửa một lỗi trong hầu hết các câu trả lời với jquery trong đó dấu # không được thêm tiền tố với dấu gạch chéo ngược. Thật không may, nút quay lại không điều hướng quay lại đúng các liên kết băm trước đó ...

$('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);
});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.