Come realizzare un HTML Mobile Slide Menu con Animazioni CSS3
Oggi riprendiamo il discorso delle performance per quanto riguarda le interfacce nei dispositivi mobile, che per caratteristiche hardware sono meno potenti di quelli desktop e riescono a supportare i processi di rendering in maniera molto più difficoltosa.
La strada scelta per realizzare un’animazione CSS3 influenza notevolmente la fluidità e la reattività con cui un dispositivo mobile riesce a metterla in atto, e scrivere gli stili in modo corretto permette di creare Applicazioni Mobile in HTML5 e Javascript che non hanno nulla da invidiare a quelle native.
A tal proposito ti consiglio di leggere:
- Performance CSS3: consigli per ottimizzare le prestazioni
- Web e Mobile App fluide con Hardware acceleration
Il tutorial di oggi: HTML Mobile Slide Menu
In questo tutorial ti voglio mostrare come creare un Mobile Slide Menu con effetto ease e con voci di navigazione animate, utilizzando stili CSS3 performanti e gestendo gli eventi tramite Javascript. Ogni voce di menu sarà animata con un leggero ritardo rispetto a quella precedente, in modo da creare un effetto più accattivante.
L’esperimento potrebbe essere benissimo integrato in una HTML5 Mobile App da utilizzare come versione mobile di un sito web o da distribuire nei vari store, compilandola tramite tools come Phonegap.
Premessa
Il risultato è ottimizzato per dispositivi mobile e le tecniche utilizzate (come l’accelerazione hardware e la composizione dei livelli grafici) sono suppurate solo dai browser di ultima generazione. Pertanto, se vuoi integrare il menu in un sito web, è opportuno attuare un’adeguata tecnica di Progressive Enhancement.
Per approfondire il discorso del Progressive Enhancement e per vedere come realizzare uno slide menu ottimizzato su tutti i browser, ti consiglio di leggere questo post:
Il markup HTML
Come primo passo impostiamo il markup HTML del documento, il quale prevede principalmente due elementi essenziali: il contenitore del menu (con al suo interno una lista di 4 voci) e quello dei contenuti dell’applicazione, rispettivamente rappresentati da un elemento <nav> con classe ‘menu’, e da un <div> con classe ‘content-wrapper’.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<nav class="menu"> <ul> <li> <a href="#"> <i class="fa fa-search fa-2x"></i> <span>Ricerca</span> </a> </li> <li> <a href="#"> <i class="fa fa-star fa-2x"></i> <span>Preferiti</span> </a> </li> <li> <a href="#"> <i class="fa fa-users fa-2x"></i> <span>Amici</span> </a> </li> <li> <a href="#"> <i class="fa fa-cog fa-2x"></i> <span>Impostazioni</span> </a> </li> </ul> </nav> <!-- contenuto dell'applicazione --> <div class="content-wrapper"> <section class="page"> <!-- pagina (o view dell'applicazione) --> <header> <!-- header della pagina --> <button class="toggle-menu"><i class="fa fa-bars fa-lg"></i></button> <h1 class="title">HTML Mobile App</h1> </header> <article class="text-center"> Conenuto pagina </article> </section> </div> |
Per realizzare il nostro HTML Mobile Slide Menu facciamo in modo di posizionare entrambi gli elementi DOM (‘.menu‘ e ‘.content-wrapper‘) tramite la proprietà position:absolute, per sovrapporre il contenitore dell’applicazione al menu.
Poi, avviando l’effetto slide, il contenitore sarà traslato orizzontalmente dello stesso numero di pixel che compongono la larghezza del menu (260px).
Andiamo quindi a vedere il codice CSS3 necessario per raggiungere tale obiettivo.
Gli stili CSS3
Innanzitutto posizioniamo i due elementi, attribuendo al contenitore uno z-index superiore a quello del menu:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
nav.menu { position: absolute; left: 0; width: 260px; height: 100%; top: 0; z-index: 1; background: #B8BDC5; } .content-wrapper{ position: absolute; top: 0; left: 0; height: 100%; width: 100%; z-index: 2; background-color: #4A5A6E; } /* ecco gli stili per il posizionamento di un'ipotetica pagina (o view) che si trova all'internod el contenitore su cui effettueremo l'effeto slide */ .content-wrapper > section.page{ position: absolute; top:0; left:0; width: 100%; height: 100%; } |
Attiviamo l’effetto slide-right, utile per rivelare il menu, impostando il foglio di stile in modo che basti aggiungere una classe all’elemento DOM:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
.content-wrapper { position: absolute; top: 0; left: 0; height: 100%; width: 100%; z-index: 2; background-color: #4A5A6E; /* impostiamo l'effetto di transizione sul contenitore della pagina/delle pagine del documento in modo da forzare la creazione dei layer grafici (accelerazione hardware) e rendere l'animazione più performante; il tutto riportando tutti i prefix per la compatibilità browser */ -webkit-transition: -webkit-transform .5s ease-in-out; -moz-transition: -moz-transform .5s ease-in-out; -ms-transition: -ms-transform .5s ease-in-out; -o-transition: -o-transform .5s ease-in-out; transition: transform .5s ease-in-out; } .content-wrapper.open-left { /* nel caso in cui venga aggiunta la classe 'open-left' avviamo l'effetto transition modificando la prop. transform e traslando in senso positivo tutto il contenuto di 260px, al fine di rivelare il menu nascosto sotto */ -webkit-transform: translate3d(260px, 0, 0); -moz-transform: translate3d(260px, 0, 0); -ms-transform: translate3d(260px, 0, 0); -o-transform: translate3d(260px, 0, 0); transform: translate3d(260px, 0, 0); } |
Agendo sulla proprietà di stile transition, richiamiamo, tramite il transform, un tipo di effetto che forza l’accelerazione hardware e quindi la composizione dei livelli grafici (il cui rendering è delegato alla GPU), alleggerendo così i carichi di lavoro e favorendo la fluidità dell’animazione.
Facciamo quindi la stessa cosa per gli elementi della lista del menu, che devono essere traslati anch’essi orizzontalmente e mostrati con una leggera dissolvenza:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
nav.menu ul li{ display: block; margin-bottom: 10px; opacity: 0.8; -webkit-transform: translate3d(-260px, 0, 0); -moz-transform: translate3d(-260px, 0, 0); -ms-transform: translate3d(-260px, 0, 0); -o-transform: translate3d(-260px, 0, 0); transform: translate3d(-260px, 0, 0); } /* facciamo in modo che le <li> della navigazione siano animate solo nel caso in cui l'elemento '.menu' abbia la classe 'animate li'; questo ci permette di animare ogni <li> solo quando il menu viene mostrato e non quando viene chiuso */ nav.menu.animate-li ul li{ -webkit-transition: all .5s ease-in-out; -moz-transition: all .5s ease-in-out; -ms-transition: all .5s ease-in-out; -o-transition: all .5s ease-in-out; transition: all .5s ease-in-out; } |
Dal codice puoi vedere che l’effetto transition viene attivato solo nel caso in cui all’elemento <nav> del menu venga aggiunta la classe ‘animate-li‘; questo è per animare gli elementi della lista solo nel caso in cui il menu venga aperto, e non durante l’azione di chiusura.
Per rendere l’effetto più accattivante aggiungiamo a tutti gli elementi della lista (tranne il primo) un leggero ritardo rispetto a quello precedente tramite la proprietà transition-delay:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* impostiamo i ritardi di animazione per gli elementi della lista */ nav.menu ul li:nth-child(2){ -webkit-transition-delay: .05s; transition-delay: .05s; } nav.menu ul li:nth-child(3){ -webkit-transition-delay: .08s; transition-delay: .08s; } nav.menu ul li:nth-child(4){ -webkit-transition-delay: .11s; transition-delay: .11s; } |
Impostiamo quindi la classe da giungere al menu per attivare l’animazione sulle 4 voci:
1 2 3 4 5 6 7 8 9 10 11 12 |
/* attiviamo l'animazione della transition agendo sulle proprietà 'scatenanti' */ nav.menu.open-left ul li{ opacity: 1; -webkit-transform: translate3d(0, 0, 0); -moz-transform: translate3d(0, 0, 0); -ms-transform: translate3d(0, 0, 0); -o-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } |
Infine, per inclinare graficamente ogni voce di menu, ci serviamo anche qui della proprietà tansform, tramite la funzionalità skew attivata agendo sull’asse delle Y:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
nav.menu ul a > span{ display: block; width:100%; height: 60px; background: #000; font-size: 20px; z-index: 1; text-transform: uppercase; font-weight: 400; padding:15px 10px 15px 75px; -moz-box-sizing: border-box; box-sizing: border-box; /* utilizziamo la proprietà 'skew' per effettuare un'inclinazione verticale per lo span (agendo sull'asse delle Y), usando come origine l'angolo in basso a sinistra per fare in modo che l'icona rimanga nella sua posizione rispetto allo span */ -webkit-transform-origin: 0 100%; -moz-transform-origin: 0 100%; -ms-transform-origin: 0 100%; -o-transform-origin: 0 100%; transform-origin: 0 100%; -webkit-transform: skew(0,-10deg); -moz-transform: skew(0,-10deg); -ms-transform: skew(0,-10deg); -o-transform: skew(0,-10deg); transform: skew(0,-10deg); } |
Poiché l’obiettivo era quello di inclinare tutta la voce ma non l’icona, ci siamo serviti di uno <span> posto all’interno del link a cui abbiamo attribuito uno sfondo nero e all’interno del quale abbiamo inserito il testo della rispettiva voce.
Questa tecnica ci ha permesso inoltre di applicare due trasformazioni diverse ad ogni voce di menu, in quanto non sarebbe stato possibile traslare ed inclinare contemporaneamente l’elemento <li> (la possibilità di impostare una sola trasformazione alla volta per ogni elemento è purtroppo una limitazione delle animazioni CSS3).
Il codice Javascript
Andiamo a gestire ora l’evento di click sul pulsante di apertura per aprire o chiudere il nostro Mobile Slide Menu:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
/* Grazie a modernizr riprendo il nome dell'evento di fine transizione, che cambia a seconda del browser */ var endTransitionName = { 'WebkitTransition' : 'webkitTransitionEnd', 'OTransition' : 'oTransitionEnd', 'msTransition' : 'MSTransitionEnd', 'transition' : 'transitionend' }; var transitionEventName = endTransitionName[ Modernizr.prefixed( 'transition' ) ]; $(function(){ var menuNav = $("nav.menu"); $(".toggle-menu").on("click", function(){ if(!menuNav.hasClass("open-left")){ /* se il menu di navigazione non ha la classe 'open-left' e quindi è chiuso, come prima cosa aggiungiamo la classe 'animate-li', che aggiunge le impostazioni per l'effetto di transizione, e poi la stessa 'open-left'; facciamo quindi lo stesso con il contenitore della pagina (classe 'content-wrapper') */ menuNav.addClass("animate-li"); $("nav.menu, .content-wrapper").addClass("open-left"); }else{ /* se il menu di navigazione è 'aperto', quindi presenta la classe 'open-left', come prima cosa rimuoviamo la classe 'animate-li' in modo da non scatenare l'animazione sulle <li> per la chiusura Poi rimuoviamo la classe 'open-left' SOLO al contentenitore, in modo da scatenare l'aniamzione di chiusura. AL termine di quest'ultima rimuoveremo la classe anche dal menu per ripristinare la posizione di partenza di ogni <li> */ menuNav.removeClass("animate-li"); $(".content-wrapper").removeClass("open-left").one(transitionEventName, function(){ menuNav.removeClass("open-left"); }); } }); }); |
Nel momento in cui il pulsante viene cliccato controlliamo se il menu è aperto o chiuso verificando la presenza o meno della classe ‘open-left‘ sull’elemento <nav>.
Se è chiuso, prima attiviamo gli effetti per le voci di menu aggiungendo la classe ‘animate-li‘ al contenitore del menu, poi avviamo le animazioni sia su di esso che sul contenitore delle pagine, aggiungendo ai relativi elementi la classe ‘open-left‘.
Se invece il menu è visible, rimuoviamo la classe ‘animate-li‘ dall’elemento <nav> per non scatenare l’animazione contraria sulle 4 voci, poi rimuoviamo la classe ‘open-left‘ dal contenitore in modo avviare l’effetto slide di chiusura, ed infine, una volta terminato quest’ultimo, riportiamo le voci di menu allo stato iniziale rimuovendo anche dall’elemento <nav> la classe ‘open-left’.
Per vedere come gestire gli eventi di fine transizione e animazione con Modernizr, ti consiglio di leggere questo articolo:
Conclusioni
Dalla demo puoi vedere come il risultato dell’esperimento sia un’animazione fluida e performante, priva di quei sfarfalli e crash che spesso caratterizzano le applicazioni HTML realizzate con framework come jQuery Mobile o jQtouch.
Due piccole note su questo tutorial:
- nel codice sopra riportato sono stati aggiunti i prefissi su proprietà come transition e transform per la compatibilità browser; tuttavia sviluppando solo per mobile sarebbe possibile omettere tutti i prefissi tranne quello per browser webkit-based (-webkit-)
- per avere un risultato ed una user-experience migliore sarebbe opportuno aggiungere il supporto per il touch, in modo da mostrare il menu durante l’azione di swipe dell’utente.
E tu? Hai mai realizzato delle applicazioni Mobile in HTML4, CSS3 e Javascript? Lascia un commento qui di seguito e fammi sapere le tue opinioni a riguardo!
Crea la tua mobile app in HTML, CSS3 e Javascript
Utilizzando questa tecnica insieme a molte altre, ho realizzato più di 10 mobile app in HTML, CSS3 e Javascript (tra cui Tint e Dieta SI o NO?).
Se anche tu vuoi realizzare la tua applicazione in HTML, CSS e javascript da distribuire nei vari store, forse potrebbe interessarti il mio e-book HTML Mobile Accelerato.
Giacomo Freddi
Web Designer Freelance e Developer, si occupa del design e dello sviluppo di applicazioni web dal 2008, come molti freelance è abituato a gestire più ruoli e spaziare su più campi, ma la sua passione principale è quella della creazione di interfacce front-end e back-end utilizzando codice html5 e css3. Adora usare pattern MVC per i suoi Javascript.
Pingback: Come realizzare un mobile slide menu con animaz...()
Pingback: HTML5 Mobile app: transizioni e animazioni CSS3 (parte 2) | Your Inspiration Web()