Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. JavaScript
Code

Creare il carosello perfetto, Parte 3

by
Difficulty:AdvancedLength:LongLanguages:
This post is part of a series called Create the Perfect Carousel.
Create the Perfect Carousel, Part 2

Italian (Italiano) translation by Cinzia Sgariglia (you can also view the original English article)

Questa è la terza e ultima parte del nostra serie di tutorial Creare il carosello perfetto. Nella parte 1, abbiamo valutato i caroselli su Netflix e Amazon, due dei caroselli maggiormente utilizzati nel mondo. Abbiamo impostato il nostro carosello e reso effettivo lo scorrimento tramite il tocco.

Poi nella parte 2, abbiamo aggiunto lo scorrimento orizzontale del mouse, l'impaginazione e un indicatore di avanzamento. Boom.

Ora, nella nostra parte finale, guarderemo il mondo oscuro e spesso dimenticato dell'accessibilità da tastiera. Regoleremo il nostro codice per rimisurare il carosello quando cambia la dimensione del viewport. E infine, faremo alcuni ritocchi utilizzando la fisica della forza elastica.

Si può riprendere  da dove avevamo lasciato in questo CodePen.

Accessibilità da tastiera

È vero che la maggioranza degli utenti non fa affidamento sulla navigazione tramite tastiera, purtroppo a volte ci dimentichiamo dei nostri utenti che lo fanno. In alcuni paesi, lasciare un sito inaccessibile può essere illegale. Ma peggio, è una mossa del cavolo.

La buona notizia è che solitamente è facile da implementare! Infatti, il browser fa la maggior parte del lavoro per noi. Seriamente: provate la tabulazione nel carosello che abbiamo fatto. Poiché abbiamo usato un markup semantico, è già possibile!

Tranne, noterete, che i nostri pulsanti di navigazione scompaiono. Questo perché il browser non permette di focalizzarsi su di un elemento al di fuori del nostro viewport. Così anche se abbiamo impostato overflow: hidden, non siamo in grado di scorrere la pagina in orizzontale; in caso contrario, la pagina infatti scorrerà per visualizzare l'elemento con il focus.

Questo va bene, e si qualificherebbe, a mio parere, come "funzionale", benché non esattamente piacevole.

Anche il carosello di Netflix funziona in questo modo. Ma poiché la maggior parte dei loro titoli è caricato lentamente, e sono anche passivamente accessibili da tastiera (nel senso che non hanno scritto alcun codice specificamente per gestirlo), in realtà non possiamo selezionare qualsiasi titolo oltre i pochi che abbiamo abbiamo già caricato. Sembra anche terribile:

Keyboard Accessibility

Possiamo fare di meglio.

Gestire l'evento focus

Per fare questo, andremo ad ascoltare l'evento focus che si attiva su qualsiasi elemento nel carosello. Quando un elemento riceve il focus, eseguiremo una query per la sua posizione. Quindi, confronteremo quello con sliderX e sliderVisibleWidth per vedere se questo elemento è all'interno della finestra visibile. Se non lo è, lo impagineremo utilizzando lo stesso codice che abbiamo scritto nella parte 2.

Alla fine della funzione carousel, aggiungete questo listener di eventi:

Noterete che abbiamo messo a disposizione un terzo parametro, true. Piuttosto che aggiungere un listener di eventi per ogni elemento, possiamo usare ciò che è noto come event delegation per ascoltare gli eventi su un solo elemento, loro genitore diretto. L'evento focus non si propaga, quindi true sta dicendo al listener di eventi di attendere la fase di cattura, la fase in cui l'evento si attiva su ogni elemento da window fino all'obiettivo (in questo caso, l'elemento riceve lo stato focus).

Sopra il nostro blocco crescente dei listener di eventi, aggiungete la funzione onFocus:

Lavoreremo su questa funzione per il resto di questa sezione.

Abbiamo bisogno di misurare l'elemento offset left e right e verificare se qualsiasi punto si trova all'esterno dell'area attualmente visibile.

