Płynne przewijanie po kliknięciu linku kontrolnego


487

Mam kilka hiperłączy na mojej stronie. Często zadawane pytania, które użytkownicy przeczytają, gdy odwiedzą moją sekcję pomocy.

Za pomocą łączy zakotwiczenia mogę przewinąć stronę w kierunku zakotwiczenia i poprowadzić tam użytkowników.

Czy istnieje sposób na płynne przewijanie?

Ale zauważ, że używa niestandardowej biblioteki JavaScript. Może jQuery oferuje coś takiego upieczonego?


Czy możesz przejrzeć najlepszą odpowiedź?
Jednowierszowe

Odpowiedzi:


1158

Aktualizacja kwietnia 2018 r .: Istnieje teraz natywny sposób :

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

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

Jest to obecnie obsługiwane tylko w najnowocześniejszych przeglądarkach.


W przypadku starszych przeglądarek możesz użyć tej techniki jQuery:

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

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

A oto skrzypce: http://jsfiddle.net/9SDLw/


Jeśli element docelowy nie ma identyfikatora i łączysz się z nim za pomocą name, użyj tego:

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

    return false;
});

Aby zwiększyć wydajność, należy buforować ten $('html, body')selektor, aby nie działał za każdym razem po kliknięciu kotwicy:

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

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

    return false;
});

Jeśli chcesz zaktualizować adres URL, zrób to w ramach animatewywołania zwrotnego:

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
Wydaje się, że usuwa to #rozszerzenie z adresu URL, przerywając funkcję powrotu. Czy jest na to jakiś sposób?
Fletch

2
@JosephSilber że nie powinno być scrollTop: $(this.hash).offset().topzamiast scrollTop: $(this.href).offset().top?
Gregory Pakosz

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

5
Twierdziłbym, że buforowanie html, bodyobiektu tutaj nie jest konieczne, uruchamianie selektora raz na kliknięcie nie jest aż tak duże.

2
Pierwsze rozwiązanie jest najlepsze i najnowocześniejsze, możesz użyć tego wypełnienia, aby wesprzeć to zachowanie w starych przeglądarkach dzięki temu wypełnieniu
Efe

166

Prawidłowa składnia to:

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

Uproszczenie : OSUSZANIE

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

Wyjaśnienie href*=\\#:

  • *oznacza, że ​​pasuje do tego, co zawiera #char. Dlatego pasują tylko do kotwic . Więcej informacji na temat tego znaczenia znajduje się tutaj
  • \\to dlatego, że #jest to specjalny znak w selektorze css, więc musimy przed tym uciec.

8
Musiałem zmienić, $('a')aby $('a[href*=#]')podawać tylko adresy URL kotwicy
okliv

2
@okliv To będzie za dużo służyć, na przykład link javascript <a href="javascript:$('#test').css('background-color', '#000')">Test</a>. Powinieneś raczej użyć, $('a[href^=#]')aby dopasować wszystkie adresy URL zaczynające się od znaku skrótu.
Martin Braun

3
również „#” jest znakiem specjalnym i należy go a[href^=\\#]
unikać w

3
Spowodowało to, że linki do kotwic na innych stronach przestały działać. Rozwiązany przez dodanie warunkowego płynnego przewijania if ($ ($ (this.hash) .selector) .length) {... }
Liren

1
Jak mogę to animować podczas pierwszej podróży na nową stronę? Na przykład klikając: website.com/newpage/#section2. Chciałbym, aby załadował stronę, a następnie przewinął w dół. Czy to jest możliwe?
Samyer

72

Nowa popularność w CSS3. Jest to o wiele łatwiejsze niż każda metoda wymieniona na tej stronie i nie wymaga Javascript. Wystarczy wpisać poniższy kod w css, a wszystkie nagłe linki prowadzą do lokalizacji na twojej stronie będą miały płynną animację przewijania.

html{scroll-behavior:smooth}

Następnie wszelkie linki wskazujące na div będą płynnie przesuwać się do tych sekcji.

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

Edycja: dla tych, którzy są zdezorientowani powyższym tagiem. Zasadniczo jest to link, który można kliknąć. Możesz mieć inny tag div gdzieś na swojej stronie internetowej, np

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

