Cum se construiește un efect de deplasare subliniat cu CSS și JavaScript

În tutorialul din ziua de azi, vom folosi un pic de CSS și JavaScript pentru a crea un efect de hover al fanilor. Nu este un rezultat final complicat, dar construirea acestuia va fi o mare oportunitate de a ne practica abilitățile de capăt.

Fără altă intro, hai să vedem ce vom construi:

Marcajul

Începem cu un marcaj de bază; A nav element care conține meniul și un spațiu gol deschidere element:

 

CSS

Cu pregătirea marcajului, vom specifica câteva stiluri de bază pentru elementele legate:

.mynav ul afișare: flex; justify-content: centru; flex-wrap: folie; listă-tip: none; umplutura: 0;  .mynav li: nu (: ultimul-copil) margin-right: 20px;  .mynav a display: bloc; font-size: 20px; culoarea neagra; text-decoration: nici unul; padding: 7px 15px;  .target poziție: absolută; margine de fund: 4px solid transparent; indicele z: -1; transformă: translateX (-60px);  .mynav a, .target tranziție: toate .35s ușurință în afară; 

Observați că deschidere element (.ţintă) Este absolut poziționată. După cum vom vedea într-un moment, vom folosi JavaScript pentru a determina poziția exactă. În plus, ar trebui să apară in spate link-urile de meniu, deci îi dăm un negativ z-index.

JavaScript

În acest moment, hai să ne concentrăm atenția asupra JavaScript-ului necesar. În primul rând, direcționăm elementele dorite. De asemenea, definim o serie de culori pe care le vom folosi ulterior.

const țintă = document.querySelector (". target"); const link = document.querySelectorAll (".minav a"); const culori = ["deepskyblue", "portocaliu", "firebrick", "aur", "magenta", "negru", "închis");

Evenimente

Apoi ascultăm pentru clic și mouseenter evenimentele din legăturile de meniu. 

Cand clic evenimentul se întâmplă, împiedicăm reîncărcarea paginii. Desigur, acest lucru funcționează în cazul nostru, deoarece toate legăturile au un gol href atribut. Într-un proiect real, însă, fiecare dintre legăturile de meniu ar deschide probabil o pagină diferită.  

Cel mai important, de îndată ce mouseenter incendii eveniment, mouseenterFunc funcția de apel invers este executată:

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

mouseenterFunc

Corpul mouseenterFunc funcționează astfel:

funcția mousecenterFunc () pentru (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"; 

În cadrul acestei funcții, facem următoarele:

  1. Adaugă activ clasa părintelui imediat (Li) a legăturii țintă.
  2. Micșorați opacitate din toate link-urile de meniu, în afară de cea "activă".
  3. Folosește getBoundingClientRect pentru a recupera mărimea legăturii asociate și poziția acesteia față de portul de vizualizare. 
  4. Obțineți o culoare aleatorie din matricea menționată mai sus și transferați-o ca valoare către border-color proprietate a deschidere element. Rețineți că valoarea inițială a proprietății este setată la transparent.
  5. Atribuiți valorile extrase din getBoundingClientRect metodă pentru proprietățile corespunzătoare ale deschidere element. Cu alte cuvinte, deschidere eticheta moștenește mărimea și poziția legăturii care este plină.
  6. Resetați transformarea implicită aplicată la deschidere element. Acest comportament este important doar pentru prima dată când plasăm cursorul peste o legătură. În acest caz, transformarea elementului trece de la transformare: translateX (-60px) la transforma: nici unul. Asta ne dă un efect frumos de alunecare.

Dacă este Activ

Este important să rețineți că codul de mai sus este executat de fiecare dată când plasăm cursorul peste un link. Prin urmare, rulează atunci când vom trece peste un link "activ", de asemenea. Pentru a preveni acest comportament, înfășurăm codul de mai sus într-un dacă afirmație:

funcția mousecenterFunc () if (! this.parentNode.classList.contains ("active")) // cod aici

Până acum, demo-ul nostru arată după cum urmează:

Aproape, dar nu destul

Deci, totul pare să funcționeze așa cum era de așteptat, nu? Ei bine, nu este adevărat, pentru că dacă parcurgem pagina sau redimensionăm fereastra de vizualizare și apoi încercăm să selectăm o legătură, lucrurile se încurcă. În mod specific, poziția deschidere elementul devine incorect.

Redați-vă cu demonstrația completă a paginii (asigurați-vă că ați adăugat conținut suficient de inactiv) pentru a vedea ce vreau să spun.

Pentru ao rezolva, trebuie să calculați cât de departe am derulat din partea superioară a ferestrei și adăugați această valoare la curent top valoarea elementului țintă. În același mod, ar trebui să calculați cât de departe documentul a fost derulat orizontal (doar în caz). Valoarea rezultată este adăugată curentului stânga valoarea elementului țintă.

Iată cele două linii de cod pe care le actualizăm:

const stânga = this.getBoundingClientRect () left + window.pageXOffset; const top = this.getBoundingClientRect () top + fereastră.pageYOffset;

Rețineți că tot codul de mai sus este executat imediat ce browserul procesează DOM și găsește scriptul relevant. Din nou, pentru propriile implementări și desene sau modele ar putea să doriți să executați acest cod atunci când pagina se încarcă sau ceva de genul ăsta. Într-un astfel de scenariu, va trebui să îl încorporați într-un handler de evenimente (de ex. sarcină organizatorul evenimentului).

viewport

Ultimul lucru pe care trebuie să-l facem este să ne asigurăm că efectul va continua să funcționeze pe măsură ce redimensionăm fereastra browserului. Pentru a realiza acest lucru, ascultăm pentru redimensiona eveniment și înregistrarea resizeFunc organizatorul evenimentului.

window.addEventListener ("redimensionare", resizeFunc);

Iată corpul acestui manipulator:

funcția resizeFunc () const activ = document.querySelector (".mynav li.active"); dacă (activ) const stânga = activ.getBoundingClientRect () left + window.pageXOffset; const top = activ.getBoundingClientRect () top + fereastră.pageYOffset; target.style.left = '$ left px'; target.style.top = '$ top px'; 

În interiorul funcției de mai sus, facem următoarele:

  1. Verificați dacă există un element din lista de meniuri cu clasa de activ. În cazul în care există este un astfel de element, care afirmă că am mai trecut pe o legătură.
  2.  Obțineți noul stânga și top proprietățile elementului "activ", împreună cu proprietățile ferestrei asociate și le atribuie acestora deschidere element. Rețineți că vom prelua valorile numai pentru proprietățile care se modifică în timpul redimensiona eveniment. Aceasta înseamnă că nu este nevoie să recalculați lățimea și înălțimea legăturilor de meniu.

Suport pentru browser

Demo-ul funcționează bine în toate browserele recente. Dacă totuși întâmpinați probleme, anunțați-ne în comentariile de mai jos. De asemenea, după cum ați observat, folosim Babel pentru a ne compila codul ES6 până la ES5.

Concluzie

În acest tutorial am trecut prin procesul de creare a unui efect simplu, dar interesant, de hovering în meniu.

Sper că v-ați bucurat de ceea ce am construit aici și am inspirat dezvoltarea unor efecte de meniu chiar mai puternice, cum ar fi cea care apare (în momentul redactării) în site-ul Stripe.

Ai creat vreodată ceva similar? Dacă da, asigurați-vă că ați împărtășit cu noi provocările cu care v-ați confruntat.