L'elemento è fornito dal parametro target dell'evento, e che possiamo misurare con getBoundingClientRect:

left e right sono relativi al viewport, non allo dispositivo di scorrimento. Quindi abbiamo bisogno di ottenere l'offset left del contenitore del carosello a cui dar conto. Nel nostro esempio, sarà 0, ma per rendere affidabile il carosello, dovrebbe dar conto di essere posizionato ovunque.

Ora, possiamo fare un semplice controllo per verificare se l'elemento è all'esterno dell'area visibile del dispositivo di scorrimento e impaginare in quella direzione:

Ora, quando usiamo la tabulazione, il carosello con fiducia impagina intorno con il focus della tastiera! Solo poche righe di codice per mostrare più amore verso i nostri utenti.

Rimisurare il carosello

Potreste aver notato mentre seguite questo tutorial che, se si ridimensiona la finestra del browser, il carosello non si impagina più correttamente. Questo è perché abbiamo misurato la sua larghezza relativa all'area visibile solo una volta, al momento dell'inizializzazione.

Per assicurarsi che il nostro carosello si comporti correttamente, abbiamo bisogno di sostituire un po' del nostro codice di misurazione con un nuovo listener di evento che viene generato quando window si ridimensiona.

Ora, vicino all'inizio della vostra funzione carousel, subito dopo la riga dove definiamo progressBar, vogliamo sostituire tre di queste misurazioni const con let, perché li cambieremo quando il viewport cambia:

Quindi, possiamo passare la logica che precedentemente ha calcolato questi valori a una nuova funzione di measureCarousel:

Vogliamo immediatamente richiamare questa funzione, quindi ancora impostiamo questi valori in fase di inizializzazione. Nella riga successiva, chiamate measureCarousel:

Il carosello dovrebbe funzionare esattamente come prima. Per aggiornare al ridimensionamento della finestra, aggiungiamo semplicemente questo listener di eventi alla fine della nostra funzione carousel:

Ora, se ridimensionate il carosello e provate l'impaginazione, continuerà a funzionare come previsto.

Una nota sulle prestazioni

Vale la pena considerare che nel mondo reale, si potrebbero avere più caroselli sulla stessa pagina, moltiplicando l'impatto sulle prestazioni di questo codice di misurazione per tale importo.

Come abbiamo discusso brevemente nella parte 2, non è saggio eseguire calcoli pesanti più spesso di quanto è necessario. Con il puntatore e gli eventi di scorrimento, dicevamo che volete eseguire quelli una volta per fotogramma per aiutare a mantenere i 60fps. Gli eventi di ridimensionamento sono un po' diversi di quelli che l'intero documento ridisporrà, probabilmente il momento più dispendioso di risorse che incontrerà una pagina web.

Non abbiamo bisogno di misurare nuovamente il carosello fino a quando l'utente ha finito di ridimensionare la finestra, perché non interagisce con esso nel frattempo. Possiamo inserire la nostra funzione measureCarousel in una funzione speciale denominata un antirimbalzo.

Una funzione antirimbalzo dice in sostanza: "Lancia questa funzione solo quando non è stato chiamata per oltre x millisecondi." Potete leggere di più circa l'antirimbalzo sull'eccellente guida di base di David Walsh e raccogliere anche qualche codice di esempio.

Ultimi ritocchi

Finora, abbiamo creato un carosello abbastanza buono. È accessibile, si anima bene, funziona attraverso il tocco e il mouse e fornisce una grande quantità di flessibilità di progettazione in un modo che i caroselli a scorrimento in modo nativo non consentono.

Ma questa non è la serie di tutorial "Creare un carosello abbastanza buono". È tempo per noi di vantarci, e per farlo, abbiamo un'arma segreta. L'elasticità.

Aggiungeremo due interazioni con l'elasticità. Una per il tocco e una per l'impaginazione. Entrambe vogliono comunicare all'utente, in un modo divertente e giocoso, che hanno raggiunto la fine del carosello.

