Hvis du noen gang har jobbet på en responsiv nettside, har du uten tvil hatt å takle en av de vanskeligste problemene i dette nye feltet: navigering. For enkel navigering kan løsningene være rett frem. Men hvis du jobber med noe litt mer komplisert, kanskje med flere nestede lister og dropdowns, kan en mer dramatisk omplassering være i orden.
I denne tilnærmingen til responsiv navigering skal vi bruke en tilnærming som kan huse store navigasjonsmenyer på flere nivåer ved hjelp av medieforespørsler og jQuery, samtidig som vi prøver å holde vår oppslag enkel og våre eksterne ressurser minimal.
Hvis du er ute etter en rask løsning, er det en flott samling CSS navigasjonsmenyer og stiler over på Envato Market.
Denne CSS3 Mega Drop Down-menyen er spesielt smart - den er bare avhengig av CSS / XHTML og kommer med et fullt fungerende kontaktskjema, samt å være fullt lydhør overfor oppstart. Tre hovedvarianter er inkludert: Horisontal, vertikaljustert til venstre og vertikaljustert til høyre.
Du kan også jobbe med en av ekspertleverandørene på Envato Studio.
Her er det vi satser på:
Våre oppslag er en ganske rett fremad uordnet liste, med nestede lister som finnes i listeposter. Jeg forsøker ikke å bruke noen klasser eller IDer på noe element, men den uordnede listen over foreldre, slik at menyen vil være kompatibel med CMS-genererte menyer.
Meny
- sko
- Womens
- sandaler
- joggesko
- kiler
- hæler
- mokasiner
- Flats
- Mens
- mokasiner
- joggesko
- Formell
Trinn 2: Grunnleggende stilering
La oss legge til litt grunnleggende styling for å få listen vår som en navigeringslinje:
kropp, nav, ul, li, en margin: 0; polstring: 0; body font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; en tekst-dekorasjon: ingen; .container bredde: 90%; maksimal bredde: 900px; margin: 10px auto; .toggleMenu display: none; bakgrunn: # 666; polstring: 10px 15px; farge: #fff; .nav listestil: none; * zoom: 1; bakgrunn: # 175e4c; stilling: relativ; .nav: før, .nav: etter innhold: ""; skjerm: bord; .nav: etter clear: both; .nav ul listestil: none; bredde: 9em; .nav en polstring: 10px 15px; farge: #fff; * zoom: 1; .nav> li float: left; border-top: 1px solid # 104336; z-indeks: 200; .nav> li> a display: block; .nav li ul posisjon: absolutt; igjen: -9999px; z-indeks: 100; .nav li li a display: block; bakgrunn: # 1d7a62; stilling: relativ; z-index: 100; border-top: 1px solid # 175e4c; .nav li li li a bakgrunn: # 249578; z-index: 200; border-top: 1px solid # 1d7a62;Vi har nettopp flyttet våre listeposter til en horisontal linje, satt noen farger opp og skjult undermenyene fra skjermen ved hjelp av absolutt posisjonering. Hvis du lurer på linje 20, er det en enkel clearfix-metode som jeg finner effektive i slike situasjoner (les mer på Nicolas Gallaghers blogg).
Trinn 3: Horisontal Dropdown-meny
Deretter la vi få de horisontale rullegardinmenyene til å skje. Mens dette kan gjøres med rent CSS ved hjelp av
:sveve
pseudo-selector, jeg skal legge til det ved å bruke JavaScript siden vi skal bytte menyene for å aktivere på klikk i vår liten skjermversjon.Siden vi bruker absolutt posisjonering for å flytte undermenyene våre fra skjermen, la oss legge til noen
.sveve
regler som vil plassere undermenyene i forhold til foreldrene deres når.sveve
klassen er til stede (som vi skal ta vare på med jQuery)..nav li posisjon: relativ; .nav> li.hover> ul left: 0; .nav li li.hover ul left: 100%; topp: 0;Nå legger vi til et par linjer med enkel jQuery for å legge til .overklassen for å liste elementer når de svinger over.
$ (dokument) .ready (funksjon () $ (". toggleMenu"). css ("display", "none"); $ (".nav li"). hover (funksjon () $ (dette). addClass ('hover');, funksjon () $ (dette) .removeClass ('hover');););Og akkurat slik har vi selv en funksjonell, flernivå rullegardinmeny.
Trinn 4: Vertikal Dropdown-meny
Vår nydelige, horisontale rullegardinmeny ser dessverre ut ganske liten på mobilskjermbilder, så la oss sørge for at mobile nettlesere blir fullt innzoomd når de laster inn siden vår ved å legge til metadaggen.
Selvfølgelig ser vår rullegardinmeny enda verre ut på mobile enheter, og det meste passer ikke på skjermen! La oss legge til i noen medieforespørsler for å utforme listen vår i en vertikal liste under vårt bruddpunkt. Vårt pausepunkt bestemmes av det punktet som vår meny går på to linjer, i mitt tilfelle, det er omtrent 800 px.
På vårt knutepunkt fjerner vi flyter og setter listepostene og uordnede lister til
bredde: 100%
. Akkurat nå, når vi svinger over foreldreelementene våre, vises deres barnelister over toppen av elementene under den. Vi vil heller de andre toppnivålistene bli forskjøvet. Så i stedet for å endrevenstre
posisjonen til den uordnede listen, vil vi bare sette innstilling
verdi tilstatisk
.@media skjerm og (maksimal bredde: 800px) .nav> li float: none; .nav ul display: block; bredde: 100%; .nav> li.hover> ul .nav li li.hover ul posisjon: statisk;Trinn 5: Konvertere Hover to Click
Siden du ikke kan svinge på en berøringsskjerm (ennå), skal vi lage en betinget kode for å sjekke bredden på vinduet, og skriv koden for å angi
Klikk ()
ogsveve()
arrangementer.$ (dokument) .ready (funksjon () var ww = document.body.clientWidth; hvis (ww < 800) $(".toggleMenu").css("display", "inline-block"); $(".nav li a").click(function() $(this).parent("li").toggleClass('hover'); ); else $(".toggleMenu").css("display", "none"); $(".nav li").hover(function() $(this).addClass('hover'); , function() $(this).removeClass('hover'); ); );For
klikk
Hendelsen, vi har måttet endre målrettet element fra listeposten til overordnet element, siden lister er nestet og å klikke på en liste element kan også åpne barnebarnene sine. Problemet med denne endringen er imidlertid at det å klikke på en ankermerke vil laste siden på nytt, men vi kan ikke forhindre standardadferd på alle ankerkoder som er etterkommere av listeposter.For å fikse dette, la oss legge til en liten bit av jQuery for å legge til klassen
.forelder
til enhver liste gjenstand hvis barnanker har søsken, målrett bare på disse ankrene (igjen, prøver å holde vår oppslag fleksibel).$ (".nav li a"). hver (funksjon () hvis ($ (dette) .neste () .lengde> 0) $ (dette) .addClass ("foreldre");;) ww < 800) $(".toggleMenu").css("display", "inline-block"); $(".nav li a.parent").click(function(e) e.preventDefault(); $(this).parent("li").toggleClass('hover'); ); else …Trinn 6: Slå på menyen
Menyen vår ser ganske fin ut på mobile enheter nå, men det tar opp mye verdifull skjerm fast eiendom. En populær ny tilnærming har vært å bytte navigasjonslister med en knapp, vanligvis med ordet "Meny" eller et menyikon. La oss få vår veksleforbindelse til å vise vår navigasjonsliste bare når du klikker.
$ (". toggleMenu"). klikk (funksjon (e) e.preventDefault (); $ (".nav"). toggle ();); hvis (ww < 800) $(".toggleMenu").css("display", "inline-block"); $(".nav").hide(); else …Trinn 7: En litt mer stil
Siden vi nå har våre foreldreliste elementer målrettet med en klasse, hvorfor ikke legge til en liten nedpilen for å la brukerne våre vite hvilke listeelementer som har barn?
.nav> li> .parent bakgrunnsposisjon: 95% 50%; .nav li li .parent bakgrunnsbilde: url ("images / downArrow.png"); bakgrunn-gjentak: ikke-gjenta; bakgrunnsposisjon: 95% 50%; @media skjerm og (maksimal bredde: 800px) . nav> li> .parent bakgrunnsposisjon: 95% 50%; .nav li li .parent bakgrunnsbilde: url ("images / downArrow.png"); bakgrunn-gjentak: ikke-gjenta; bakgrunnsposisjon: 95% 50%;Bonus: Viser Av
Nå, for praktisk bruk, fungerer denne menyen ganske bra. Hvis du åpner den i en mobilnettleser, får du en veldig brukbar vertikal trekklistedatabase, hvis du åpner den i din nettleser, får du en fin, horisontal rullegardinliste. Hvis du endrer størrelsen på nettleseren din ned til mobilbredder, virker navigasjonen fortsatt bare på svinger, og menyen er ikke skjult med byttefunksjonen. For de fleste applikasjoner er dette greit. Tross alt, din gjennomsnittlige besøkende på nettstedet tar ikke kanten av nettleseren og begynner å dra galt frem og tilbake.
Men hvis du ønsker å imponere med andre fagpersoner, vil dette bare ikke gjøre. Vi må sette opp skriptet vårt for å svare på
endre størrelse på
hendelse, og utfør vår betingede kode når nettleseren er endret under brytepunktet. Utvidelse på koden demonstrert i den utmerkede Oppretting av en mobil-først-responsiv designopplæring, vi skal sette inn noen variabler for å holde oversikt over og oppdatere nettleserbredden.Trinn 8: Vinduhendelser
Siden vi vil sjekke bredden på nettleseren både på siden lastes og når nettleseren er endret, la oss begynne å flytte all betinget kode ut av
$ (Document) .ready ()
arrangement og innpakning i en funksjonadjustMenu
.var ww = document.body.clientWidth; $ (dokument) .ready (funksjon () $ (". toggleMenu"). klikk (funksjon (e) e.preventDefault (); $ (".nav"). toggle ();); $ hver (funksjon) (hvis $ (dette) .neste (). lengde> 0) $ (dette) .addClass ("overordnet");;) adjustMenu (); ); funksjonen justerMenu () hvis (ww < 800) $(".toggleMenu").css("display", "inline-block"); $(".nav").hide(); $(".nav li a.parent").click(function(e) e.preventDefault(); $(this).parent("li").toggleClass('hover'); ); else $(".toggleMenu").css("display", "none"); $(".nav li").hover(function() $(this).addClass('hover'); , function() $(this).removeClass('hover'); );For å ringe til funksjonen som nettleseren er endret, skal vi
binde
det til vinduet hendelserendre størrelse på
ogorientationchange
. I denne hendelsen skal vi omdefinereww
variabel for å justere til nettleserens nye bredde.$ (vindu) .bind ('resize orientationchange', funksjon () ww = document.body.clientWidth; adjustMenu (););På dette punktet har vi introdusert flere problemer: selv om dette i utgangspunktet ser ut til å fungere (den horisontale menyen faller inn i meny-knappen som åpner menyen), er det tydelig at vi har to store problemer:
- Hele menyen forsvinner hvis vi endrer størrelsen på mobilbreddsvinduet tilbake forbi brytepunktet.
- Hover-hendelsen skyter fortsatt på mobilversjonen.
Trinn 9: Viser og gjemmer seg
Vår manglende navigasjonsmeny virker som en enkel løsning: bare legg til
$ ( "Nav"). Vis ()
under større enn breakpoint tilstanden. Denne løsningen ser ut til å fungere, men bringer opp noen vanskelige kantsaker. Siden koden blir revurdert hver gang nettleseren er endret, når vi endrer størrelsen på menyen, lukkes den automatisk igjen.Dette kan virke som et usannsynlig kanten tilfelle, men mobile nettlesere er rare: for eksempel, på Galaxy S, ruller jeg ned, og tilbake til toppen av en side utløser
endre størrelse på
begivenhet. Ikke bra!For å fikse dette, må vi ha noen måter å sjekke om menyvelgeren har blitt klikket. Jeg skal bruke en ekstra klasse på menyknappen, fordi den kan være nyttig for styling (kanskje vi vil ha en nedpilen senere nedover linjen?) I tillegg til å skifte visning av navigasjonsmenyen, går menyknappen vil nå bytte sin egen klasse av
.aktiv
. Tilbake i vår smalere enn breakpoint-tilstand, la oss oppdatere koden for å skjule vår navigasjonsmeny bare hvis menyen bytter gjør ikke ha en klasse av.aktiv
.$ (dokument) .ready (funksjon () $ (". toggleMenu"). klikk (funksjon (e) e.preventDefault (); $ (dette) .toggleClass ("aktiv"); $ ).veksle(); ); ); hvis (ww < 800) $(".toggleMenu").css("display", "inline-block"); if (!$(".toggleMenu").hasClass("active")) $(".nav").hide(); else $(".nav").show(); $(".nav li a.parent").click(function(e) e.preventDefault(); $(this).parent("li").toggleClass('hover'); ); …Trinn 10 Ubinding Hover Hendelser
For å løse problemet vårt med navigasjonsmenyen i mobil størrelse som svarer på svinghendelser, må vi bare
frigi ()
hover-hendelsen fra våre listeposter i smalere enn breakpoint-tilstanden.$ (".nav li"). unbind ('mouseenter mouseleave');Dette belyser imidlertid et nytt problem: vår
klikk
Hendelsene fungerer ikke hvis du endrer størrelsen på nettleseren fra stor til liten. Noen feilsøking avslører atklikk
hendelsen har blitt bundet til lenken en rekke ganger, så snart vi klikker,.sveve
klassen er slått på og deretter umiddelbart av igjen. Dette skjer fordi hele funksjonen brenner gjentatte ganger ettersom du endrer størrelsen på vinduet. For å sikre at vi begynner å bytte fra riktig sted, må vifrigi
klikkhendelsen før du re-binder den igjen.Når vi endrer størrelsen på nettleseren fra små til store igjen, mangler vi nå vår
sveve
hendelse, fordi vi unbound det når nettleseren var liten, og vårklikk
Hendelsen er fortsatt der, så la oss unbind før bindingen vår svingeroppgave også. Vi skal også fjerne noen listeposter med en klasse av.sveve
før vi legger dem inn igjen på hover-hendelsen, for å hindre at menyer blir uhyggelig åpne da vi gjør nettleseren bredere.Jeg skriver om
.Klikk ()
og.sveve()
hendelser som bruker.binde()
for klarhetens skyld. Det betyr den samme eksakte tingen.hvis (ww < 800) $(".toggleMenu").css("display", "inline-block"); if (!$(".toggleMenu").hasClass("active")) $(".nav").hide(); else $(".nav").show(); $(".nav li").unbind('mouseenter mouseleave'); $(".nav li a.parent").unbind("click").bind("click", function(e) e.preventDefault(); $(this).parent("li").toggleClass('hover'); ); else $(".toggleMenu").css("display", "none"); $(".nav").show(); $(".nav li").removeClass("hover"); $(".nav li a").unbind("click"); $(".nav li").unbind('mouseenter mouseleave').bind('mouseenter mouseleave', function() $(this).toggleClass('hover'); );Hurra! Alt ser ut til å fungere som det burde.
Trinn 11: Få IE til Behave
Det ville ikke være en fest hvis IE7 ikke kom sammen for å krasje det, nå ville det? Vi har en merkelig feil her hvor våre undermenyer forsvinner når de vises over annet innhold (i vårt eksempel, noen lorem ipsum tekst). Når markøren når punktelementet, * poof * ikke mer meny. Jeg er ganske sikker på at dette skyldes litt rar i måten IE7 behandler
stilling: relativ;
, og problemet løses lett ved å utløsehasLayout
på.nav a
element..nav a * zoom: 1;Ytterligere hensyn
Som alltid må du ta en egen vurdering om nettleser og funksjonstøtte, men verktøy som Modernizr og respond.js kan ta litt av smerten ved å støtte eldre nettlesere.
Jeg har testet denne menyen på Mobile Safari og hver Android 2.3 nettleser jeg kunne få hendene på, og det ser ut til å virke ganske bra. Denne teknikken er imidlertid svært JavaScriptavhengig, og siden noen mobile nettlesere (Blackberry generelt) har svært dårlig støtte for JavaScript, kan vi forlate noen brukere med en ubrukelig navigasjonsmeny.
Heldigvis finnes det en rekke metoder du kan bruke til å betjene forenklet layout til JavaScript-mindre enheter. Den gode gammeldags teknikken for å legge til en
.no-js
Klassen til kroppsmerket og fjerning av den i JavaScript kommer i tankene, men du kan også bare gihref
attributter for toppnavigasjonsnavigasjonene, som sender brukere til den generelle "sko" -kategorien, for eksempel, og stoler påpreventDefault
for å forhindre denne oppførselen i JavaScript-aktiverte enheter.Selvfølgelig vil mediespørsmålene ikke fungere i eldre versjoner av IE, så du må avgjøre om det er verdt å inkludere en polyfil som respond.js for å fylle dette gapet..
Sist men ikke minst, det er den irriterende IOS-feilen som forårsaker at zoomnivået endres når du roterer enheten. Sjekk ut iOS Orienteringsbytt-Fix-skriptet for å squash denne feilen.
Videre lesning
Selv om denne teknikken kan være godt egnet til visse situasjoner og menystrukturer, er det fortsatt mange andre alternativer der ute for å tømme navigasjon på mobile enheter. For eksempel:
- Ryan DeBeasis nylige opplæring for en smart løsning på navigasjonsmenyer på en nivå.
- Bla gjennom Brad Frost's roundups Responsive Navigasjonsmønstre ...
- ... og komplekse navigasjonsmønstre for responsiv design.
- For en mobil-første løsning, ta en titt på navigasjonsmenyene i HTML5 Rocks Creating a Mobile-First Responsive Design.
Du er velkommen til å lese, klone eller gaffel GitHub repo, og takk for at du leser!