Reibungsloses Scrollen beim Klicken auf einen Ankerlink

487

Ich habe ein paar Hyperlinks auf meiner Seite. Eine FAQ, die Benutzer lesen, wenn sie meinen Hilfebereich besuchen.

Mithilfe von Ankerlinks kann ich die Seite zum Anker scrollen lassen und die Benutzer dorthin führen.

Gibt es eine Möglichkeit, das Scrollen reibungslos zu gestalten?

Beachten Sie jedoch, dass er eine benutzerdefinierte JavaScript-Bibliothek verwendet. Vielleicht bietet jQuery so etwas an?

Nur Bolivianer hier
quelle
Können Sie bitte die beste Antwort überprüfen? Reine CSS-Einzeilenlösung ist unter allen umfangreichen Abfragevorschlägen
3лександр Киричек

Antworten:

1159

Update April 2018: Es gibt jetzt eine native Möglichkeit, dies zu tun :

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

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

Dies wird derzeit nur in den modernsten Browsern unterstützt.


Für die Unterstützung älterer Browser können Sie diese jQuery-Technik verwenden:

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

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

Und hier ist die Geige: http://jsfiddle.net/9SDLw/


Wenn Ihr Zielelement keine ID hat und Sie über seine ID darauf verlinken name, verwenden Sie Folgendes :

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

    return false;
});

Um die Leistung zu steigern, sollten Sie diesen $('html, body')Selektor zwischenspeichern, damit er nicht jedes Mal ausgeführt wird, wenn auf einen Anker geklickt wird:

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

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

    return false;
});

Wenn Sie möchten, dass die URL aktualisiert wird, tun Sie dies innerhalb des animateRückrufs:

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;
});
Joseph Silber
quelle
10
Dies scheint die # Erweiterung aus der URL zu entfernen und die Back-Funktion zu unterbrechen. Gibt es einen Weg, dies zu umgehen?
Fletch
2
@ JosephSilber sollte das nicht scrollTop: $(this.hash).offset().topstatt sein scrollTop: $(this.href).offset().top?
Gregory Pakosz
4
@ CreateSean -scrollTop: $(href).offset().top - 72
Joseph Silber
5
Ich würde argumentieren, dass das Zwischenspeichern des html, bodyObjekts hier nicht erforderlich ist. Das Ausführen eines Selektors einmal pro Klick ist nicht wirklich so viel.
2
Die erste Lösung ist die beste und modernste. Sie können diese Polyfüllung verwenden, um dieses Verhalten in alten Browsern mit dieser Polyfüllung zu unterstützen
Efe
166

Die richtige Syntax lautet:

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

Vereinfachung : TROCKEN

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

Erklärung von href*=\\#:

  • *bedeutet, dass es mit dem übereinstimmt, was #char enthält . Also nur passende Anker . Weitere Informationen zur Bedeutung finden Sie hier
  • \\Das liegt daran, dass das #ein spezielles Zeichen in der CSS-Auswahl ist, also müssen wir ihm entkommen.
