Bygg en successivt förbättrad mobilmeny som fungerar utan JavaScript
Senaste uppdateringen gjordes den 21 januari 2019.
Rena CSS-fria hamburgermenyer utanför canvas är inte en ny upptäckt. Chris Coyier skrev trots allt om den här tekniken redan i november 2012.
- Om det här är ett gammalt trick för dig, så häng med mig en stund. Jag har förbättrat Chris exempel och vill gärna ha din feedback.
- Om detta är nytt för dig, oroa dig inte. Du har gott om sällskap, eftersom det verkar som om en stor del av webben inte riktigt har fattat det än.
Med detta kommer vi att bygga en enkel, responsiv hamburgermeny utanför canvas med hjälp av endast CSS som kommer att vara lätt att införliva i ditt eget projekt. Men först…
Vad är det för fel på JavaScript?
Inget.
Aaron Gustafson förklarar vikten av Progressive Enhancements och JavaScript:s roll i webbutveckling bättre än vad jag någonsin skulle kunna göra. Du borde läsa hans inlägg. Men för korthetens skull ska jag försöka sammanfatta det:
- ”Kärnaktiviteter kan alltid utföras utan JavaScript.”
- Kärnaktiviteter bör utföras på det mest stabila lagret (dvs. inte JavaScript).
- Progressive Enhancements är inte anti-JavaScript. Det handlar bara om att anamma rätt teknik på rätt lager.
- ”Eftersom det finns en viss chans att JavaScript inte kommer att fungera måste vi alltid ta hänsyn till den chansen.”
- Det är aldrig en bra idé att ignorera potentiella användare.
- Progressive Enhancements är bara bra teknik.
Så, vi kommer att göra så mycket som möjligt med HTML och CSS. Sedan får JavaScript göra sin magi på ett mer lämpligt lager – förbättra det redan befintliga användargränssnittet.
Steg 1: HTML
Som du kanske vet är det första steget alltid att skriva ett gediget, väl genomtänkt grundlager av HTML.
Notera: Jag använder Font Awesome för ikonerna i mitt exempel.
Det ser ganska standard ut, eller hur? Vi har:
- Vårt överordnade <header> element
- Ikonen för hamburgare (”fa-bars”)
- En huvudrubrik (eller eventuellt en logotyp)
- Navigationen i ett <nav> element
- En ikon för stängning (”fa-close”) i navigationen (mer om detta senare)
- En ”backdrop” efter navigationen. Varför är det en ankartagg? Det ska jag förklara senare.
Steg 2: Låt oss göra det mer tillgängligt
Tillgänglighet bör aldrig vara en eftertanke – som efter att du har skrivit din applikation. Den bör planeras från början. Att lägga till några grundläggande överväganden nu kommer inte bara att förbättra den övergripande tillgängligheten på din webbplats, utan det kommer också att ge dig (utvecklaren) bättre markeringar att använda i din JavaScript!
Därmed ska vi lägga till ytterligare några attribut och lite text för skärmläsare:
Här är en snabb uppdelning av alla dessa attribut och hur de fungerar:
- Vi har lagt till unika ID:n för att kunna rikta in våra HREF:er (mer om hur detta fungerar senare).
- Vi har tillhandahållit en informativ etikett för knapparna för skärmläsare med hjälp av .
- Vi har dolt ikonerna för skärmläsare med , eftersom de är visuella representationer, och lagt till text som endast är avsedd för skärmläsare med <span class=”sr-only”>-elementen.
- Vi har tagit bort ”bakgrunden” från tabbningsindexet med en . Den är rent visuell till sin natur och vi vill inte förvirra våra synskadade och tangentbordsanvändare.
- Vi har lagt till attributet amazing för att ställa in det initiala (och semantiska) tillståndet för ”bakgrunden”. Inget mer skräp – så spännande!
Här är resultatet hittills:
Steg 3: Låt oss styla det!
Vi kommer att närma oss det här mobilt, så vi tar fram den mobila, ”hamburgerliknande” vyn (den intressanta delen).
Först ska vi bara få ordning på rubrikens layout (utan interaktivitet):
Resultatet:
Steg 4: Interaktivitet med ren CSS
När du gör widgetar interaktiva med CSS har du ett par alternativ:
- Använd radioradioer eller kryssrutor
- Använd pseudoklassen :target.
Radioradioer och kryssrutor fungerar otroligt bra för de flesta widgetar, som flikar, modaler, dropdowns och dragspel. Chris Coyier har döpt den här tekniken till ”the checkbox hack”. Flera utvecklare har använt detta ”hack” för sina menyer utanför canvas, som i Paul Lewis handledning för Chrome Dev Summit eller Luis Manuels morphing hamburgermeny.
Pseudoklassen :target är dock mer semantisk i det här användningsfallet, eftersom vi har direkt att göra med navigering. Du kanske inte håller med, och det är helt okej! Det skulle vara otroligt enkelt och helt acceptabelt att byta ut pseudoklassen :target mot en kryssruta.
Båda teknikerna har dock sina begränsningar.
Användning av en kryssruta:
- Kräver att JavaScript stänger menyn utanför canvas om en av länkarna i menyn var en ankarlänk till ett specifikt avsnitt på samma sida.
- Kräver att fältet <input> är ett syskon till menyn eller åtminstone ett syskon till menyns föregångare. CSS är med andra ord lite knepigare. Du kan dock ha <label> (även flera etiketter) någon annanstans.
- <label>-elementet kommer inte att vara direkt fokuserbart eller tabbar, vilket kräver lite knepigare CSS för att hantera fokus på kryssrutan samtidigt som man ändrar det synliga utseendet på <label>.
- Tangentbordsnavigationen vid öppning/stängning av menyn kommer att vara snurrig. Att påverka en tillståndsändring på en kryssruta sker genom den och inte genom tangenten. Medan blinda användare kanske förstår att widgeten styrs av en kryssruta, kommer synskadade tangentbordsanvändare att bli förvirrade eftersom kryssrutan inte är synlig – något som jag kände var ett problem i det här användningsfallet.
Användning av pseudoklassen :target:
- Lägger till öppnandet/stängningen av menyn utanför canvas till webbläsarens historik (skjuter in hashen i adressfältet). Det krävs att JavaScript kör Event.preventDefault() för att undvika detta (och det potentiellt irriterande hoppet till toppen av sidan).
Och det kan finnas andra förbehåll som jag missat. Hur som helst är valet av teknik både en fråga om preferenser och beroende på projektets krav. Hur som helst, jag har avvikit…
Här kommer den interaktiva delen av CSS:
Resultatet när man klickar:
Hur allt detta fungerar
Pseudoklassen :target ger oss i princip ett nytt ”tillstånd” för att styla den målinriktade navigeringen. När main-menu har blivit target (med dess hash som lagts till i URL:en) kan vi nu dra ut menyn. Det är lite som en :focus-pseudoklass för det målinriktade elementet (inte själva länken).
Vi har också tillåtit ”backdrop” att visas när navigeringen är målinriktad.
Du märker att ikonen för huvud-hamburgaren är kopplad till navigeringens ID, medan både stängnings-ikonen och backdrop-knapparna är kopplade till ikonen för huvud-hamburgaren. Detta gör att vi kan klicka på stängningsikonen eller bakgrundsknappen för att ta bort ”fokus” – eller egentligen :target – från navigeringen. Om bakgrunden inte var en länk skulle den inte vara klickbar utan JavaScript.
Jag har också kedjat :target-selektorerna tillsammans med attributet i CSS. Här kommer vi så småningom att successivt förbättra hamburgermenyn med JavaScript så att den inte hoppar till rubriken när man klickar på den – och på så sätt undviker vi den invändning som jag nämnde tidigare. Att JavaScript kapar webbläsarens hashbeteende innebär att pseudoklassen :target inte längre kommer att fungera. När detta händer kommer vi att dra nytta av attributet för att styla växlingen med sant/felaktigt-värden på samma sätt som vi tidigare kunde ha gjort med klasser.
Under tiden fungerar detta dock utmärkt utan JavaScript.
Jag har lagt till @supports media query för att ge den föredragna CSS:en position:fixed till webbläsare (både mobila och stationära) som har stöd för det. I annat fall får lama webbläsare och enheter – jag tittar på dig iOS – position:absolute.
Steg 5: Stilar för större skärmar
Då vi inte vill att hamburgermenyn ska visas för enheter som inte är mobila (eller större skärmar i allmänhet), lägger vi till den nödvändiga mediaquery:n för detta. Sedan stylar vi den så att den ser ut som en horisontell navigation:
Resultatet:
Voila! Vi är klara!
Sätt ihop det hela
Här är den slutliga HTML: