I dagens handledning kommer vi att använda en liten bit av CSS och JavaScript för att skapa en fin menyhuvudseffekt. Det är inte ett komplicerat slutresultat, men byggandet är ett utmärkt tillfälle att öva våra avancerade färdigheter.
Utan ytterligare intro, låt oss kolla vad vi ska bygga:
Vi börjar med en mycket grundläggande uppställning. en nav
element som innehåller menyn och en tom spänna
element:
Med markup redo, nästa vi specificerar några grundläggande stilar för de relaterade elementen:
.mynav ul display: flex; rättfärdiga innehåll: center; flex-wrap: wrap; lista-stil-typ: none; vaddering: 0; .mynav li: not (: last-child) margin-right: 20px; .mynav a display: block; fontstorlek: 20px; svart färg; text-dekoration: ingen; vaddering: 7px 15px; .target position: absolute; gränsbotten: 4px solid transparent; z-index: -1; transformera: translateX (-60px); .mynav a, .target transition: all .35s easy-in-out;
Observera att spänna
element (.mål
) Är helt placerad. Som vi ser på ett ögonblick använder vi JavaScript för att bestämma dess exakta position. Dessutom bör det visas Bakom menyn länkar, så vi ger det en negativ z-index
.
Låt oss nu fokusera på den obligatoriska JavaScript. Till att börja med riktar vi in de önskade elementen. Vi definierar också en uppsättning färger som vi använder senare.
const target = document.querySelector (". target"); const links = document.querySelectorAll (".mynav a"); const colors = ["deepskyblue", "orange", "firebrick", "gold", "magenta", "black", "darkblue");
Nästa lyssnar vi på klick
och mouseenter
händelser i menykopplingarna.
När klick
händelse händer, förhindrar vi att sidan laddas om. Naturligtvis fungerar detta i vårt fall eftersom alla länkar har en tom href
attribut. I ett verkligt projekt kommer dock alla menykopplingar sannolikt att öppna en annan sida.
Viktigast, så snart som mouseenter
händelsebränder, mouseenterFunc
återuppringningsfunktionen utförs:
för (låt jag = 0; i < links.length; i++) links[i].addEventListener("click", (e) => e.preventDefault ()); länkar [i] .addEventListener ("mouseenter", mouseenterFunc);
Kroppen av mouseenterFunc
funktionen ser så här ut:
funktion mouseenterFunc () for (låt jag = 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";
Inne i den här funktionen gör vi följande:
aktiva
klass till omedelbar förälder (li
) av mållänken.opacitet
från alla meny länkar, förutom den "aktiva" en.getBoundingClientRect
metod för att hämta storleken på den associerade länken och dess position i förhållande till visningsporten. gräns färg
egenskapen hos spänna
element. Kom ihåg att dess ursprungliga egenskapsvärde är inställt på transparent
.getBoundingClientRect
metod till motsvarande egenskaper hos spänna
element. Med andra ord, spänna
taggen ärverger storleken och läget för länken som svävar över.spänna
element. Detta beteende är bara viktigt första gången vi svävar över en länk. I detta fall går omvandlingen av elementet från transformera: translateX (-60px)
till transformera: ingen
. Det ger oss en snygg inskjutning.Det är viktigt att notera att koden ovan är exekverad varje gång vi svävar över en länk. Det körs därför när vi svävar över en "aktiv" länk också. För att förhindra detta beteende sätter vi in koden ovan i en om
påstående:
funktion mouseenterFunc () if (! this.parentNode.classList.contains ("active")) // kod här
Hittills ser vår demo ut enligt följande:
Så verkar allt som förväntat, eller hur? Jo det är inte sant, för om vi bläddra igenom sidan, eller ändra storlek på visningsporten och försök att välja en länk, blir det rörigt. Specifikt läget för spänna
elementet blir felaktigt.
Spela runt med demonstrationen för hela sidan (se till att du har lagt till tillräckligt med dummyinnehåll) för att se vad jag menar.
För att lösa det måste vi beräkna hur långt vi har bläddrat från toppen av fönstret och lägg till det här värdet till det aktuella topp
värdet av målelementet. På samma sätt borde vi beräkna hur långt dokumentet blivit rullat horisontellt (bara i fall). Det resulterande värdet läggs till strömmen vänster
värdet av målelementet.
Här är de två raderna av kod som vi uppdaterar:
const left = this.getBoundingClientRect (). left + window.pageXOffset; const top = this.getBoundingClientRect (). top + window.pageYOffset;
Tänk på att hela koden ovan är körd så snart webbläsaren behandlar DOM och hittar det aktuella skriptet. Återigen, för dina egna implementeringar och mönster kanske du vill köra den här koden när sidan laddas, eller något liknande. I ett sådant scenario måste du bädda in det inom en händelsehanterare (t.ex.. ladda
händelsehanterare).
Det sista vi måste göra är att se till att effekten fortfarande fungerar när vi ändrar storleken på webbläsarfönstret. För att uppnå detta lyssnar vi på ändra storlek
händelse och registrera resizeFunc
händelsehanterare.
window.addEventListener ("resize", resizeFunc);
Här är den här handlarens kropp:
funktion resizeFunc () const active = document.querySelector (". mynav li.active"); om (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';
Inne i funktionen ovan gör vi följande:
aktiva
. Om det är ett sådant element, som säger att vi redan har svängt över en länk.vänster
och topp
egenskaper för det "aktiva" objektet tillsammans med de relaterade fönsteregenskaperna och tilldela dem till spänna
element. Observera att vi bara hämtar värdena för de egenskaper som ändras under ändra storlek
händelse. Det betyder att man inte behöver räkna om bredden och höjden på menylänkarna.Demon fungerar bra i alla nya webbläsare. Om du stöter på några problem, låt mig veta i kommentarerna nedan. Också, som du kanske har märkt, använder vi Babel för att kompilera vår ES6-kod ner till ES5.
I denna handledning gick vi igenom processen för att skapa en enkel men ändå intressant menyhuver effekt.
Jag hoppas att du njöt av vad vi byggde här och tog inspiration för att utveckla ännu mer kraftfulla menyeffekter som den som visas (vid skrivandet) i Stripes webbplats.
Har du någonsin skapat något liknande? Om så är fallet, var noga med att dela med oss de utmaningar du ställt inför.