Una pagina web può essere arricchita facilmente con qualche effetto grafico usando del buon vecchio JavaScript. Esistono molte librerie in grado di ottenere ottimi risultati con relativamente poco sforzo, come ad esempio jQuery, Protoype e MooTools. ma non sempre abbiamo tempo o voglia di imparare ad usarli per inserire un singolo, semplice, abbellimento in una pagina. Un'alternativa molto semplice per ottenere gradevole effetti grafici è introdurre un delay (ritardo) tra alcune trasformazioni CSS o HTML.

Il concetto è semplice: se cambiamo l'aspetto di un elemento HTML, ad esempio in seguito ad un evento generato dall'utente, la trasformazione istantanea può risultare funzionale, ma difficilmente farà scatenare l'effetto wow. Basta rallentare l'esecuzione della trasformazione di stile per ottenere un gradevolissimo effetto di scomparsa, sfumatura, apparizione o addirittura movimento. Da un punto di vista cognitivo, l'llusione del movimento può infatti essere ottenuto mediante l'effetto stroboscobico (scoperto da Wertheimer all'inizio del '900): se spengo ed accendo delle “lucine” né troppo velocemente, né troppo lentamente, l'osservatore percepirà il fenomeno come movimento e non come accensione ritardata delle luci.

Imparare a gestire il delay in JavaScript può aiutarci a migliorare l'apparenza delle nostre pagine. Di seguito vedremo un semplice esempio di fading su un elemento HTML, ma il concetto può essere applicato per ottenere qualsiasi effetto o animazione.

La funzione setTimeout

La funzione permette di eseguire un'istruzione con il ritardo desiderato. Ad esempio

setTimeout('foo()',500) ;

eseguirà la funzione foo() circa mezzo secondo (500 millisecondi) più tardi rispetto all'istante in cui il processo “passa attraverso la riga” contenente l'istruzione stessa. Di primo acchito si potrebbe pensare di ottenere un effetto di fading scrivendo un codice come quello qui sotto

var delay = 80;

var the_array = new Array(

"#000000","#202020","#404040","#606060",

"#808080","#A0A0A0","#C0C0C0","#FFFFFF"

);

function setColor(obj, color) { obj.style.color = color; }

function fade() {

the_obj = document.getElementById("my_element") ;

for (var n=0 ; n<the_array.length ; n++) {

setTimeout('setColor(the_obj, the_array[n])',(n+1)*delay);

}

}

Ma il codice qui sopra non funziona. Il problema è che la funzione setTimeout rimanda l'esecuzione di tutte le chiamate a setColor, per cui le istruzioni “rimandate” verranno eseguite in un secondo tempo, alla fine del ciclo for. In pratica il nostro codice viene tradotto nella sequenza di istruzioni

setTimeout('setColor(the_obj, the_array[7])', 8*delay) ;

setTimeout('setColor(the_obj, the_array[7])', 8*delay) ;

ecc.

Infatti, quando le istruzioni “rimandate” vengono eseguite, il ciclo for è bello che finito, per cui la variabile n assume il valore 7 per tutte le chiamate! Anzi: se la variabile n è definita con scope all'interno del ciclo (come nel nostro esempio) essa non verrà nemmeno riconosciuta! Una soluzione potrebbe essere quella di implementare il fade scrivendo manualmente la sequenza corretta (al posto del ciclo for)

setTimeout('setColor(the_obj,the_array[0])',1*delay);

setTimeout('setColor(the_obj,the_array[1])',2*delay);

setTimeout('setColor(the_obj,the_array[2])',3*delay);

ecc.

la soluzione funziona, ma è poco elegante, scomoda, non performante e difficile da mantenere. Un modo corretto di ottenere l'effetto voluto è quello di accodare le istruzioni con il valore assunto dalla variabile n durante il ciclo, senza usare il simbolo n (che per la precisione si chiama l'identificatore della variabile). Questo si ottiene concatenando in modo opportuno gli elementi della chiamata alla funzione, ad esempio

setTimeout('setColor(the_obj, the_array['+n+'])',(n+1)*delay);

in questo modo, quando le varie istruzioni vengono accodate durante l'esecuzione del ciclo for, quello che viene accodato è il valore corrente della variabile n, anziché l'identificatore n. Il risultato è che le funzioni sono accodate proprio come nell'esempio qui sopra, quando abbiamo ipotizzato di scrivere la sequenza a mano, ovvero

setTimeout('setColor(the_obj,the_array[0])',1*delay);

setTimeout('setColor(the_obj,the_array[1])',2*delay);

setTimeout('setColor(the_obj,the_array[2])',3*delay);

ecc.

Riportiamo per completezza il codice corretto del ciclo for

 for (var n=0 ; n<the_array.length ; n++) {

setTimeout('setColor(the_obj, the_array['+n+'])',(n+1)*delay);

}

Il principio di accodamento vale anche quando si utilizzano dei framework JavaScript, ed imparare a domarlo ci tornerà utile se utilizziamo librerie di alto livello. La morale potrebbe essere: meglio tardi che mai.