Elasticità tattile

In primo luogo, aggiungiamo uno strappo in stile iOS quando un utente sta cercando di scorrere il dispositivo di scorrimento oltre i suoi confini. Attualmente, stiamo superando lo scorrimento touch utilizzando clampXOffset. Invece, sostituiamolo con del codice che applica uno strappo, quando la differenza calcolata è fuori i suoi confini.

In primo luogo, abbiamo bisogno di importare il nostro elastico. C'è un trasformatore chiamato nonlinearSpring che applica una forza che aumenta in modo esponenziale contro il numero che gli forniamo, verso un origin. Che significa che tanto più tiriamo il dispositivo di scorrimento, più si potrà tirare indietro. Possiamo importarlo così:

Nella funzione determineDragDirection, abbiamo questo codice:

Appena di sopra di esso, creiamo i nostri due elastici, uno per ogni limite di scorrimento del carosello:

Decidere su un valore di elasticity è una questione di giocare intorno e vedere quello che sembra giusto. Un numero troppo basso e l'elastico sembra troppo rigido. Troppo alto e non noterete il suo strappo o, peggio ancora, potrà spingere il dispositivo di scorrimento più lontano dal dito dell'utente!

Ora abbiamo solo bisogno di scrivere una semplice funzione che si applicherà a uno di questi elastici se il valore fornito è al di fuori dell'intervallo consentito:

Possiamo sostituire clampXOffset nel codice sopra con applySpring. Ora, se si tira il dispositivo di scorrimento oltre i suoi confini, si potrà tirare indietro!

Tuttavia, quando lasciamo andare l'elastico, una sorta di scatti lo porterà senza tante cerimonie di nuovo al suo posto. Vogliamo modificare la nostra funzione stopTouchScroll, che attualmente gestisce il momento dello scorrimento, per verificare se il dispositivo di scorrimento è ancora al di fuori dell'intervallo consentito e, in questo caso, applicare invece un elastico con l'azione physics.

Fisica dell'elasticità

L'azione physics è in grado di modellare anche l'elasticità. Dobbiamo solo fornirlo delle proprietà spring e to.

In stopTouchScroll, spostiamo l'inizializzazione dello scorrimento esistente di spring in un pezzo di logica che rende sicuro che siamo entro i limiti dello scorrimento:

All'interno della prima clausola dell'istruzione if, sappiamo che il dispositivo di scorrimento è fuori dai limiti di scorrimento, quindi possiamo aggiungere la nostra elasticità:

Vogliamo creare un'elasticità che sia elegante e reattiva. Ho scelto un valore relativamente alto per spring per avere uno "scoppio" tirato, e ho abbassato friction a 0.92 per permettere un piccolo rimbalzo. Potete impostarlo a 1 per eliminare completamente il rimbalzo.

Come compito, provate a sostituire clampXOffset nella funzione output dello scorrimento physics con una funzione che faccia scattare un'elasticità simile quando l'offset x raggiunge i suoi confini. Piuttosto che l'attuale fermata brusca, provate a farlo rimbalzare dolcemente alla fine.

L'elasticità della paginazione

Gli utenti tattili sempre la bontà dell'elasticità, giusto? Facciamo condividere quell'amore agli utenti desktop rilevando quando il carosello è nei suoi limiti di scorrimento, e avendo uno strappo indicativo per mostrare chiaramente e con sicurezza all'utente che è alla fine.

In primo luogo, vogliamo disabilitare i pulsanti della paginazione quando è stato raggiunto il limite. Innanzitutto aggiungiamo una regola CSS che dia stile ai pulsanti per mostrare che essi sono disabled. Nella regola button, aggiungete:

Stiamo usando una classe qui anziché l'attributo più semantico disabled perché abbiamo ancora voglia di catturare gli eventi cliccati, che, come suggerisce il nome, disabled bloccherebbe.

