Come realizzare una progress bar CSS3 per una HTML Mobile App
In altri articoli ho discusso l’importanza delle performance per quanto riguarda lo sviluppo di HTML mobile app tramite CSS3 e Javascript.
Durante la realizzazione di un’applicazione destinata a dispositivi mobile è importante sviluppare ogni effetto e animazione tenendo conto delle performance, fattore che su smartphone o tablet con sistemi operativi iOS, Android e Windows Phone diventa un vero e proprio must, se si vuole fornire all’utente un’interfaccia piacevole, fluida e reattiva.
In questo post voglio proporti il “modo performante” di realizzare una progress bar CSS3 con HTML5 e Javascript che risulti leggera ai fini del processo di rendering e piacevole all’occhio dell’utente, mentre egli interagisce con l’interfaccia.
Per capire meglio quali sono i punti chiave del codice CSS3, ma soprattutto la differenza visiva, ci soffermeremo su come scrivere la stessa animazione anche in modo poco performante.
Due progress bar CSS3 a confronto
Il mio principale intento con questo articolo, oltre quello di mostrarti diverse strade per realizzare lo stesso effetto, è sottolineare la differenza che si può avere agendo con due tecniche separate:
- quella che sfrutta la composizione dei layer grafici (alta performance e fluidità)
- quella che costringe il browser a ripetere l’intero processo di rendering per ogni keyframe dell’animazione (bassa performance e movimenti scattosi)
Al fine di comprendere meglio i concetti di processo di rendering e dei layer grafici ti consiglio di leggere rispettivamente questi due post (credimi, se sei un front-end developer ne vale proprio la pena):
- Come ottimizzare le animazioni per i dispositivi mobile
- Scrivere HTML Mobile App fluide con i layer grafici e l’accelerazione hardware
In questo esperimento realizzeremo quindi due progress bar CSS3, la versione fluida, e quella con scarse prestazioni.
Il markup HTML
Vediamo il (semplice) markup HTML delle due progress bar:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!-- Progress bar fluida e performante --> <div class="progress-box fast"> <div class="progress-inner"></div> <i class="fa fa-check"></i> </div> <!-- Progress bar scattosa e poco performante --> <div class="progress-box low"> <div class="progress-inner"></div> <i class="fa fa-check"></i> </div> |
In particolare usiamo la div con classe .progress-box come contenitore principale, il quale presenta al suo interno la barra che sarà animata (classe .progress-inner) e l’icona che mostreremo alla fine dell’animazione, per comunicare all’utente che l’operazione (qualunque essa sia) è andata a buon fine.
Come puoi vedere dal codice l’unica differenza tra le due progress bar sono le classi “fast” o “low” applicate al contenitore principale progress-box; è grazie ad esse che assegneremo ai due elementi DOM degli stili diversi per realizzare lo stesso tipo di effetto.
Gli stili CSS3
Impostiamo gli stili per il contenitore (progress-box), per la barra da animare (progress-inner) e per l’icona di completamento dell’operazione: alla prima attribuiamo la proprietà position:relative, mentre alla seconda e alla terza position:absolute, in modo da poterle muovere all’interno del contenitore con più facilità (utilizzando gli attributi “top“, “left” ):
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 |
.progress-box { position: relative; background: #3BB563; height:30px; width:300px; margin:20px auto; } /*progress bar*/ .progress-box .progress-inner { position: absolute; top: 0; left: 0; height: 100%; background: #0e7138; } /*icona dello stato completo della'animazione*/ .progress-box i{ position: absolute; top:7px; right:7px; color:#FFF; /* animazione molto leggera, sfrutta la creazione dei layers tramite le prop. opacity e transform, da caricare poi nella GPU; allo stato iniziale "nascondiamo" l'icona con l'opacity: 0 e la trasliamo "indietro" di 30px */ opacity:0; -webkit-transform: translateX(-30px); -moz-transform: translateX(-30px); -ms-transform: translateX(-30px); -o-transform: translateX(-30px); transform: translateX(-30px); } |
Allo stato iniziale l’icona, che non deve essere visibile fino al completamento dell’operazione, è stata impostata non visibile tramite la trasparenza (opacity:0) e traslata “indietro” di 30px tramite la proprietà CSS3 transform: traslateX(-30px) (con tutti i relativi prefissi del caso per la compatibilità).
Vediamo ora come animare la progressabar con classe low “alla vecchia maniera”, tramite codice poco perforemante:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
.progress-box.low .progress-inner { /* la larghezza iniziale allo 0%; sarà poi modificata tramite Javascript e portata al 100% */ width: 0; /* animazione pesante, sfrutta la proprietà width: il browser deve ripercorrere tutto il processo di rendering per ogni keyframe dell'animazione */ -webkit-transition: width 3s; -moz-transition: width 3s; -ms-transition: width 3s; -o-transition: width 3s; transition: width 3s; } |
Abbiamo agito sulla proprietà “width“, che fa parte del primo step del processo di rendering e che quindi costringe il browser a ripetere tale processo (eseguendo tutti gli step che lo compongono) ad ogni keyframe dell’applicazione, provocando un effetto di “sfarfallio”.
Passiamo ora invece a degli stili decisamente più performanti, quelli della progress bar con classe fast:
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 |
.progress-box.fast .progress-inner { /* la larghezza iniziale è gia al 100%; ma la prop. transform:scaleX è a 0; sarà poinportata tramite javascript al 100% della sua larghezza impostando il valore 1 */ width:100%; /* impostiamo l'origine della trasformazione, che di defualt sarebbe al 50%, ma noi vogliamo che inizi da sinistra (appunto 0) */ -webkit-transform-origin-x: 0; -moz-transform-origin-x: 0; -ms-transform-origin-x: 0; -o-transform-origin-x: 0; transform-origin-x: 0; -webkit-transform: scaleX(0); -moz-transform: scaleX(0); -ms-transform: scaleX(0); -o-transform: scaleX(0); transform: scaleX(0); /* animazione fluida e perfomante, sfrutta la proprietà transform, che fa parte dell'ultimo step del processo di rendering del browser, quello della creazione dei layer. Lo stile transform viene eseguito sulla memoria grafica (la GPU) separatamente */ -webkit-transition: -webkit-transform 3s; -moz-transition: -moz-transform 3s; -ms-transition: -ms-transform 3s; -o-transition: -o-transform 3s; transition: transform 3s; } |
Qui realizziamo l’animazione impostando la proprietà transition in modo da agire sul transform, per forzare la creazione dei layer grafici, i quali fanno parte del terzo step del processo di rendering. Così facendo la creazione dei relativi effetti viene delegata alla memoria grafica (la GPU).
Il codice Javascript
Passiamo ora al semplice codice javascript per gestire gli eventi di azione sui pulsanti che avviano e resettano l’operazione (“#start” e “#reset“):
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 50 51 52 53 54 |
$("#start").on("click", function(){ var fastProgressScale = "scaleX(1)"; /* progress bar performante: lavoriamo sulla prop. "transform" che fa parte del 3° step del processo di rendering, e forza la creazione di un layer da delegare alla GPU (alleggerisce il carico di lavoro) */ if(!$(".progress-box.fast").hasClass("complete")) $(".progress-box.fast .progress-inner") .css({ "-webkit-transform": fastProgressScale, "-moz-transform": fastProgressScale, "-ms-transform": fastProgressScale, "-o-transform": fastProgressScale, "transform": fastProgressScale }) .one(transitionEventName, function(){ $(".progress-box.fast").addClass("complete"); }); /* progress bar poco performante: lavoriamo sulla prop. "width" che fa parte del 1° step del processo di rendering */ if(!$(".progress-box.low").hasClass("complete")) $(".progress-box.low .progress-inner") .css("width", "100%").one(transitionEventName, function(){ $(".progress-box.low").addClass("complete"); }); }); $("#reset").on("click", function(){ //rimettiamo i due stati a 0 var fastProgressScale = "scaleX(0)"; $(".progress-box.fast").removeClass("complete") .find(".progress-inner").css({ "-webkit-transform": fastProgressScale, "-moz-transform": fastProgressScale, "-ms-transform": fastProgressScale, "-o-transform": fastProgressScale, "transform": fastProgressScale }); $(".progress-box.low").removeClass("complete") .find(".progress-inner").css("width", "0"); }); |
Al click del pulsante #start impostiamo semplicemente la proprietà width al 100% per la progress lenta, e la proprietà “transform:scaleX” ad 1 (che equivale al 100% ) per la progress fluida.
Al click del pulsante “#reset” riportiamo le due progress bar ai valori iniziali, avendo come risultato un’animazione con effetto contrario.
Conclusioni e considerazioni
Con la demo è possibile visualizzare la grande differenza tra la progress bar scritta in modo performante e quella scritta in modo poco performante: la prima risulta fluida e piacevole visivamente, mentre la seconda è scattante e presenta un notevole sfarfallio (ti consiglio di visualizzare l’esempio in un dispositivo mobile).
In un’eventuale HTML mobile app (ma anche in qualsiasi web app che sfrutta le funzionalità dei CSS3), impiegare più effetti con scarse performance, oltre ad una user-experience sgradevole, può provocare crash continui dell’applicazione, e incidere notevolmente sul giudizio che gli utenti attribuiscono al nostro prodotto (con conseguente impatto negativo sulla community).
Dall’altro lato invece, se scriviamo le nostre animazioni CSS3 in modo da sfruttare correttamente il lavoro della GPU, avremo come risultato un’applicazione piacevole, fluida e performante, e la differenza con quelle native sarà pressoché inesistente.
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: Progress bar CSS3 in HTML5 e Javacript per HTML...()
Pingback: Come realizzare un Mobile Action Sheet con Bootstrap 3 e Animazioni CSS3 | upCreative()