Anleitung zur Erstellung einer Unterlinie mit CSS und JavaScript, die durch hovern zwischen Menüpunkte wechselt
German (Deutsch) translation by Hannes Dermutz (you can also view the original English article)
Im heutigen Tutorial verwenden wir etwas CSS und JavaScript um daraus einen stylischen Hover-Effekt im Menü zu erstellen. Es entsteht kein kompliziertes Endresultat und bietet zusätzlich eine sehr gute Möglichkeit unsere Front-End Fähigkeiten zu verbessern.
Ohne weiterer Einleitung, sehen wir uns an was wir bauen werden:
Das HTML
Wir starten mit sehr einfachen markup; einem nav
Element welches ein Menü und ein leeres span
Element beinhaltet.
<nav class="mynav"> <ul> <li> <a href="">Home</a> </li> <li> <a href="">About</a> </li> <li> <a href="">Company</a> </li> <li> <a href="">Work</a> </li> <li> <a href="">Clients</a> </li> <li> <a href="">Contact</a> </li> </ul> </nav> <span class="target"></span>
Das CSS
Mit dem betriebsbereiten Markup, spezifizieren wir als nächstes einfache Styles für die zugehörigen Elemente.
.mynav ul { display: flex; justify-content: center; flex-wrap: wrap; list-style-type: none; padding: 0; } .mynav li:not(:last-child) { margin-right: 20px; } .mynav a { display: block; font-size: 20px; color: black; text-decoration: none; padding: 7px 15px; } .target { position: absolute; border-bottom: 4px solid transparent; z-index: -1; transform: translateX(-60px); } .mynav a, .target { transition: all .35s ease-in-out; }
Beachte bitte, dass das span
Element (.target
) absolut positioniert ist. Wie wir in Kürze sehen werden, werden wir JavaScript verwenden um die exakte position festzulegen. Zusätzlich soll es hinter den Menü Links aufscheinen, dazu geben wir dem Element einen negativen Z-Index
.
Das JavaScript
In diesem Punkt konzentrieren wir uns auf das benötigte JavaScript. Zum Anfang peilen wir die gewünschten Elemente an. Wir definieren zusätzlich noch ein Array von verschiedenen Farben, das wir später verwenden werden.
const target = document.querySelector(".target"); const links = document.querySelectorAll(".mynav a"); const colors = ["deepskyblue", "orange", "firebrick", "gold", "magenta", "black", "darkblue"];
Events
Als nächstes hören wir auf einen click
und mouseenter
Events der Menü Links.
Wenn das click
Event eintrifft, verhindern wir das neu Laden der Seite. Natürlich funktioniert dies in unserem Fall weil alle Links ein leeres href
Attribut besitzen. Jedoch in einem realen Projekt würden die Menü Links verschiedene Seiten öffnen.
Am wichtigsten ist, dass sobald das mouseenter
Event eintritt, die mouseenterFunc
Callback Funktion ausgeführt wird.
for (let i = 0; i < links.length; i++) { links[i].addEventListener("click", (e) => e.preventDefault()); links[i].addEventListener("mouseenter", mouseenterFunc); }
mouseenterFunc
Der Hauptteil der mouseenterFunc
Funktion sieht folgendermaßen aus:
function mouseenterFunc() { for (let i = 0; i < links.length; i++) { if (links[i].parentNode.classList.contains("active")) { links[i].parentNode.classList.remove("active"); } links[i].style.opacity = "0.25"; } this.parentNode.classList.add("active"); this.style.opacity = "1"; const width = this.getBoundingClientRect().width; const height = this.getBoundingClientRect().height; const left = this.getBoundingClientRect().left; const top = this.getBoundingClientRect().top; const color = colors[Math.floor(Math.random() * colors.length)]; target.style.width = `${width}px`; target.style.height = `${height}px`; target.style.left = `${left}px`; target.style.top = `${top}px`; target.style.borderColor = color; target.style.transform = "none"; }
Innerhalb der Funktion machen wir folgendes:
- Hinzufügen der
active
Klasse zum direkten Elternteil (li
) des Ziellinks. - Senken der
opacity
von allen Menü Links, abgesehen von dem "aktiven" Link. - Um die Größe des verbundenen Links und deren Position des jeweiligen Ansichtsfensters zu erhalten, verwenden wir die
getBoundingClientRect
Funktion. - Erhalten einer zufälligen Farbe vom vorhin erwähnten Array und weitergeben als Wert zur
border-color
Eigenschaft desspan
Elements. Vergiss nicht, der Anfangseigenschaftswert ist auftransparent
gesetzt. - Zuordnen der Werte, die von der
getBoundingClientRect
Methode extrahiert wurden, zu den dazugehörigen Eigenschaften desspan
Elements. In anderen Worten, derspan
Tag erbt die Größe und Position des Links über dem gehovert wird. - Zurücksetzen der Standardtransformation bezogen auf das
span
Element. Dieses Verhalten ist nur beim ersten Hover über eines Links wichtig. In diesem Fall, die Transformation des Elements geht vontransform: translateX(-60px)
zutransform: none
. Dies gibt uns einen stylischen Slide-In Effekt.
Wenn Aktiv
Es ist wichtig zu wissen, dass der oben angeführte Code jedes Mal ausgeführt wird, wenn wir über einen Link hovern. Es wird auch ausgeführt, wenn wir über einen "aktiven" Link hovern. Um dieses Verhalten zu verhindern, verpacken wir den obigen Code innerhalb einer if
Anweisung.
function mouseenterFunc() { if (!this.parentNode.classList.contains("active")) { // code here } }
Bisher sieht unsere Demo folgendermaßen aus:
Beinahe, aber nicht Ganz
Alles sieht so aus als würde es korrekt funktionieren, stimmts? Nun ja, dies ist nicht korrekt, denn wenn wir durch unsere Seite scrollen oder das Ansichtsfenster verändern und dann versuchen einen Link auszuwählen, entsteht ein Durcheinander.
Spiel mit der kompletten Seiten Demo herum um zu sehen was ich meine.
Um dies zu lösen, müssen wir herausfinden wie weit wir vom Anfang der Seite heruntergescrollt haben und diesen Wert zu unseren aktuellen top
Wert des Zielelements hinzufügen. Gleichfalls sollten wir kalkulieren, wie weit das Dokument horizontal gescrollt wurde (nur zur Sicherheit). Der resultierende Wert wird zum momentanen left
Wert des Zielelements hinzugefügt.
Hier sind auch zwei Zeilen Code die wir aktualisieren müssen:
const left = this.getBoundingClientRect().left + window.pageXOffset; const top = this.getBoundingClientRect().top + window.pageYOffset;
Bitte behalte im Gewissen, dass all der oben angeführte Code direkt ausgeführt wird, nachdem der Browser das DOM verarbeitet und das relevante Skript gefunden hat. Wiederum, für deine eigenen Implementierungen und Designs kannst du mit diesem Code ausführen wenn die Seite geladen wird, oder so ähnlich. In manchen Szenarien kann es passieren, dass du den Code innerhalb eines Event Handlers (z.B. load
Event Handler) einbetten musst.
Ansichtsfenster
Zuletzt müssen wir garantieren können, dass der Effekt immer noch funktioniert, wenn wir das Browser Fenster verändern. Um dies zu vollenden, müssen wir auf ein resize
Event hören und einen resizeFunc
Event Handler registrieren.
window.addEventListener("resize", resizeFunc);
Hier ist das Gerüst dieses Handlers:
function resizeFunc() { const active = document.querySelector(".mynav li.active"); if (active) { const left = active.getBoundingClientRect().left + window.pageXOffset; const top = active.getBoundingClientRect().top + window.pageYOffset; target.style.left = `${left}px`; target.style.top = `${top}px`; } }
Innerhalb der obigen Funktion, machen wir folgendes:
- Checken falls ein Menü Listen Item mit der Klasse
active
existiert. Wenn sich dort ein Element befindet, heißt das, dass wir schon über einen Link gehovert haben. - Erhalten der neuen
left
undtop
Eigenschaften des "aktiven" Items mit dessen verbundenen Fenster Eigenschaften und diese zumspan
Element zuordnen. Beachte, dass wir die Werte nur dann für die Eigenschaften die während desresize
Events geändert wurden bekommen. Dies heißt, dass wir keine Neuberechnung der Breite und Höhe des Menü Links benötigen.
Browser Unterstützung
Die Demo funktioniert in allen neuen Browsers. Wenn du irgendwelche Probleme begegnen solltest, lass es mich in den Kommentaren wissen. Wie du auch möglicherweise schon bemerkt hast, verwenden wir Babel um unseren ES6 Code auf ES5 zu kompilieren.
Zusammenfassung
In dieser schnellen Anleitung haben wir uns durch den Prozess der Erstellung eines einfachen und jetzt interessanten Menü Hover Effects durchgearbeitet.
Ich hoffe euch hat das Erstellte gefallen und gab euch eine Inspiration zur weiteren Entwicklung von noch stärkeren Menü-Effekten wie das hier aufscheinende (während des Schreibens) auf der Stripe Seite.
Habt ihr schon etwas ähnliches kreiert? Wenn ja, teilt uns die Herausforderungen mit die ihr bewältigen musstet.