So erstellen Sie einen verschiebbaren Unterstrich-Hover-Effekt mit CSS und JavaScript

Im heutigen Tutorial verwenden wir ein wenig CSS und JavaScript, um einen ausgefallenen Menü-Hover-Effekt zu erzeugen. Es ist kein kompliziertes Endergebnis, aber das Bauen ist eine großartige Gelegenheit, unsere Frontend-Fähigkeiten zu üben.

Lassen Sie uns ohne weitere Einführung prüfen, was wir bauen werden:

Der Markup

Wir beginnen mit einem sehr einfachen Markup. ein nav Element, das das Menü und ein leeres enthält Spanne Element:

 

Das CSS

Wenn das Markup fertig ist, geben wir als Nächstes einige grundlegende Stile für die zugehörigen Elemente an:

.mynav ul display: flex; Inhalt rechtfertigen: Mitte; Flex-Wrap: Wrap; Typ des Listentyps: keine; Polsterung: 0;  .mynav li: nicht (: letztes Kind) margin-right: 20px;  .mynav a display: block; Schriftgröße: 20px; Farbe schwarz; Textdekoration: keine; Polsterung: 7px 15px;  .target position: absolut; Rand unten: 4px durchsichtig transparent; z-Index: -1; transform: translateX (-60px);  .mynav a, .target Übergang: alle .35s-Inaktivität; 

Beachten Sie, dass die Spanne Element (.Ziel) Ist absolut positioniert. Wie wir gleich sehen werden, verwenden wir JavaScript, um die genaue Position zu bestimmen. Außerdem sollte es erscheinen hinter Das Menü verlinkt, also geben wir es negativ z-index.

Das JavaScript

An dieser Stelle konzentrieren wir uns auf das erforderliche JavaScript. Zunächst zielen wir auf die gewünschten Elemente. Wir definieren auch eine Reihe von Farben, die wir später verwenden werden.

const target = document.querySelector (". target"); const links = document.querySelectorAll (". mynav a"); const colors = ["deepskyblue", "orange", "firebrick", "gold", "magenta", "schwarz", "darkblue"];

Veranstaltungen

Als nächstes hören wir auf die klicken und Mouseenter Ereignisse der Menülinks. 

Wenn der klicken Wenn ein Ereignis auftritt, wird verhindert, dass die Seite erneut geladen wird. Das funktioniert natürlich in unserem Fall, da alle Links leer sind href Attribut. In einem realen Projekt würde jedoch wahrscheinlich jeder der Menü-Links eine andere Seite öffnen.  

Am wichtigsten ist, sobald die Mouseenter Ereignis brennt, die mouseenterFunc Callback-Funktion wird ausgeführt:

für (sei i = 0; i < links.length; i++)  links[i].addEventListener("click", (e) => e.preventDefault ()); links [i] .addEventListener ("mouseenter", mouseenterFunc); 

mouseenterFunc

Der Körper der mouseenterFunc Funktion sieht so aus:

function mouseenterFunc () for (sei 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 = '$widthpx'; target.style.height = '$heightpx'; target.style.left = '$leftpx'; target.style.top = '$toppx'; target.style.borderColor = color; target.style.transform = "none"; 

Innerhalb dieser Funktion führen wir Folgendes aus:

  1. Ergänzen Sie die aktiv Klasse zum unmittelbaren Elternteil (li) des Ziellinks.
  2. Verringern Sie die Opazität von allen Menü-Links außer dem "aktiven".
  3. Verwenden Sie die getBoundingClientRect Methode, um die Größe des verknüpften Links und seine Position relativ zum Viewport abzurufen. 
  4. Holen Sie sich eine zufällige Farbe aus dem oben genannten Array und übergeben Sie diese als Wert an das Randfarbe Eigentum der Spanne Element. Denken Sie daran, dass der anfängliche Eigenschaftswert auf festgelegt ist transparent.
  5. Weisen Sie die aus dem extrahierten Werte zu getBoundingClientRect Methode auf die entsprechenden Eigenschaften des Spanne Element. Mit anderen Worten, die Spanne Das Tag erbt die Größe und die Position des Links, über den sich der Mauszeiger bewegt.
  6. Setzen Sie die auf die angewendete Standardumwandlung zurück Spanne Element. Dieses Verhalten ist nur wichtig, wenn wir zum ersten Mal über einen Link fahren. In diesem Fall geht die Transformation des Elements von aus transform: translateX (-60px) zu verwandeln: keine. Das gibt uns einen schönen Slide-In-Effekt.

Wenn aktiv

Es ist wichtig zu wissen, dass der obige Code jedes Mal ausgeführt wird, wenn wir über einen Link fahren. Es läuft also, wenn wir auch über eine "aktive" Verbindung fahren. Um dieses Verhalten zu verhindern, wickeln wir den obigen Code in ein ob Aussage:

function mouseenterFunc () if (! this.parentNode.classList.contains ("active")) // Code hier

Bisher sieht unsere Demo folgendermaßen aus:

Fast, aber nicht ganz

Also scheint alles wie erwartet zu funktionieren, richtig? Nun, das stimmt nicht, denn wenn wir durch die Seite blättern oder die Größe des Ansichtsfensters ändern und dann versuchen, einen Link auszuwählen, werden die Dinge unordentlich. Insbesondere die Position der Spanne Element wird falsch.

Spielen Sie mit der ganzseitigen Demo (stellen Sie sicher, dass Sie genügend Dummy-Inhalte hinzugefügt haben), um zu sehen, was ich meine.

Um das Problem zu lösen, müssen wir berechnen, wie weit wir vom oberen Rand des Fensters gescrollt wurden, und diesen Wert zum aktuellen Wert hinzufügen oben Wert des Zielelements. Auf dieselbe Weise sollten wir berechnen, wie weit das Dokument horizontal verschoben wurde (nur für den Fall). Der resultierende Wert wird zum Strom addiert links Wert des Zielelements.

Hier sind die zwei Codezeilen, die wir aktualisieren:

const left = this.getBoundingClientRect (). left + window.pageXOffset; const top = this.getBoundingClientRect (). top + window.pageYOffset;

Beachten Sie, dass der gesamte Code ausgeführt wird, sobald der Browser das DOM verarbeitet und das entsprechende Skript findet. Für Ihre eigenen Implementierungen und Designs möchten Sie möglicherweise diesen Code ausführen, wenn die Seite geladen wird, oder ähnliches. In einem solchen Szenario müssen Sie es in einen Event-Handler einbetten (z. Belastung Eventhandler).

Sichtfenster

Das letzte, was wir tun müssen, ist sicherzustellen, dass der Effekt immer noch funktioniert, wenn wir die Größe des Browser-Fensters ändern. Um dies zu erreichen, hören wir auf die Größe ändern Veranstaltung und Registrierung der resizeFunc Eventhandler.

window.addEventListener ("resize", resizeFunc);

Hier ist der Körper dieses Handlers:

function resizeFunc () const active = document.querySelector (". mynav li.active"); if (aktiv) const left = active.getBoundingClientRect (). left + window.pageXOffset; const top = active.getBoundingClientRect (). top + window.pageYOffset; target.style.left = '$ left px'; target.style.top = '$ top px'; 

In der obigen Funktion führen wir Folgendes aus:

  1. Prüfen Sie, ob es einen Menüeintrag mit der Klasse von gibt aktiv. Wenn dort ist ein solches Element, das besagt, dass wir bereits über einen Link schwebten.
  2.  Holen Sie sich das Neue links und oben Eigenschaften des „aktiven“ Elements zusammen mit den zugehörigen Fenstereigenschaften und weisen Sie diese dem zu Spanne Element. Beachten Sie, dass wir die Werte nur für die Eigenschaften abrufen, die sich während der Änderung ändern Größe ändern Veranstaltung. Das bedeutet, dass Sie die Breite und Höhe der Menü-Links nicht neu berechnen müssen.

Browser-Unterstützung

Die Demo funktioniert gut in allen aktuellen Browsern. Wenn Sie jedoch auf Probleme stoßen, teilen Sie mir dies in den Kommentaren mit. Wie Sie möglicherweise bereits bemerkt haben, verwenden wir Babel, um unseren ES6-Code auf ES5 herunterzukompilieren.

Fazit

In diesem Tutorial haben wir einen einfachen, aber interessanten Menü-Hover-Effekt erstellt.

Ich hoffe, Ihnen hat das, was wir hier gebaut haben, Spaß gemacht, und Sie haben sich inspirieren lassen, noch leistungsfähigere Menüeffekte zu entwickeln, wie die, die (zum Zeitpunkt des Schreibens) auf der Stripe-Site erscheint.

Hast du schon einmal etwas Ähnliches geschaffen? Wenn ja, teilen Sie uns mit, welche Herausforderungen Sie hatten.