Container-Tilpasse Faner Med “Mer” – Knappen

0
51

Eller prioritet navigasjon mønster, eller gradvis kollapse menyen. Vi kan navnet på minst tre måter.

Det er flere UX løsninger for faner og menyer, og hver av dem har sine egne fordeler over en annen, du trenger bare å velge den beste for det tilfelle du prøver å løse. På design og utvikling byrå Kollegorna vi var debattere på den mest hensiktsmessige UX teknikk for faner for vår klient ‘ s nettside…

Vi ble enige om det bør være en one-liner fordi mengden av kategorien elementer er ukjent og falt vårt valg ned til to: horisontal rulling og adaptive med “mer” – knappen. For det første, problemet med det tidligere er at horisontal rulling som en funksjon er ikke alltid visuelt tydelig for brukerne (spesielt for smale elementer som faner), mens det andre kan være mer tydelig enn en knapp (“mer”), høyre? For det andre, rulle vannrett ved hjelp av en mus-kontrollerte enheten er ikke en veldig behagelig ting å gjøre, så vi må kanskje gjøre våre UI mer komplisert med ekstra pil-knappene. Alle betraktes som endte vi opp med å velge de senere alternativ:

Planlegging

Den viktigste intriger her er om det er mulig å oppnå det uten JavaScript? Delvis ja, men de begrensninger som det kommer med sannsynligvis gjøre det bare bra for et konsept museum snarere enn virkelige scenarier (uansett, Kenan gjorde en veldig fin jobb). Likevel, avhengigheten av JS betyr ikke at vi ikke kan gjøre det brukbart hvis for noen grunn teknologi er ikke tilgjengelig. Progressive enhancement og grasiøs degradering for å vinne!

Siden mengden av kategorien elementer er usikker eller flyktige, vil vi gjøre bruk av Flexbox som sikrer elementer er pent fordelt i container element uten å sette bredder.

Første Prototype

Det er to lister både visuelt og teknisk: man er for elementer som passer inn i beholderen, og en for objekter som ikke gjør det. Siden vi vil avhenge av JavaScript, det er helt greit å ha vår første markup med en enkelt liste (vi vil duplisere det med JS):

<nav class=”faner”>
<ul class=”-primær”>
<li><a href=”…”>Falkenberg</a></li>
<li><a href=”…”>Braga</a></li>
<!– … –>
</ul>
</nav>

Med en liten touch av flex-baserte CSS-ting er i ferd med å få alvorlige her. Jeg skal hoppe over de dekorative CSS-egenskaper i mine eksempler her og sted her hva som virkelig betyr noe:

.faner .-primære {
skjerm: flex;
}
.faner .-primære > li {
flex-vokse: 1;
}

Her er hva vi allerede har:

Grasiøs Nedbrytning

Nå før å styrke det gradvis med JavaScript, la oss sørge for at det forringer grasiøst hvis det er ingen JS tilgjengelig. Det flere grunner til JS fravær: det er fortsatt lasting, det har fatale feil, det klarte ikke å bli overført over nettverket.

.kategorier:ikke(.–jsfied) {
overflow-x: auto;
-webkit-overløp-rulle: trykk;
}

Og når JavaScript er her, –jsfied klasse navn er lagt til container element som nøytraliserer CSS ovenfor:

beholderen.classList.legg til(‘–jsfied’)

Det viser seg at den horisontale bla strategi som jeg har nevnt før, kan en fint bruke her! Når det ikke er nok plass til menyelementer overfylte innhold blir festet på innsiden av beholderen og rullefelt vises. Det er langt bedre enn tomme plassen eller noe som er ødelagt, er det ikke?

Mangler Deler