W związku z tym link będzie klikalny i przejdzie do dowolnego #section, w tym przypadku jest to nasz div, który nazwaliśmy sekcją.

BTW, spędziłem godziny próbując sprawić, żeby to zadziałało. Znalazłem rozwiązanie w jakiejś niejasnej sekcji komentarzy. To było błędne i nie działało w niektórych tagach. Nie działał w ciele. W końcu zadziałało, gdy wstawiłem go do html {} w pliku CSS.


4
Mogę być bardzo przydatny, ale mają one wady
Buzut

3
fajnie, ale bądź ostrożny, ponieważ w tej chwili nie jest obsługiwany przez Safari i oczywiście przez Explorera (03/2019)
Marco Romano

2
fajne rozwiązanie, tylko zasięg jest ograniczony do 74,8%. może w przyszłości
iepur1lla

1
To niesamowite. Wielkie dzięki.
Mikkel Fennefoss,

1
To będzie najbardziej odpowiednia odpowiedź w nadchodzących latach.
Nurul Huda

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

to działało idealnie dla mnie


1
„event.preventDefault ();” może zastąpić „return false;”
Andres Separ

Przykro mi to mówić, ale nie działa i nie wyświetla się szybko na stronie o nazwie anchor bez żadnej płynności.
Kamlesh

18

Dziwi mnie, że nikt nie opublikował natywnego rozwiązania, które zajmuje się także aktualizacją skrótu lokalizacji przeglądarki, aby pasował. Oto on:

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

Zobacz samouczek: http://www.javascriptkit.com/javatutors/scrolling-html-bookmark-javascript.shtml

W przypadku witryn z lepkimi nagłówkami scroll-padding-topmożna użyć CSS w celu zapewnienia przesunięcia.


1
Najbardziej podoba mi się ta odpowiedź. Jednak afais nie ma możliwości zapewnienia offsetu. Jak by to było potrzebne w przypadku stałego nagłówka.
bskool

Niestety, to samo słabe wsparcie dla właściwości przewijania CSS: developer.mozilla.org/en-US/docs/Web/CSS/…
Dmitry Nevzorov

15

Tylko CSS

html {
    scroll-behavior: smooth !important;
}

Wystarczy tylko dodać to. Teraz Twoje przewijanie wewnętrznych linków będzie płynne jak przepływ strumienia.

Uwaga : Wszystkie najnowsze przeglądarki ( Opera, Chrome, Firefoxetc) obsługuje tę funkcję.

w celu szczegółowego zrozumienia przeczytaj ten artykuł


1
miły! Dlaczego nie jest to akceptowana odpowiedź? nie potrzebujemy całego tego javascript!
Trevor de Koekkoek,

1
Działa świetnie, to powinna być zaakceptowana odpowiedź.
grób

Sprawdź obsługę przeglądarki tutaj
Ryan Zhou,

1
działa jak urok. nie potrzeba js
Navbro

To najlepsze rozwiązanie do płynnego przewijania NIGDY! Dzięki!
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;
      }
    }
  });
});

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


1
wydaje się, że działa to tylko w przypadku wewnętrznych linków zakotwiczenia strony, ale linki kotwiące z innych stron nie działają, na przykład website.com/about-us/#who-we-are
rainerbrunotte

5

Jest tu już wiele dobrych odpowiedzi - jednak wszyscy pomijają fakt, że należy wykluczyć puste kotwice . W przeciwnym razie skrypty generują błędy JavaScript, jak tylko kliknięta zostanie pusta kotwica.

Moim zdaniem poprawna odpowiedź jest następująca:

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

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

4

Za pomocą JQuery:

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


3

Podana odpowiedź działa, ale wyłącza linki wychodzące. Poniżej wersji z dodatkowym bonusem rozluźnienie (huśtawka) i szanuje linki wychodzące.