Aggiungete questa classe disabled al tasto Prev, perché ogni carosello inizia con un offset pari a 0:

Verso la parte superiore di carousel, create una nuova funzione denominata checkNavButtonStatus. Vogliamo che questa funzione controlli semplicemente il valore fornito per minXOffset e maxXOffset e imposti di conseguenza la classe del pulsante disabled:

Si sarebbe tentati di chiamarlo ogni volta che cambia sliderX. Se lo abbiamo fatto, i pulsanti inizierebbero a lampeggiare ogni volta che un elastico ha oscillato intorno ai confini di scorrimento. Porterebbe anche a uno strano comportamento se uno dei pulsanti è stato premuto durante una di tali animazioni di elasticità. Il tiro di "fine scorrimento" dovrebbe essere sempre generato se siamo alla fine del carosello, anche se c'è un'animazione di elasticità che lo distanzia dalla fine assoluta.

Quindi abbiamo bisogno di essere più selettivi su quando chiamare questa funzione. Sembra ragionevole chiamarla:

All'ultima riga di onWheel, aggiungete checkNavButtonStatus(newX);.

All'ultima riga di goto, aggiungete checkNavButtonStatus(targetX);.

E infine, alla fine del determineDragDirection e nella clausola all'impeto dello slancio (il codice all'interno di else) di stopTouchScroll, sostituite:

Con:

Ora tutto ciò che è rimasto è di modificare gotoPrev e gotoNext per controllare le classList del loro pulsante d'avviamento per disabled e impaginare solo se è assente:

La funzione notifyEnd è solo un'altra elasticità di physics, e assomiglia a questo:

Giocate con quello e ancora una volta, aggiustate il parametro di physics a vostro piacimento.

C'è solo un piccolo bug a sinistra. Quando il dispositivo di scorrimento salta oltre il suo confine più a sinistra, la barra di avanzamento è invertita. Possiamo rimediare rapidamente sostituendo:

Con:

Potremmo impedirgli il rimbalzo in altro modo, ma personalmente penso che è abbastanza fantastico che rifletta il movimento di elasticità. Sembra proprio strano quando si rimbalza dentro e fuori.

Rimettete in ordine

Con le applicazioni a pagina singola, i siti Web durano di più in una sessione utente. Spesso, anche quando cambia la "pagina", stiamo ancora facendo il runtime dello stesso JS come al caricamento iniziale. Non possiamo contare su una tabula rasa ogni volta che l'utente fa clic su un link, e ciò significa che dobbiamo rimettere in ordine per evitare di lanciare i listener di eventi su elementi morti.

In React, questo codice viene inserito nel metodo componentWillLeave. Vue utilizza beforeDestroy. Si tratta di una pura implementazione di JS, ma possiamo ancora fornire un metodo distruttivo che avrebbe funzionato ugualmente in entrambi i framework.

Finora, la nostra funzione carousel non ha restituito nulla. Cerchiamo di cambiarla.

In primo luogo, modificate la riga finale, la linea che chiama  carousel, con:

Restituiremo solo una cosa a carousel, una funzione che separa tutti i nostri eventi listener. Alla fine della funzione carousel, scrivete:

Ora, se si chiama destroyCarousel e provate a giocare con il carosello, non accade nulla! È quasi un po' triste vederlo così.

E questo è tutto

Accidenti. Era un sacco di roba! Quanto lontano siamo arrivati. Si può vedere il prodotto finito su questo CodePen. In questa parte finale, abbiamo aggiunto l'accessibilità da tastiera, rimisurando il carosello quando il viewport cambia, alcune divertenti aggiunte con la fisica dell'elasticità e il passo straziante ma necessario di farlo a pezzi nuovamente.

Spero che vi sia piaciuto questo tutorial tanto quanto mi sono divertito a scriverlo. Mi piacerebbe sentire i vostri pensieri su ulteriori modi con cui potremmo migliorare l'accessibilità, o aggiungere modi più divertenti.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.