First off, la oss sette inn de manglende DOM deler:

  • Sekundær (dropdown-liste som er en kopi av de viktigste liste;
  • “Mer” – knappen.

const container = – dokument.querySelector(‘.kategorier’)
const primære = container.querySelector(‘.-primær’)
const primaryItems = container.querySelectorAll(‘.-primære > li: (. -mer)’)
beholderen.classList.legg til(‘–jsfied’)

// sett inn “mer” – knappen og kopier liste

primære.insertAdjacentHTML(‘beforeend’, `
<li class=” -“>
<- knappen type=”button” aria-haspopup=”true” aria-utvidet=”false”>
Mer &darr;
</button>
<ul class=”videregående”>
${primære.innerHTML}
</ul>
</li>
`)
const sekundær = container.querySelector(‘.-sekundære’)
const secondaryItems = sekundær.querySelectorAll(‘li’)
const allItems = container.querySelectorAll(‘li’)
const moreLi = primary.querySelector(‘.-mer”)
const moreBtn = moreLi.querySelector(‘knappen’)
moreBtn.addEventListener(‘click’, (e) => {
e.preventDefault()
beholderen.classList.veksle(‘–show-sekundær’)
moreBtn.setAttribute(‘aria-utvidet’, container.classList.inneholder(‘–show-sekundær’))
})

Her er vi hekkende videregående listen i primær-og ved hjelp av noen aria-* egenskaper. Vi ønsker at våre navigeringsmenyen for å være tilgjengelig, ikke sant?

Det er også en event handler festet til “mer” – knapp som veksler –show-videregående klasse navn på beholderen element. Vi vil bruke den til å vise og skjule den sekundære listen. La oss nå stil den nye deler. Du ønsker kanskje å visuelt aksent “mer” – knappen.

.faner {
position: relative;
}
.faner .-sekundær {
display: none;
position: absolute;
øverst: 100%;
høyre: 0;
}
.faner.–vis videregående .-sekundær {
display: block;
}

Her er hvor som brakte oss til:

Selvsagt, vi trenger noen kode som skjuler og viser tappene…

Skjule og Vise Faner i Lister

På grunn av Flexbox, den kategorien elementer vil aldri bryte inn flere linjer, og vil krympe til sine minst mulig bredder. Dette betyr at vi kan gå gjennom hvert punkt en og en, legge opp sine bredder, sammenligne det til bredden av .faner element og slå synligheten av bestemte faner tilsvarende. For at vi skal lage en funksjon som kalles doAdapt og pakk inn koden nedenfor i dette avsnittet.

Til å begynne bredde, bør vi visuelt avsløre alle de elementer:

allItems.forEach((element) => {
elementet.classList.fjern(‘–skjult”)
})

På en side notat, .–skjult fungerer på den måten du har sannsynligvis hadde forventet:

.faner .–skjult {
display: none;
}

Matematikk tid! Jeg må skuffe deg hvis du forventet en avansert matematikk. Så, som beskrevet tidligere, og vi går gjennom hver primær-fanen ved å legge opp sine bredder under stopWidth variabel. Vi utfører også en sjekk hvis elementet passer i beholderen, skjule elementet hvis ikke, og lagre indeksen for senere bruk.

la stopWidth = moreBtn.offsetWidth
la hiddenItems = []
const primaryWidth = primary.offsetWidth
primaryItems.forEach((element, i) => {
hvis(primaryWidth >= stopWidth + elementet.offsetWidth) {
stopWidth += elementet.offsetWidth
} else {
elementet.classList.legg til(‘–skjult”)
hiddenItems.trykk(jeg)
}
})

Heretter, vi trenger å skjule tilsvarende elementer fra videregående liste som var synlig i det primære. Samt skjule “mer” knappen hvis ingen av kategoriene var skjult.

if(!hiddenItems.lengde) {
moreLi.classList.legg til(‘–skjult”)
beholderen.classList.fjern(‘–show-sekundær’)
moreBtn.setAttribute(‘aria-utvidet’, false)
}
else {
secondaryItems.forEach((element, i) => {
if(!hiddenItems.omfatter(i)) {
elementet.classList.legg til(‘–skjult”)
}
})
}

Til slutt, sørg for doAdapt funksjonen utføres på rett øyeblikk:

doAdapt() // tilpasse umiddelbart på legg
vinduet.addEventListener(‘resize’, doAdapt) // tilpasse på vinduet endrer størrelse

Ideelt endre størrelse hendelseshåndterer bør være debounced for å unngå unødvendige beregninger.

Mine damer og herrer, dette er resultatet (spille med endring av størrelse demo vindu):

Se Penn Container-Tilpasse Faner Med “Mer” – Knappen ved Osvaldas (@osvaldas) på CodePen.

Jeg kunne sannsynligvis ende min artikkel her, men det er en ekstra mil for vi kan gå for å gjøre det bedre og noen ting å merke…

Ekstrautstyr

Det har blitt implementert i demo ovenfor, men det har vi ikke omtalt en liten detalj som forbedrer UX av våre faner widget. Det er som gjemmer rullegardinlisten automatisk hvis brukeren klikker du hvor som helst utenfor listen. For at vi kan binde en global klikk på lytteren og sjekk om klikket element eller alle av sine foreldre er secondarylist eller “mer” – knappen. Hvis ikke, dropdown-listen blir avvist.

dokumentet.addEventListener(‘click’, (e) => {
la el = e.målet
mens(el) {
hvis(el === sekundær || el === moreBtn) {
tilbake;
}
el = el.parentNode
}
beholderen.classList.fjern(‘–show-sekundær’)
moreBtn.setAttribute(‘aria-utvidet’, false)
})

Edge Saker

Lang Kategorien Titler

Kanskje du har vært lurer på hvordan widgeten fungerer med lange titler-fanen. Vel, du har minst to valg her…

  1. La titler wrap til neste linje som er hvordan de oppfører seg som standard (du kan også aktivere tekstbryting med word-wrap: break-word):
  1. Eller du kan deaktivere alle typer innpakning i den primære liste med white-space: nowrap. Skriptet er fleksibel nok til å sette de alt for lange gjenstander til dropdown (der titlene er gratis å vikle) ved å tre til side kortere søsken:

Mange Faner

Selv om den sekundære liste position: absolute det spiller ingen rolle hvor lenge dokumentets høyde. Så lenge container element eller dets foreldre er ikke stilling: fast, dokumentet vil tilpasse seg, og den nederste elementene vil bli tilgjengelig ved å bla nedover på siden.

En Ting å være Klar Over

Ting kan bli vanskelig hvis kategoriene er knappene snarere enn ankere semantisk, som betyr at deres svar på klikk er besluttet av JavaScript, for eksempel: dynamisk faner. Problemet her er at fane-knappen event-handlere ikke er duplisert langs med markeringen. Jeg ser minst to tilnærminger for å løse det:

  • Sted dynamisk hendelse handler vedlegg rett etter den adaptive kategorien koden;
  • Bruk en hendelse delegasjon metode i stedet (tenk på jQuery live()).

Dessverre, det oppstår hendelser i antall: mest sannsynlig er det at fanene vil ha en valgt tilstand som visuelt viser den gjeldende fanen så det er også viktig å behandle tilstander samtidig. Hvis ikke, snu nettbrettet og du tapt.

Nettleser Kompatibilitet

Selv om jeg brukte ES6 syntaks i eksempler og demo, det bør bli konvertert til ES5 av en kompilator som Babel betydelig utvide nettleseren støtte (ned til IE9 inkludert).

Du kan også utvide Flexbox gjennomføring med en eldre versjon og syntaks (helt ned til IE10). Hvis du trenger å også støtte ikke-Flexbox nettlesere kan du alltid gjøre funksjonen for gjenkjenning med CSS @støtter, kan du bruke den teknikken gradvis, og stole på horisontal rulling for eldre nettlesere.

Glad tabbe!