Banner dinamico espandibile cross-browser Mi sono imbattuto spesso ultimamente in banner espandibili su vari siti internet ed anche in articoli su alcune riviste di settore. Purtroppo quasi tutti soffrivano di un difetto che a me non va giù: erano pensati e fatti solo per funzionare con Internet Explorer, magari addirittura per le versioni più recenti e causavano errori a runtime o non funzionavano affatto con Mozilla ed altri browser che uso per testare i miei script. Da qui l'idea di realizzarne uno per i miei lettori e vedere se effettivamente è così difficile per queste agenzie di advertising realizzare effetti come questo che siano funzionanti con tutti i browser in grado di utilizzare i livelli. Leggendo questa scheda scopriremo che non è affatto difficile ottenere il risultato, e mi viene da pensare e dubitare della qualità del servizio che queste agenzie forniscono ai loro clienti, dubbi a maggior ragione legittimi considerando la crisi del settore. Tutto quel che ci serve è un'immagine, il banner, normalmente collegato con un link A HREF ed un livello a posizione fissa che andrà opportunamente riposizionato. Ovviamente useremo l'event-handler onmouseover sul link per attivare il livello, e l'opposto onmouseout sul link nello stesso livello per farlo scomparire: . . . . . . . . . Il link al sito pubblicizzato sarà ovviamente posizionato sia sul banner grande che su quello normale, in modo che possa essere utilizzato anche da chi usa un browser non compatibile con la gestione dei livelli. Il banner "normale" che nell'esempio è un banale 468x60 verrà immerso nel documento come di consueto, io l'ho semplicemente messo all'inizio del secondo paragrafo ed ho aggiunto un align='right' per spostarlo al margine destro della pagina.. Il tag DIV del livello che contiene l'immagine grande sarà invece preferibilmente posizionato alla fine del documento, prima del tag in modo che non interferisca con gli altri elementi della pagina neanche in fase di download, visto che sarà ovviamente un'immagine più pesante in termini di KByte. Lo stile assegnato al livello, invece, lo posiziona in alto a sinistra (position:absolute ... top:0 ; left:0 ... ) La gestione dell'effetto è a cura della funzione BannerToggle() che in automatico rileverà lo stato attuale di visibilità del livello mostrandolo quando il mouse è sul banner piccolo, e rinascondendolo quando il mouse lascerà l'immagine grande.. Vediamo lo script (due linee sono spezzate solo per impaginazione): var DynaBanner=false; var DynaBannerStato=""; var DynaBannerModifica=""; function BannerStart() { var n4 = document.layers?true:false; var d2 = document.getElementById?true:false; var ie4 = document.all?true:false; var BigBannerObj=n4?document.layers.bigbanner:d2?document.getElementById("bigbanner").style:document.all.bigbanner.style; var SmallBannerObj=document.smallbanner; if (n4) { BigBannerObj.top=SmallBannerObj.y; BigBannerObj.left=SmallBannerObj.x; DynaBannerStato="document.layers.bigbanner.visibility=='show'"; DynaBannerModifica="document.layers.bigbanner.visibility=eval(DynaBannerStato)?'hidden':'visible'"; } else { BigBannerObj.top=SmallBannerObj.offsetTop; BigBannerObj.left=SmallBannerObj.offsetLeft; DynaBannerStato=d2?"document.getElementById('bigbanner').style.visibility=='visible'": [... ..."document.all.bigbanner.style.visibility=='visible'"; DynaBannerModifica=d2?"document.getElementById('bigbanner').style.visibility=eval(DynaBannerStato)?'hidden':'visible'": [... ..."document.all.bigbanner.style.visibility=eval(DynaBannerStato)?'hidden':'visible'"; } DynaBanner=parseInt(navigator.appVersion)>=4; onresize=BannerStart; } function BannerToggle() { if (DynaBanner) eval(DynaBannerModifica); } onload=BannerStart; La prima variabile globale (DynaBanner) servirà per far scattare o impedire la visualizzazione del livello, il valore predefinito (false) impedisce il funzionamento. Delle altre due variabili, invece, la prima servirà per rilevare lo stato del livello e la seconda per modificarne la visibilità. Lo script inizia a funzionare quando il caricamento del documento sarà completato, e ciò grazie all'istruzione onload=BannerStart nell'ultima riga. Notiamo che finché questa funzione non scatta la variabile DynaBanner resta al valore false quindi se l'utente passa sul banner piccolo non verrà visualizzato il livello. Il motivo di questa scelta è semplice: non avendo stabilito a priori una posizione per il banner piccolo, che è stato immerso nel documento senza preoccuparci di questo aspetto, non possiamo sapere dove visualizzare il livello finché il documento non sarà completamente renderizzato dal browser, e se facessimo comunque visualizzare il livello si troverebbe inevitabilmente in alto a sinistra nella finestra. Quando scatta onload viene eseguita la funzione associata BannerStart(). Dovendo lavorare di DHTML inizia come di consueto col determinare il browser in cui sta lavorando discernendo fra Netscape 4, browser che supportano il DOM 2 (IE5+/Mozilla/N6+ etc.), ed IE4; nel primo caso dovremo usare document.layers per accedere al livello, nel secondo document.getElementById, nel terzo caso document.all. Fatto questo nella variabile BigBannerObj viene referenziato il livello con le solite istruzioni che abbiamo visto varie volte. All'ultima variabile (SmallBannerObj) associamo l'immagine del banner piccolo referenziandola come facciamo normalmente per qualsiasi immagine, tipicamente nei rollover. Da qui in poi la funzione si spezza fra Netscape4 e gli altri browser perché abbiamo bisogno di istruzioni diverse per rilevare la posizione del banner piccolo: x/y per N4 e offsetLeft/offsetTop per gli altri. Nelle due sezioni della if () ... else () viene per prima cosa riposizionato il livello, poi vengono valorizzate le due variabili globali viste all'inizio dello script. Lo stato del livello viene determinato automaticamente confrontandolo con lo stato di visibilità, quindi "show" per N4 e "visible" per gli altri.. Notiamo che in questa funzione non lo stiamo effettivamente determinando, ci limitiamo a memorizzare in una variabile l'istruzione necessaria. La variabile verrà infatti eseguita in un secondo tempo tramite eval() che, com'è noto, accetta come argomento una stringa contenente le istruzioni JavaScript da eseguire: eval("alert('Riccardo')") è equivalente a fare alert('Riccardo') con la differenza che la stringa (l'alert) possiamo costruirla prima di eseguirla. Nella riga successiva infatti (sempre delle due porzioni dell'if ()) troviamo le classiche istruzioni che cambiano lo stato di visibilità di un livello sempre, a loro volta, memorizzate in un'altra variabile: DynaBannerModifica. In uscita dalla if() la variabile DynaBannerModifica conterrà una stringa equivalente a questa: DynaBannerModifica="document.layers.bigbanner.visibility=document.layers.bigbanner.visibility=='show'?'hidden':'visible'"; il solito uso dell'operatore ternario cambierà lo stato di visibilità del livello in base allo stato attuale: se document.layers.bigbanner.visibility=='show' sarà true la visibilità passerà a 'hidden' altrimenti a 'visible'. Stesso discorso per gli altri browser, con la sola differenza che in base al valore di d2 (vera solo se il browser accetta document.getElementById) verrà usata una o l'altra sintassi. La funzione si chiude valorizzando definitivamente la variabile DynaBanner che sarà true solo se la versione del broser è maggiore o uguale a 4, quindi solo se il browser è in grado di gestire i livelli, e con l'attivazione di un altro event-handler (onresize=BannerStart) che rieseguirà la funzione se la finestra viene ridimensionata, questo al fine di riposizionare il livello nella nuova posizione assunta dal banner piccolo. La funzione successiva è quella attivata dagli event-handler onmouseover/onmouseout nei links dei due banner, se DynaBanner è true viene eseguita l'istruzione successiva eval(DynaBannerModifica) che a sua volta esegue il codice memorizzato nella variabile/stringa che abbiamo appena visto. Variabile che non verrebbe eseguita se DynaBanner fosse false (ad esempio lo script sta girando in IE3). Il codice in DynaBannerModifica funziona in pratica in questo modo (faccio sempre riferimento al codice per N4 per comodità): quando il mouse passa sopra al banner piccolo document.layers.bigbanner.visibility=='show' sarà false e l'operatore ternario ? : eseguirà questo codice: document.layers.bigbanner.visibility='visible' mostrando il banner. Visto che il livello con il link dell'immagine grande copre il banner piccolo, nessun altro evento verrà più catturato su quest'ultimo ed il mouse si ritroverà posizionato sul banner grande il cui link farà scattare di nuovo la BannerToggle() al mouseout. Viene di nuovo eseguita la stringa DynaBannerModifica, ma ora il risultato di document.layers.bigbanner.visibility=='show' sarà false (il livello è in quell'istante visibile) ed in definitiva DynaBannerModifica conterrà l'istruzione document.layers.bigbanner.visibility='hidden' che nasconderà il livello, sempre che l'utente non abbia cliccato sul banner e quindi non sia approdato al sito collegato. Ancora una volta lo script è più complesso da commentare di quanto effettivamente sia complicato. Ho usato eval() solo a fini didattici in quanto avrei potuto spostare tutti gli if() e ? : nella BannerToggle() ottenendo ugualmente l'effetto voluto, ma poi ogni volta l'interprete JavaScript avrebbe dovuto scegliere una sintassi fra le tre per rilevare lo stato di visibilità del livello, ed ancora una fra le tre per cambiare di stato.. Invece costruendo le istruzioni in una stringa ho ottenuto uno script più veloce e performante, un obiettivo questo che nel nostro caso non ha molto senso avendo risparmiato un solo salto condizionale, ma che in script più complessi anderebbe invece tenuto in considerazione. http://www.jsdir.com/staffscripts/script082.asp