Wie der Titel schon sagt! Hier ist eine Seitenleisten-Navigationsleiste, die…
- Verwendet "sticky" Positionierung. Sie bleibt sichtbar, solange es möglich ist, aber überlappt nicht den Header, Footer und macht niemals Links unzugänglich.
- Scrollt sanft zu den Abschnitten, die Sie anklicken.
- Aktiviert die aktuelle Navigation basierend auf der Scroll-Position (es ist eine Einzelseiten-Sache).
Siehe den Pen Sticky, Smooth, Active Nav von Chris Coyier (@chriscoyier) auf CodePen.
Sticky
Es ist einfach, position: sticky; top: 0; auf etwas anzuwenden. Damit es funktioniert, muss es sich jedoch innerhalb eines höheren Elternelements befinden. Die ungeordnete Liste (<ul>) innerhalb der Navigation (<nav>) funktioniert hier also bestens. Dank des CSS-Grid-Layouts ist die <nav> so hoch wie der <main>-Inhaltsbereich. Beachten Sie jedoch, dass wir für iOS auch position: -webkit-sticky; benötigen.
Ich habe auch eine magische Zahl für die vertikale Media Query hinzugefügt, damit sie nicht so haftet, dass Sie die unteren Navigationspunkte nicht erreichen können.
/* Only stick if you can fit */
@media (min-height: 300px) {
nav ul {
position: sticky;
top: 0;
}
}

Smooth
Bei meinem ersten Versuch dachte ich an JavaScript-basiertes Smooth Scrolling. Es ist heutzutage sogar nativ, ohne dass Frameworks benötigt werden. Sie können ein Element ansteuern und sanft dorthin scrollen.
document.querySelector('.hello').scrollIntoView({
behavior: 'smooth'
});
Das auf eine beliebige Anzahl von Navigationspunkten anzuwenden…
let mainNavLinks = document.querySelectorAll("nav ul li a");
mainNavLinks.forEach(link => {
link.addEventListener("click", event => {
event.preventDefault();
let target = document.querySelector(event.target.hash);
target.scrollIntoView({
behavior: "smooth",
block: "start"
});
});
});
Das wird sowohl in Chrome als auch in Firefox unterstützt, aber nicht in Edge oder Safari.
Dann fiel mir ein, dass CSS das kann! Es gibt eine Eigenschaft scroll-behavior, die Sie dem Dokument zuweisen können, um alles auf diese Weise scrollen zu lassen.
html {
scroll-behavior: smooth;
}
Da unsere Navigationslinks (<a>) Hash-/Sprung-/Ankerlinks sind, ist das buchstäblich alles, was wir brauchen. Vergessen Sie das JavaScript. Insbesondere da die Browserunterstützung für scroll-behavior dieselbe ist wie für die "Smooth"-Version von .scrollIntoView().
Active
Das ist etwas kniffliger, insbesondere weil dies eine Einzelseiten-Scrolling-App und keine einzelnen Seiten mit eigenen separaten Dokumenten sind. Wenn es sich um separate Dokumente handeln würde, würden wir irgendwo in der Navigation eine aktive Klasse ändern oder eine Klasse wie body.specific_page verwenden oder so etwas.
Stattdessen müssen wir die Scroll-Position der Seite betrachten, entscheiden, welcher Abschnitt sichtbar ist, und ihn entsprechend markieren. Es mag eine schicke IntersectionObserver-Methode geben, um das zu handhaben, aber ich konnte sie nicht ganz erfassen, also betrachte ich stattdessen alle relevanten Abschnitte, nehme einige Messungen und Berechnungen vor und entscheide auf diese Weise, ob der Link aktiv ist.
let mainNavLinks = document.querySelectorAll("nav ul li a");
let mainSections = document.querySelectorAll("main section");
let lastId;
let cur = [];
window.addEventListener("scroll", event => {
let fromTop = window.scrollY;
mainNavLinks.forEach(link => {
let section = document.querySelector(link.hash);
if (
section.offsetTop <= fromTop &&
section.offsetTop + section.offsetHeight > fromTop
) {
link.classList.add("current");
} else {
link.classList.remove("current");
}
});
});
Der Scroll-Handler dort sollte ein kleines Warnsymbol auslösen. Das ist die Art von Sache, die wahrscheinlich gedrosselt werden sollte, wenn Sie lodash verfügbar haben.
window.addEventListener("scroll", () => {
_.throttle(doThatStuff, 100);
});
Ich habe das hier nur nicht gemacht, um die Demo vom Abhängigkeiten zu befreien.
Oh! Und es funktioniert größtenteils gut auf Mobilgeräten (hier iOS).