Andres Separ
quelle
8
Ich musste wechseln $('a'), $('a[href*=#]')um nur Anker-URLs zu bedienen
okliv
2
@okliv Dies wird zu viel dienen, zum Beispiel ein Javascript-Link wie <a href="javascript:$('#test').css('background-color', '#000')">Test</a>. Sie sollten lieber verwenden $('a[href^=#]'), um alle URLs abzugleichen, die mit einem Hash-Zeichen beginnen.
Martin Braun
3
Außerdem ist '#' ein Sonderzeichen und muss folgendermaßen a[href^=\\#]
maskiert werden
3
Dies führte dazu, dass Links zu Ankern auf anderen Seiten nicht mehr funktionierten. Gelöst durch Hinzufügen einer bedingten if ($ ($ (this.hash) .selector) .length) {... glatter Bildlauf. }
Liren
1
Wie kann ich dies animieren, wenn ich zum ersten Mal auf eine neue Seite gehe? Zum Beispiel durch Klicken auf: website.com/newpage/#section2. Ich möchte, dass die Seite geladen und dann nach unten gescrollt wird. Ist das möglich?
Samyer
72

Die neue Schärfe in CSS3. Dies ist viel einfacher als jede auf dieser Seite aufgeführte Methode und erfordert kein Javascript. Geben Sie einfach den folgenden Code in Ihr CSS ein und plötzlich zeigen Links, die auf Stellen auf Ihrer eigenen Seite verweisen, eine flüssige Bildlaufanimation.

html{scroll-behavior:smooth}

Danach gleiten alle Links, die auf ein Div zeigen, reibungslos zu diesen Abschnitten.

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

Bearbeiten: Für diejenigen, die über das oben genannte Tag verwirrt sind. Grundsätzlich ist es ein Link, der anklickbar ist. Sie können dann irgendwo auf Ihrer Webseite ein anderes div-Tag haben

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

In dieser Hinsicht ist der a-Link anklickbar und führt zu dem # Abschnitt, in diesem Fall ist es unser Div, den wir Abschnitt genannt haben.

Übrigens habe ich stundenlang versucht, dies zum Laufen zu bringen. Die Lösung wurde in einem obskuren Kommentarbereich gefunden. Es war fehlerhaft und funktionierte in einigen Tags nicht. Hat im Körper nicht funktioniert. Es hat endlich funktioniert, als ich es in HTML {} in der CSS-Datei abgelegt habe.

Cristian Reyes
quelle
4
Ich kann sehr praktisch sein, aber sie sind Nachteile
Buzut
3
nett, aber sei vorsichtig, denn im Moment wird es nicht von Safari und offensichtlich von Explorer (03/2019) unterstützt
Marco Romano
2
schöne lösung, nur die abdeckung ist mit 74,8% begrenzt. vielleicht in der Zukunft
iepur1lla
1
Das ist unglaublich. Vielen Dank.
Mikkel Fennefoss
1
Dies wird in den nächsten Jahren die relevanteste Antwort sein.
Nurul Huda
22
$('a[href*=#]').click(function(event){
    $('html, body').animate({
        scrollTop: $( $.attr(this, 'href') ).offset().top
    }, 500);
    event.preventDefault();
});

Das hat perfekt für mich funktioniert

Philipp Sander
quelle
1
"event.preventDefault ();" kann "return false" ersetzen;
Andres Separ
Tut mir leid zu sagen, aber es funktioniert nicht und wird auf der Seite mit dem Namen "Anker" schnell und ohne Glätte angezeigt.
Kamlesh
18

Ich bin überrascht, dass niemand eine native Lösung veröffentlicht hat, die sich auch darum kümmert, den Hash des Standortes des Browsers entsprechend zu aktualisieren. Hier ist es:

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

Siehe Tutorial: http://www.javascriptkit.com/javatutors/scrolling-html-bookmark-javascript.shtml

Für Sites mit klebrigen Headern kann scroll-padding-topCSS verwendet werden, um einen Offset bereitzustellen.

Coco Puffs
quelle
1
Diese Antwort gefällt mir am besten. Allerdings gibt es keine Möglichkeit, einen Offset bereitzustellen. Wie es bei einem festen Header nötig wäre.
bskool
Leider die gleiche schlechte Unterstützung wie für die CSS-Scroll-Verhaltenseigenschaft: developer.mozilla.org/en-US/docs/Web/CSS/…
Dmitry Nevzorov
15

Nur CSS

html {
    scroll-behavior: smooth !important;
}

Alles was Sie brauchen, um nur dies hinzuzufügen. Jetzt ist das Scrollverhalten Ihrer internen Links reibungslos wie ein Stream-Flow.

Hinweis : Alle aktuellen Browser ( Opera, Chrome, Firefoxusw.) diese Funktion unterstützt.

Lesen Sie diesen Artikel, um detaillierte Informationen zu erhalten

WasiF
quelle
1
nett! Warum ist dies nicht die akzeptierte Antwort? Wir brauchen nicht all das Javascript!
Trevor de Koekkoek
1
Es funktioniert super, dies sollte die akzeptierte Antwort sein.
Grab
Überprüfen Sie die Browser-Unterstützung hier
Ryan Zhou
1
Es funktioniert wie ein Zauber. keine Notwendigkeit für js
Navbro
Dies ist die beste Lösung für reibungsloses Scrollen! Vielen Dank!
yehanny
10

Ich schlage vor, diesen generischen Code zu erstellen:

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

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

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

return false;});

Sie können hier einen sehr guten Artikel sehen: jquery-effet-glatt-scroll-defilement-fluide

Sarah Bouyer
quelle
9
Dies ist nicht generisch, dies ist 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;
      }
    }
  });
});

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

KingRider
quelle
1
Dies scheint nur für
Ankerlinks
5

Hier gibt es bereits viele gute Antworten - allen fehlt jedoch die Tatsache, dass leere Anker ausgeschlossen werden müssen . Andernfalls erzeugen diese Skripte JavaScript-Fehler, sobald auf einen leeren Anker geklickt wird.

Meiner Meinung nach lautet die richtige Antwort wie folgt:

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

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

Verwenden von JQuery:

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

Die angegebene Antwort funktioniert, deaktiviert jedoch ausgehende Links. Unten eine Version mit einem zusätzlichen Bonus (Swing) und Respekt für ausgehende Links.

$(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;
        });
    });
});
Rick
quelle
+1 für die stop()URL-Krume funktioniert jedoch nicht wie erwartet: Die Schaltfläche Zurück bringt nicht zurück. Dies liegt daran, dass die Krume nach Abschluss der Animation in der URL festgelegt wird. Es ist besser ohne einen Krümel in der URL, zum Beispiel macht Airbnb das so.
Eric
3

HTML

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

oder Mit absoluter vollständiger 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;
            }
        }
    });
});
Jasmeet Singh
quelle
3