$(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 za to, stop()że okruch adresu URL nie działa zgodnie z oczekiwaniami: przycisk Wstecz nie przywraca, dzieje się tak, ponieważ gdy okruchy są ustawione w adresie URL po zakończeniu animacji. Lepiej jest bez okruchów w adresie URL, na przykład tak robi airbnb.
Eric,

3

HTML

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

lub z bezwzględnym pełnym adresem URL

<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

Nowoczesne przeglądarki są obecnie nieco szybsze. SetInterval może działać. Ta funkcja działa teraz dobrze w Chrome i Firefox. (Trochę powolny w safari, nie przeszkadzało to w 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

Istnieje sposób CSS na wykonanie tego przy użyciu zachowania przewijania. Dodaj następującą właściwość.

    scroll-behavior: smooth;

I to jest to. Nie wymaga 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: sprawdź kompatybilność przeglądarki.


do którego kontenera należy użyć przewijania: gładkie;
CraZyDroiD

W razie wątpliwości dodaj go do tagu body @CraZyDroiD
Santosh

2

Dodanie tego:

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

w jakiś sposób niweluje przesunięcie pionowe

top - 72

w Firefox i IE, ale nie w Chrome. Zasadniczo strona płynnie przewija się do punktu, w którym powinna się zatrzymać na podstawie przesunięcia, ale następnie przeskakuje w dół do miejsca, w którym strona poszedłaby bez przesunięcia.

Dodaje skrót na końcu adresu URL, ale naciśnięcie go wstecz nie zabierze Cię z powrotem na górę, po prostu usuwa skrót z adresu URL i pozostawia okno wyświetlania w miejscu, w którym się znajduje.

Oto pełny js, którego używam:

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

To rozwiązanie będzie działać również w przypadku następujących adresów URL, bez przerywania linków zakotwiczonych do różnych stron.

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

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

itp.

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

Nie przetestowałem tego jeszcze we wszystkich przeglądarkach.


2

Ułatwi to, że jQuery rozpoznaje twój docelowy skrót i wie, kiedy i gdzie zatrzymać.

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

Testowany i zweryfikowany kod

<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

Zrobiłem to zarówno dla kotwic href „/ xxxxx # asdf”, jak i „#asdf”

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

Oto rozwiązanie, które wdrożyłem dla wielu linków i kotwic, dla płynnego przewijania:

http://www.adriantomic.se/development/jquery-localscroll-tutorial/ jeśli masz linki nawigacyjne skonfigurowane w div nawigacji i zadeklarowane za pomocą tej struktury:

<a href = "#destinationA">

oraz odpowiednie miejsca docelowe tagów zakotwiczenia:

<a id = "destinationA">

Następnie po prostu załaduj to do nagłówka dokumentu:

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

Dzięki @Adriantomic


1

Jeśli masz prosty przycisk na stronie, aby przewinąć w dół do div i chcesz , aby przycisk Wstecz działał, przeskakując na górę, po prostu dodaj ten kod:

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

Można to rozszerzyć, aby przejść również do różnych div, czytając wartość skrótu i ​​przewijając jak Joseph Silbers odpowiedzi.


1

Nigdy nie zapominaj, że funkcja offset () podaje pozycję elementu do udokumentowania. Więc kiedy potrzebujesz przewinąć swój element względem jego rodzica, powinieneś go użyć;

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

Kluczowym punktem jest pobranie scrollTop z scroll-div i dodanie go do scrollTop. Jeśli tego nie zrobisz, funkcja position () zawsze daje różne wartości pozycji.


1

Można korzystać window.scroll()z behavior: smoothi topustawiony na przesunięcie szczytu, który zapewnia, że znacznik kotwica będzie na górze rzutni w tagu zakotwiczenia za.

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

Próbny:

Możesz po prostu ustawić właściwość CSS scroll-behaviorna smooth(którą obsługuje większość współczesnych przeglądarek), co eliminuje potrzebę Javascript.


0

dzięki za udostępnienie, Joseph Silber. Oto twoje rozwiązanie 2018 jako ES6 z niewielką zmianą, aby zachować standardowe zachowanie (przewiń do góry):

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

Wymaga jquery i animacji do zakotwiczenia tagu o określonej nazwie zamiast id, przy jednoczesnym dodawaniu skrótu do adresu URL przeglądarki. Naprawiono również błąd w większości odpowiedzi z jquery, w których znak # nie jest poprzedzony odwrotnym ukośnikiem. Niestety przycisk Wstecz nie nawiguje prawidłowo do poprzednich łączy mieszających ...

$('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);
});
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.