Eine kostenlose Vorlage für JavaScript-Bibliotheks-Homepages
Ich habe all diese Dinge in dieser Vorlage verwendet, die Sie kostenlos nutzen können, für was auch immer.

Haben Sie in Erwägung gezogen, IntersectionObserver zu verwenden? (wirklich interessant aus Leistungssicht)
Ich habe es getestet, um eine einfache Kopie von RevealJS zu erstellen (mit CSS Scroll Snap Points und ScrollIntoView). Sehen Sie https://medium.com/@Nico3333fr/creating-a-light-revealjs-clone-with-css-scroll-snap-points-306dfba71652
Das wollte ich auch sagen! Ich benutze auch IntersectionObserver in meinem LazyLoad und es funktioniert einwandfrei! Das Lauschen auf das Fenster-Scroll-Ereignis ist aufwändig und könnte nur als Fallback verwendet werden.
Ich habe einen seltsamen Fehler (ich nenne ihn 'Fehler', weil ich ihn nicht verstehe) in Firefox 62dev gefunden.
verursacht, dass das Element
nav ulnicht sticky ist. Das Entfernen dieser Deklaration aus body behebt dieses Problem.Ah, ja, interessant! Ich bin mir auch nicht sicher, welcher Browser es richtig macht, aber es scheint nicht ganz notwendig zu sein, also habe ich es vorerst entfernt und im Code vermerkt.
Sicher! Das ist in den CSS-Kommentaren des Pens vermerkt. :)
Scheint, als sei das in Bootstrap schon vor langer Zeit mit Scrollspy und Affix gemacht worden.
Sie müssen möglicherweise einen harten Refresh versuchen. Es funktioniert bei mir in der neuesten stabilen Version (61.0.1).
Ich habe früher gedacht, dass die Verwendung von jQuery zu Spaghetti-Code führen würde.
Aber in den letzten Jahren, vom Wechsel von Angular zu Vue und dann zurück zu jQuery... habe ich erkannt, dass es der Mangel an Konventionen war, der zu Spaghetti-Code führte.
Ihrer Demonstration fehlt BEM und die Verwendung von verketteten Element-Selektoren fördert eine schlechte Angewohnheit bei aufstrebenden Entwicklern.
Stattdessen
Jetzt haben Sie die JavaScript-Verhaltensweise von CSS entkoppelt und das Ändern der Casenamen erfordert keine Änderung des JavaScripts.
Das Ändern der HTML-Struktur bricht das JavaScript nicht.
Es ist auch sehr offensichtlich, dass das Element Teil von etwas ist.
Dies sind alles Dinge, mit denen Sie als Frontend-Entwickler in einem großen Team umgehen müssen, wo Sie den Wartungsaufwand für andere Teammitglieder minimieren möchten.
Denken Sie daran, dass einfach und leicht zwei völlig unterschiedliche Ergebnisse sind.
Ich habe den Pen (schnell und schmutzig, er hat viele Fehler) modifiziert, um zu zeigen, wie es mit Intersection Observer gemacht werden könnte. Es funktioniert noch nicht richtig (im Vollbildmodus scheint es zu funktionieren, aber wenn Sie das Ansichtsfenster dehnen, tut es das nicht).
Bei größeren Browserfenstern kann ich nicht zum letzten Abschnitt navigieren.
Ein kleiner Trick, der helfen könnte, ist das Hinzufügen von
{passive: true}zumscroll-Ereignis-Listener, da Ihre Handler dasscroll-Ereignis niemals abbrechen werden. Es ist weitgehend unterstützt und hat Performance-Vorteile.Sie könnten eine einfache Throttle-Funktion verwenden, um den Zweck zu erfüllen, ohne ein Framework/eine Bibliothek.
Rufen Sie es dann auf mit
„“
window.addEventListener(“scroll”, throttled(() => {
…
}));
“`