Moderne Browser sind heutzutage etwas schneller. Ein setInterval könnte funktionieren. Diese Funktion funktioniert heutzutage gut in Chrome und Firefox. (Etwas langsam in der Safari, hat sich nicht um den Internet Explorer gekümmert.)

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
    }
}
kleine Stiefel
quelle
3

Es gibt eine CSS-Methode, um dies mithilfe des Bildlaufverhaltens zu tun. Fügen Sie die folgende Eigenschaft hinzu.

    scroll-behavior: smooth;

Und das ist alles. Kein JS erforderlich.

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: Bitte überprüfen Sie die Browserkompatibilität.

Santosh
quelle
zu welchem ​​Container soll ich Scroll-Verhalten verwenden: glatt;
CraZyDroiD
Im Zweifelsfall fügen Sie es dem Body-Tag @CraZyDroiD
Santosh
2

Hinzufügen dieses:

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

hebt irgendwie den vertikalen Versatz auf

top - 72

in Firefox und IE, aber nicht in Chrome. Grundsätzlich scrollt die Seite reibungslos bis zu dem Punkt, an dem sie basierend auf dem Versatz anhalten soll, springt dann aber nach unten, wo die Seite ohne den Versatz hingehen würde.

Der Hash wird zwar am Ende der URL hinzugefügt, durch Zurückdrücken werden Sie jedoch nicht nach oben zurückgeführt. Der Hash wird lediglich aus der URL entfernt und das Anzeigefenster bleibt dort, wo er sich befindet.

Hier ist das vollständige js, das ich benutze:

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;
});
Reid
quelle
2

Diese Lösung funktioniert auch für die folgenden URLs, ohne dass Ankerlinks zu verschiedenen Seiten unterbrochen werden.

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

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

usw.

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

Ich habe dies noch nicht in allen Browsern getestet.

Midas
quelle
2

Auf diese Weise können Sie jQuery auf einfache Weise ermöglichen, Ihren Ziel-Hash zu erkennen und zu wissen, wann und wo Sie aufhören müssen.

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

    }



});
Abk
quelle
2

Getesteter und verifizierter Code

<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>
Atif Tariq
quelle
1

Ich habe dies sowohl für "/ xxxxx # asdf" als auch für "#asdf" href-Anker gemacht

$("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;
      }
    }
});
AndreDurao
quelle
1

Hier ist die Lösung, die ich für mehrere Links und Anker implementiert habe, für einen reibungslosen Bildlauf:

http://www.adriantomic.se/development/jquery-localscroll-tutorial/ Wenn Sie Ihre Navigationslinks in einem Navigationsbereich eingerichtet und mit dieser Struktur deklariert haben:

<a href = "#destinationA">

und Ihre entsprechenden Anker-Tag-Ziele wie folgt:

<a id = "destinationA">

Dann laden Sie dies einfach in den Kopf des Dokuments:

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

Vielen Dank an @Adriantomic

Collyg
quelle
1

Wenn Sie eine einfache Schaltfläche auf der Seite haben, mit der Sie zu einem Div scrollen können und die Zurück-Schaltfläche funktionieren soll, indem Sie nach oben springen, fügen Sie einfach diesen Code hinzu:

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

Dies könnte erweitert werden, um auch zu verschiedenen Divs zu springen, indem der Hash-Wert gelesen und wie bei Joseph Silbers Antwort gescrollt wird.

Niclas
quelle
1

Vergessen Sie niemals, dass die Funktion offset () die Position Ihres Elements zum Dokument angibt. Wenn Sie also Ihr Element relativ zu seinem übergeordneten Element scrollen müssen, sollten Sie dies verwenden.

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

Der entscheidende Punkt ist, scrollTop von scroll-div zu erhalten und es zu scrollTop hinzuzufügen. Wenn Sie diese position () -Funktion nicht ausführen, erhalten Sie immer unterschiedliche Positionswerte.

rotring05
quelle
1

Sie können window.scroll()mit behavior: smoothund topauf den versetzten oberen Rand des Ankertags setzen, um sicherzustellen, dass sich das Ankertag oben im Ansichtsfenster befindet.

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

Demo:

Sie können einfach die CSS-Eigenschaft scroll-behaviorauf smooth(die von den meisten modernen Browsern unterstützt wird) setzen, sodass kein Javascript erforderlich ist.

hev1
quelle
0

Danke fürs Teilen, Joseph Silber. Hier Ihre 2018-Lösung als ES6 mit einer geringfügigen Änderung, um das Standardverhalten beizubehalten (nach oben scrollen):

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"
    });
  });
});
Motine
quelle
0

Erfordert JQuery und Animationen, um das Tag mit dem angegebenen Namen anstelle der ID zu verankern, während der Hash zur Browser-URL hinzugefügt wird. Behebt auch einen Fehler in den meisten Antworten mit jquery, bei dem dem # -Zeichen kein Escape-Backslash vorangestellt ist. Die Zurück-Schaltfläche navigiert leider nicht richtig zurück zu vorherigen Hash-Links ...

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