Container-Anpassa Flikar Med “Mer” Knappen

0
44

Eller de prioriterade navigering mönster, eller gradvis på att kollapsa navigation-menyn. Vi kan nämna att det på åtminstone tre sätt.

Det finns flera UX lösningar för flikar och menyer och var och en av dem har sina egna fördelar jämfört med en annan, du behöver bara välja den bästa för det fall du försöker lösa. Vid design och utveckling byrå Kollegorna var vi debatterar på den mest lämpliga UX-teknik för flikar för vår kunds hemsida…

Vi kom överens om att det bör vara en one-liner eftersom mängden fliken objekt är okänd och minskat våra val ner till två: horisontell scroll och adaptiva med “mer” – knappen. För det första, problemet med det tidigare är att horisontell scroll som en funktion är inte alltid visuellt uppenbart för användare (särskilt för smala element som tabs) vad kan vara mer självklart än en knapp (“mer”), rätt? För det andra, rulla horisontellt med hjälp av en mus-kontrollerade enheten inte är en mycket bekväm sak att göra, så vi kan behöva för att göra våra UI mer komplex med ytterligare pilknapparna. Alla anses slutade det med att vi väljer det senare alternativet:

Planering

Den huvudsakliga intrig här är om det är möjligt att uppnå detta utan JavaScript? Delvis ja, dock med de begränsningar som det har förmodligen att göra det bara bra för ett koncept museum snarare än verkliga livet scenarier (hur som helst, Kenan gjorde ett riktigt bra jobb). Fortfarande, beroende på JS betyder inte att vi inte kan göra det användbart om du av någon anledning tekniken är inte tillgänglig. Progressive enhancement och graceful degradation för att vinna!

Eftersom storleken på fliken objekt är osäker eller flyktiga, vi kommer att använda sig av Flexbox som säkerställer att objekten är fint sprids i behållaren för del, utan att lägga bredder.

Första Prototypen

Det finns två listor, både visuellt och tekniskt: en är för poster som passar in i behållaren, och en för poster som inte gör det. Eftersom vi är beroende av JavaScript, och det är helt bra att ha vår första markup med en enda lista bara (vi kommer att dubbla den med JS):

<nav class=”flikar”>
<ul class=”primär”>
<li><a href=”…”>Falkenberg</a></li>
<li><a href=”…”>Braga</a></li>
<!– … –>
</ul>
</nav>

Med en liten touch av flex-baserade CSS-saker och ting börjar bli allvarliga här. Jag ska hoppa över den dekorativa CSS-egenskaper i mitt exempel här och här vad som verkligen är viktigt:

.flikar .-primary {
display: flex;
}
.flikar .-primära > li {
flex-växa: 1;
}

Här är vad vi redan har:

Graceful Degradation

Nu innan öka det gradvis med JavaScript, låt oss se till att det försämrar vackert om det inte finns någon JS tillgängliga. Det finns flera skäl för JS frånvaro: det är fortfarande lastning, det har allvarliga fel, det gick inte att överföras via nätverket.

.flikar:inte(.–jsfied) {
overflow-x: auto;
-webkit-overflow-rullning: tryck;
}

Och när JavaScript är här, –jsfied klass namn läggs till i behållaren element som neutraliserar CSS ovan:

behållare.classList.add(‘–jsfied’)

Visar sig den vågräta rullningslisten strategi som jag nämnde innan du kan göra en fin använda här! När det inte finns tillräckligt med utrymme för menyalternativ överfulla innehållet blir klippt inuti behållaren och rullningslister visas. Det är mycket bättre än den tomma rymden eller något som är sönder, är det inte?

Delar Saknas

Först och främst, låt oss sätta den saknade DOM delar:

  • Sekundära (dropdown) förteckning som är en kopia av de viktigaste lista;
  • “Mer” knappen.

const container = dokument.querySelector(‘.flikar’)
const främsta = behållaren.querySelector(‘.-primära”)
const primaryItems = behållaren.querySelectorAll(‘.-primära > li:inte(.-fler)’)
behållare.classList.add(‘–jsfied’)

// lägger till “mer” – knappen och kopiera listan

primära.insertAdjacentHTML(‘beforeend’, `
<li class=”mer”>
<button type=”button” aria-haspopup=”true” aria-utökat=”false”>
Mer &darr;
</button>
<ul class=”secondary”>
${primära.innerHTML}
</ul>
</li>
`)
const sekundära = behållaren.querySelector(‘.-sekundära’)
const secondaryItems = sekundär.querySelectorAll(‘li’)
const allItems = behållaren.querySelectorAll(‘li’)
const moreLi = primär.querySelector(‘.-mer”)
const moreBtn = moreLi.querySelector (“knappen”)
moreBtn.addEventListener (“klick”, (e) => {
e.preventDefault()
behållare.classList.växla(‘–show-sekundära’)
moreBtn.setAttribute(‘aria-utökat’, container.classList.innehåller(‘–show-sekundära’))
})

Här är vi häckande sekundära listan i primära och med hjälp av några aria-* egenskaper. Vi vill att våra navigeringen för att vara tillgänglig, eller hur?

Det finns också en händelsehanterare knutna till “mer” knappen som växlar –show-sekundär klass namn på behållaren element. Vi ska använda det för att visa och dölja den sekundära listan. Låt oss nu style den nya delar. Du kanske vill att visuellt accent “mer” – knappen.

.flikar {
position: relative;
}
.flikar .-sekundära {
display: none;
position: absolute;
topp: 100%;
rätt: 0;
}
.flikar.–visa-sekundär .-sekundära {
display: block;
}

Här är där som fört oss till:

Självklart behöver vi en del kod som döljer och visar flikar…

