Hoe een verschuivend onderstreepte zweefeffect met CSS en JavaScript te bouwen

In de tutorial van vandaag gaan we een beetje CSS en JavaScript gebruiken om een ​​chique menu-hovereffect te creëren. Het is geen gecompliceerd eindresultaat, maar het is een geweldige kans om onze front-endvaardigheden te oefenen.

Zonder verdere intro, laten we eens kijken wat we gaan bouwen:

De markup

We beginnen met een paar heel eenvoudige markeringen; een nav element dat het menu bevat en een leeg element span element:

 

De CSS

Nu de markup klaar is, specificeren we enkele basisstijlen voor de gerelateerde elementen:

.mynav ul display: flex; justify-content: center; flex-wrap: wrap; list-style-type: none; opvulling: 0;  .mynav li: not (: last-child) margin-right: 20px;  .mynav a display: block; lettertypegrootte: 20px; de kleur zwart; tekstdecoratie: geen; opvulling: 7px 15px;  .target positie: absoluut; border-bottom: 4px solid transparant; z-index: -1; transform: translateX (-60px);  .mynav a, .target transition: all .35s ease-in-out; 

Merk op dat de span element (.doelwit) Is absoluut gepositioneerd. Zoals we zo meteen zullen zien, zullen we JavaScript gebruiken om de exacte positie te bepalen. Bovendien zou het moeten verschijnen achter de menulinks, dus we geven het een negatief z-index.

JavaScript

Laten we op dit punt onze aandacht richten op het vereiste JavaScript. Om te beginnen richten we ons op de gewenste elementen. We definiëren ook een reeks kleuren die we later zullen gebruiken.

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

Evenementen

Vervolgens luisteren we naar de Klik en MouseEnter evenementen van de menulinks. 

Wanneer de Klik er gebeurt een gebeurtenis, we voorkomen dat de pagina opnieuw wordt geladen. Dit werkt in ons geval natuurlijk omdat alle links leeg zijn href attribuut. In een echt project zou echter elk van de menulinks waarschijnlijk een andere pagina openen.  

Belangrijker nog, zodra de MouseEnter evenementbranden, de mouseenterFunc callback-functie wordt uitgevoerd:

for (let i = 0; i < links.length; i++)  links[i].addEventListener("click", (e) => e.preventDefault ()); links [i] .addEventListener ("mouseenter", mouseenterFunc); 

mouseenterFunc

Het lichaam van de mouseenterFunc functie ziet er als volgt uit:

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

Binnen deze functie doen we het volgende:

  1. Voeg de toe actief klasse aan de directe ouder (li) van de doellink.
  2. Verlaag de ondoorzichtigheid van alle menulinks, behalve de "actieve".
  3. Gebruik de getBoundingClientRect methode om de grootte van de bijbehorende link op te halen en de positie ervan ten opzichte van de viewport. 
  4. Krijg een willekeurige kleur uit de bovengenoemde reeks en geef deze door als waarde voor de rand kleur eigendom van de span element. Onthoud dat de beginwaarde van de eigenschap is ingesteld op transparant.
  5. Wijs de waarden toe die zijn geëxtraheerd uit de getBoundingClientRect methode om de overeenkomstige eigenschappen van de span element. Met andere woorden, de span tag erft de grootte en de positie van de link waarop de muisaanwijzer staat.
  6. Stel de standaardtransformatie opnieuw in die is toegepast op de span element. Dit gedrag is alleen belangrijk als we de eerste keer over een link gaan. In dit geval gaat de transformatie van het element van transformeren: translateX (-60px) naar transformeren: geen. Dat geeft ons een leuk slide-in effect.

Indien actief

Het is belangrijk om te weten dat bovenstaande code telkens wordt uitgevoerd als we de muisaanwijzer over een link plaatsen. Het werkt dus ook als we over een "actieve" link zweven. Om dit gedrag te voorkomen, verpakken we de code hierboven in een als uitspraak:

function mouseenterFunc () if (! this.parentNode.classList.contains ("active")) // code here

Tot nu toe ziet onze demo er als volgt uit:

Bijna, maar niet helemaal

Dus alles lijkt te werken zoals verwacht, toch? Nou, dat is niet waar, want als we door de pagina scrollen of het formaat van de viewport wijzigen en vervolgens een link proberen te selecteren, worden de zaken rommelig. Specifiek, de positie van de span element wordt onjuist.

Speel rond met de demo van de volledige pagina (zorg ervoor dat je genoeg dummy-inhoud hebt toegevoegd) om te zien wat ik bedoel.

Om dit op te lossen, moeten we berekenen tot hoever we hebben gescrold vanaf de bovenkant van het venster en deze waarde toevoegen aan de huidige top waarde van het doelelement. Op dezelfde manier moeten we berekenen hoe ver het document horizontaal is geschoven (voor het geval dat). De resulterende waarde wordt toegevoegd aan de stroom links waarde van het doelelement.

Dit zijn de twee coderegels die we updaten:

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

Houd er rekening mee dat alle bovenstaande code wordt uitgevoerd zodra de browser de DOM verwerkt en het relevante script vindt. Nogmaals, voor uw eigen implementaties en ontwerpen wilt u misschien deze code uitvoeren wanneer de pagina wordt geladen, of iets dergelijks. In een dergelijk scenario moet u het insluiten in een gebeurtenishandler (bijv. laden event handler).

Uitkijk postje

Het laatste wat we moeten doen is zorgen dat het effect nog steeds werkt als we het formaat van het browservenster aanpassen. Om dit te bereiken, luisteren we naar de verkleinen evenement en registreer het resizeFunc gebeurtenishandler.

window.addEventListener ("resize", resizeFunc);

Dit is het lichaam van deze handler:

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

Binnen de bovenstaande functie doen we het volgende:

  1. Controleer of er een menulijstitem bij de klasse van staat actief. Als er is een dergelijk element dat beweert dat we al boven een link zweven.
  2.  Pak het nieuwe links en top eigenschappen van het "actieve" item samen met de gerelateerde venstereigenschappen en wijs ze toe aan de span element. Merk op dat we de waarden alleen ophalen voor de eigenschappen die tijdens de verkleinen evenement. Dat betekent dat het niet nodig is om de breedte en hoogte van de menulinks te herberekenen.

Browserondersteuning

De demo werkt goed in alle recente browsers. Als je echter problemen tegenkomt, laat het me weten in de reacties hieronder. Zoals je misschien hebt gemerkt, gebruiken we Babel om onze ES6-code te compileren naar ES5.

Conclusie

In deze zelfstudie hebben we het proces doorlopen van het maken van een eenvoudig, maar toch interessant menu-hovereffect.

Ik hoop dat je genoten hebt van wat we hier hebben gebouwd en heb inspiratie opgedaan voor het ontwikkelen van nog krachtiger menu-effecten zoals die verschijnen (op het moment van schrijven) in de Stripe-site.

Heb je ooit iets soortgelijks gemaakt? Als dat het geval is, deel dan de uitdagingen die je tegenkwam met ons.