Dölja och Visa Flikar i Listor

På grund av Flexbox, fliken objekt kommer aldrig att bryta sig in i flera rader och kommer att krympa till minsta möjliga bredder. Detta innebär att vi kan gå genom varje objekt en efter en, lägga upp sina bredder, jämföra det med den bredd av .flikar element och växla synligheten för vissa flikar i enlighet med detta. För att vi kommer att skapa en funktion som kallas doAdapt och linda in koden nedan i detta avsnitt.

Till att börja bredd, vi bör visuellt visa alla poster:

allItems.forEach((punkt) => {
punkt.classList.ta bort(‘–hidden’)
})

På en sida notera, .–dolda fungerar på det sätt du har nog väntat:

.flikar .–dolda {
display: none;
}

Matte tid! Jag måste göra dig besviken om du väntat en avancerad matematik. Så, som beskrivits tidigare, vi går igenom varje primära fliken genom att lägga ihop deras bredder under stopWidth variabel. Vi utför även en kontroll om det objekt som passar i behållaren, dölja objekt om inte och spara sitt index för senare användning.

låt stopWidth = moreBtn.offsetWidth
låt hiddenItems = []
const primaryWidth = primär.offsetWidth
primaryItems.forEach((objekt i) => {
om(primaryWidth >= stopWidth + artikel.offsetWidth) {
stopWidth += punkt.offsetWidth
} else {
punkt.classList.add(‘–hidden’)
hiddenItems.push(jag)
}
})

I fortsättningen behöver vi för att dölja motsvarande objekt från den sekundära listan som varit synliga i den primära. Liksom gömma sig “mer” – knappen om inga flikar var dolda.

if(!hiddenItems.length) {
moreLi.classList.add(‘–hidden’)
behållare.classList.ta bort(‘–show-sekundära’)
moreBtn.setAttribute(‘aria-utökat’, false)
}
else {
secondaryItems.forEach((objekt i) => {
if(!hiddenItems.inkluderar(i)) {
punkt.classList.add(‘–hidden’)
}
})
}

Slutligen, se till doAdapt funktion utförs i rätt ögonblick:

doAdapt() // anpassa omedelbart på last
fönster.addEventListener(‘ändra storlek’, doAdapt) // anpassa ändra storlek på fönster

Helst ändra storlek händelsehanterare bör vara debounced för att förhindra onödiga beräkningar.

Mina damer och herrar, detta är resultatet (spela med ändra storlek på demo-fönstret):

Se Pennan Container-Anpassa Flikar Med “Mer” Knappen av Osvaldas (@osvaldas) på CodePen.

Jag kan nog avsluta min artikel här, men det är en extra mil kan vi promenad för att göra det bättre och vissa saker att tänka på…

Tillbehör

Det har genomförts i demo ovan, men vi har inte överblickas en liten detalj som förbättrar UX på våra flikar widget. Det gömmer sig rullgardinsmenyn automatiskt om användaren klickar någonstans utanför listan. För att vi kan binda en global klicka på lyssnaren och kontrollera om den valda delen eller någon av dess föräldrar är secondarylist eller “mer” – knappen. Om inte, den nedrullningsbara listan blir uppsagda.

dokumentet.addEventListener (“klick”, (e) => {
låt el = e.målet
medan(el) {
om(el === sekundär || el === moreBtn) {
återvändande.
}
el = el.parentNode
}
behållare.classList.ta bort(‘–show-sekundära’)
moreBtn.setAttribute(‘aria-utökat’, false)
})

Kant Fall

Lång Fliken Titlar

Du kanske har undrat hur widgeten fungerar med lång fliken titlar. Tja, du har minst två alternativ här…

  1. Låt titlar radbyte till nästa rad, vilket är hur de beter sig som standard (du kan även aktivera radbrytning i word-wrap: break-ord):
  1. Eller så kan du inaktivera alla typer av omslag i den primära listan med white-space: nowrap. Manuset är tillräckligt flexibel för att sätta alltför långa artiklar till dropdown (där titlarna är gratis att linda) genom att stega undan kortare syskon:

Många Flikar

Även om den sekundära listan position: absolute det spelar ingen roll hur länge ditt dokument höjd. Så länge behållare element eller dess föräldrar är inte position: fixed, dokumentet kommer att anpassa sig och botten objekt kommer att nås genom att scrolla ner på sidan.

En Sak att vara Medveten Om

Saker kan bli knepigt om flikarna finns knappar snarare än ankare semantiskt, vilket innebär att deras svar till klick beslutas av JavaScript, t ex: dynamisk flikar. Problemet här är att tab-knappen event handlers inte dupliceras tillsammans med uppmärkningen. Jag ser minst två sätt att lösa det:

  • Plats dynamiska event handler bilagor direkt efter den adaptiva fliken kod.
  • Använd en händelse delegationen metod istället (tänk dig av jQuery ‘ s live()).

Tyvärr, händelser inträffar i kvantitet: troligtvis dina flikar kommer att ha ett urval av staten som visuellt indikerar aktuell flik, så det är också viktigt att hantera de stater samtidigt. Annars, vänd tablet och du är förlorad.

Webbläsare

Även om jag använde ES6 syntax i de exempel och demon, det bör omvandlas till ES5 av en kompilator som Babel för att avsevärt vidga webbläsare stöd (ner till IE9 bland annat).

Du kan också utöka Flexbox genomförandet med en äldre version och syntax (hela vägen ner till IE10). Om du behöver också stöd för icke-Flexbox webbläsare kan du alltid göra har upptäckt med CSS @stöd, tillämpa tekniken successivt, och lita på horisontell scroll för äldre webbläsare.

Glad tabbing!