A fronte di numerose richieste di spiegazioni, descrivo questa tecnica anche se non ha strettamente a che fare con Flash. Dal momento che è basata su javascript e css, più genericamente sul dhtml, per ogni tipo di delucidazione o miglioria il discorso andrebbe affrontato, se non in relazione alle basi, nei forum più adatti, come quelli dedicati all'Html o allo Scripting.
Il sistema è testato su più versioni dei principali browser, Netscape Navigator 4 e 6, Internet Explorer 5, 5.5 e 6, Opera 6: d'altronde, dal momento che l'utilizzo dei layer html è così diverso tra browser e browser, renderlo totalmente compatibile sarebbe un lavoro titanico.
Per la realizzazione dello script, mi sono basato su una funzione di Eddie Traversa presso DHTML Shock.com , sul sistema di gestione dei cookie, e sulla consulenza fattiva di ZofM e Saibal (lo script è abbastanza complesso ed elaborato).
Tutti i file che compongono l'esempio sono scaricabili da qui.
In tutto l'articolo, dove non diversamente specificato, quando parlo di layer intendo layer html.
<div id="logo" style="position:absolute; width:700px; height:115px; z-index:1"></div>
Effetto
Cliccando sul link, si apre l'esempio inserito in una pagina (parzialmente svuotata) di Flash-mx.it, per dare l'idea di come appaia su contenuti reali.
Gli utenti di Netscape (tutte le versioni) e Opera (tutte le versioni) non vedranno nulla di particolare, se non una semplice gif cliccabile in alto a sinistra, con il logo di Flash-mx.it
Al contrario, al primo accesso gli utenti di Internet Explorer vedranno un filmato in trasparenza sopra la pagina, che dopo una breve animazione andrà a posizionarsi in alto a sinistra a simulare l'immagine vista dagli altri browser. Ai successivi accessi, grazie ai cookies, vedranno anch'essi una semplice gif (inutile e fastidioso ripetere lo stesso effetto ad ogni apertura di pagina). Nell'esempio, la durata del cookie è di soli 10 secondi, dopo i quali apparirà di nuovo il filmato.
La differenza di comportamento tra browser, è dovuta al fatto che solo con Internet Explorer è possibile sfruttare il paramentro di trasparenza del fondo del filmato.
esempio su pagina con contenuti
esempio su pagina vuota
Struttura
Guardando il fla del filmato si può vedere in un layer(flash) guida, che rimane trasparente durante la riproduzione, un riquadro indicante la posizione finale che dovrà assumere il logo. Tutto ciò che c'è di flash è lì, nel decidere dentro il filmato dove andranno a posizionarsi gli oggetti. Nel caso volessimo inserire il logo, sotto forma di banner, in una colonna laterale, dovremmo semplicemente spostare il punto finale, al massimo allargando le dimensioni del filmato e del layer(html) che lo contiene.
Non sarebbero poi necessari altri ritocchi al codice javascript, dal momento che il problema è quello dell'allineamento orizzontale del layer (che deve seguire la tabella centrata del layout), e non quello verticale (scrollando la pagina con le relative barre, il layer e il suo contenuto rimangono nella posizione opportuna).
Html
Cominciamo a vedere il codice html della pagina contenente l'effetto: dal momento che è sempre lo stesso, in entrambi gli esempi, consiglio di guardare per chiarezza quello nella pagina vuota (in blu le parti notevoli):
<html>
<head>
<title>Esempio 1</title>
<script language="JavaScript1.2" type="text/javascript" src="script.js"></script>
</head>
<body bgColor=#D2D2D2 leftMargin=0 topMargin=0
marginwidth="0" marginheight="0" onLoad="setup(true);" onResize="setup(false);">
<div id="logo" style="position:absolute; width:700px; height:115px; top:0px; z-index:1">
</div>
</body>
</html>
Nell'head della pagina è inserito un riferimento al file *.js esterno contenente tutto lo script necessario. All'interno del tag body, sono contenuti i richiami alla funzione javascript setup, con due diversi parametri (true e false) a seconda dell'evento: onLoad (al caricamento della pagina) e onResize (al ridimensionamento).
Nel corpo della pagina, invece, c'è il codice del layer, posizionato in maniera assoluta, con z-index 1, di dimensioni 700*115 (altezza ininfluente), e con il nome logo come identificativo.
Sequenza JavaScript
Prima di vedere le funzioni javascript una ad una, seguiamo lo svolgimento dell'intera sequenza:
- all'apertura della pagina, viene determinato il browser con il quale si sta navigando
- in base al browser, si stabilisce la larghezza dell'area visibile (diversi metodi)
- in base alla larghezza, si stabilisce la posizione che dovrà avere il layer (diversi metodi)
- questo punto, si decide, sempre il base al browser, il contenuto del layer
- se il browser è netscape navigator, nel layer viene scritta una gif
- se il browser è internet explorer, si controllano i cookies
- se il cookie è presente, o i cookie non vengono accettati, viene scritta la gif
- se il cookie non è presente, viene inserito il filmato
- al ridimensionamento del browser, in explorer e netscape 6 viene semplicemente eseguita la funzione per l'allineamento. In netscape 4, invece, viene direttamente ricaricata la pagina (non è possibile riallineare il layer in base alle nuove dimensioni).
Funzioni
Le funzioni sono tutte contenute nel file script.js, recuperabile dallo zip: le vediamo non nell'ordine in cui sono scritte, ma nell'ordine logico della sequenza.
Prima funzione: Browser
function Browser() {
this.n4 = (document.layers) ? 1 : 0;
this.ie = (document.all) ? 1 : 0;
this.n6 = (document.getElementById) ? 1 : 0;
}
La funzione definisce una classe di oggetti. Le istanze create da questa classe avranno tre proprietà, n4, ie e n6, che avranno come valore 0 o 1. La funzione servirà a determinare il tipo di browser utilizzato, e a decidere quindi come agire: la distinzione è importante tra netscape 6 e 4, che funzionano in modo completamente diverso, e IE (le cui versioni invece sono giustamente più compatibili).
L'ordine di rilevamento (n4, ie, n6), non è influente in questa funzione particolare, ma lo sarà in altre per i motivi spiegati in questo articolo: Riconosciamo i browser con Javascript.
Seconda funzione: setup
function setup(prima){
bw = new Browser();
if(bw.ie) {
wdth = Math.round(document.body.clientWidth);
}else if(bw.n4 || bw.n6){
wdth = Math.round(window.innerWidth);
}
if(prima){
lay = new centra('logo', Math.round((wdth/2)-350));
DisplayInfo();
scrivi()
}else{
if(bw.n4){
location.reload();
}else if(bw.ie || bw.n6){
lay = new centra('logo', Math.round((wdth/2)-350));
}
}
}
La funzione setup, richiamata dall'onLoad e dall'onResize del tag body, riceve un parametro, true o false: in base al parametro, opera due sequenze diverse, appunto una adatta al caricamento, e una al ridimensionamento della pagina.
Più in dettaglio, viene creata un'istanza della classe Browser, chiamata bw. Come detto prima, l'istanza ha tre proprietà, n4, ie ed n6, e noi controlliamo se il valore è 0 o 1 (stessa cosa che true o false). Se è vera ie (ie va controllata prima di n6, perchè nel caso il browser sia Internet Explorer, risultano vere entrambe), allora la larghezza dell'area visibile viene stabilita in un modo, altrimenti (netscape) in un altro.
A questo punto, controlliamo il valore di prima (il parametro passato alla funzione): se è vera, e quindi siamo al caricamento della pagina, richiamiamo la funzione per il centramento del layer ( new centra ), controlliamo i cookies ( DisplayInfo ), e scriviamo il diverso contenuto nel layer ( scrivi ).
Se invece prima non è vera, e quindi siamo al ridimensionamento della pagina, se il browser è netscape 4 (scrivere if(bw.n4) è lo stesso che scrivere if(bw.n4 == 1)), ricarichiamo la pagina, altrimenti se il browser è explorer o netscape 6, semplicemente riallineiamo il layer (new centra ).
Quando chiamiamo la funzione centra, passiamo due parametri: il nome identificatore del layer ( logo ), e la larghezza dell'area visibile fratto 2 meno la metà delle dimensioni del layer, facendo lo stesso ragionamento dell'apertura di una popup centrata in base alla risoluzione del monitor.
Terza funzione: centra
function centra(id,left) {
if (bw.n4){
this.obj = document.layers[id];
}else if(bw.ie){
this.obj = document.all[id].style;
}else if(bw.n6){
this.obj = document.getElementById(id).style;
}
this.obj.left = (left>50) ? left : 50;
this.obj.top = 15;
return this.obj;
}
Questa funzione centra orizzontalmente il layer posizionandolo nel punto left passato dalla funzione setup: il riferimento al layer varia di browser in browser, quindi la funzione serve a stabilire il giusto percorso. In base al browser, nella proprietà this.obj viene inserito un diverso percorso, e poi usando this.obj come abbreviazione, vengono settate le proprietà top e left del layer.
Ad esempio, se il browser è Netscape Navigator 6, la riga
this.obj.top = 15;
corrisponde alla riga
document.getElementById("logo").style.top = 15;
Il top viene settato a 15, perchè 15 sono i pixel dall'alto necessari perchè il layer finisca verticalmente sopra la tabella del layout della pagina. Invece, la riga:
this.obj.left = (left>50) ? left : 50;
serve a centrare il layer finchè left è maggiore di 50, e a 50 in tutti gli altri casi (operatore ternario). Questo perchè se ridimensioniamo la pagina, ad esempio, fino a renderla larga 300 pixel, dall'operazione:
Math.round((wdth/2)-350)
otterremo un valore negativo, e in questo modo il layer uscirebbe dalla finestra sulla sinistra (e il logo uscirebbe dal layout). Con questo controllo, invece, quando siamo al limite massimo (40 è la larghezza in pixel della tabella laterale del layout, più 10 pixel di sicurezza), ci assicuriamo che il layer rimanga fermo.
Consiglio di provare per capire esattamente cosa succede. Allargando e stringendo la pagina, si può vedere come il layer si sposti verso destra o sinistra (rispetto al limite sinistro della pagina), in base alle dimensioni del browser. Ma riducendo le dimensioni oltre un certo limite, il layer non si sposta più (verso sinistra).
Quarta funzione: scrivi
function scrivi() {
var net = codice immagine
var exp = codice filmato
if (bw.n4) {
document.layers.logo.document.close();
document.layers.logo.document.write(net);
document.layers.logo.document.close();
}else if(bw.ie){
if(document.readyState == "complete"){
if(visitato || navigator.cookieEnabled == false){
eval("document.all.logo.innerHTML = net");
}else{
eval("document.all.logo.innerHTML = exp");
}
}else{
timerID = setTimeout("scrivi()",100);
}
}else if(bw.n6){
document.getElementById("logo").innerHTML = net;
}
Ho tagliato per ragioni di spazio il contenuto delle prime due righe: dove c'è scritto in blu "codice immagine" e "codice filmato", nel file *.js sono contenuti, tra virgolette, i codici di incorporamento della gif con il logo di Flash-mx.it, e del filmato swf. Da notare: all'interno dei codici di incorporamento, le virgolette vanno cambiate in apici, dal momento che stiamo definendo una stringa, e dobbiamo evitare incongruenze.
La funzione, come le precedenti, decide cosa fare in base al browser. Se è Netscape Navigator 4, usa questo codice per "scrivere" la gif nel layer (net è la variabile che contiene il codice della gif):
document.layers.logo.document.close();
document.layers.logo.document.write(net);
document.layers.logo.document.close();
Saltando all'ultimo if, se il browser è Netscape Navigator 6, usa un altro codice, sempre per scrivere la gif (ripeto, non si può inserire il filmato perchè il fondo, in Netscape, non può essere settato come trasparente):
document.getElementById("logo").innerHTML = net;
Tornando indietro, nel caso il browser sia Internet Explor, innanzitutto utilizziamo un metodo proprietario per verificare il completo caricamento della pagina:
if(document.readyState == "complete"){
...............
}else{
timerID = setTimeout("scrivi()",100);
}
Se il documento è completamente carico, la funzione esegue le azioni al posto dei puntini: altrimenti, la funzione richiama se stessa dopo una pausa di un decimo di secondo.
Ora, nel caso la pagina sia carica, abbiamo un'altra condizione:
if(visitato || navigator.cookieEnabled == false){
eval("document.all.logo.innerHTML = net");
}else{
eval("document.all.logo.innerHTML = exp");
}
Se la variabile visitato è vera (deriva dalla funzione per il controllo del cookie, e indica che abbiamo già visitato la pagina), oppure i cookie non sono abilitati (navigator.cookieEnabled), scriviamo nel layer il codice della gif, per non far vedere ogni volta il filmato all'apertura della pagina.
Se invece la pagina viene visitata per la prima volta, visualizziamo il filmato (contenuto della variabile exp).
Quinta funzione: DisplayInfo
function DisplayInfo() {
var expdate = new Date();
var visit;
// expdate.setTime(expdate.getTime() + (24 * 60 * 60 * 1000 * 365));
expdate.setTime(expdate.getTime() + (10 * 1000));
if(!(visit = GetCookie("dhtmlFlash"))) visit = 0;
visit++;
SetCookie("dhtmlFlash", visit, expdate, "/", null, false);
if(visit > 1){
visitato = true;
}else{
visitato = false;
}
}
Tralasciando le altre funzioni relative ai cookies, guardiamo solo la parte in blu di DiplayInfo.
Osservando la variabile visit estratta dal cookie (e che contiene il numero di visite effettuate), decidiamo se la variabile visitato debba essere vera o falsa. In base a questa variabile, come visto nella funzione precedente, decidiamo se scrivere nel layer la gif o il filmato quando il browser è Internet Explorer.
Opera
Vediamo adesso come adattare il tutto al browser Opera. Per vari motivi, dobbiamo inserire le funzioni nella pagina principale, e non nel js esterno.
<script language="JavaScript">
<!--
function caricamento() {
startW = this.innerWidth;
startH = this.innerHeight;
aggiornamento();
}
function aggiornamento() {
if (this.innerWidth != startW || this.innerHeight != startH) location.reload();
setTimeout('aggiornamento()',500);
}
//-->
</script>
Innanzitutto, nell'head della pagina ci sono adesso due funzioni, che servono incredibilmente a verificare il ridimensionamento della pagina, dal momento che Opera non gestisce l'evento onResize.
La prima funzione, richiamata all'avvio (se e solo se il browser è Opera), stabilisce le dimensioni della pagina, e le inserisce nelle variabili startW e startH. Poi, richiama la funzione aggiornamento, che ogni mezzo secondo verifica che le dimensioni della pagina non siano diverse da quelle iniziali. Se lo sono, ricarica la pagina (Opera non gestisce il reallineamento dei layer).
All'interno del layer, scriviamo quindi un codice javascript. Il codice verifica se il browser è Opera, e in quel caso, scrive direttamente nel layer il codice della gif (che ometto per ragioni di spazio), e richiama per la prima volta la funzione caricamento, per il controllo del resize.
<div id="logo" style="position:absolute; width:700px; height:115px; top:0px; z-index:1">
<script language="javascript">if(navigator.userAgent.indexOf("Opera") !=
-1){document.write(codice gif);caricamento();}</script></div>
Mettendo con un diverso stile la funzione:
<script language="javascript">
if(navigator.userAgent.indexOf("Opera") != -1){
document.write(codice gif);
caricamento();
}
</script>
Se all'interno della stringa restituita dal navigator.userAgent è presente la sottostringa "Opera" (e quindi stiamo visitando la pagina con Opera), la funzione scrive, tramite il document.write, il codice della gif direttamente dentro il layer, e poi chiama caricamento().
Notazioni finali
Un paio di notazioni importanti:
Come si può vedere in Internet Explorer, il filmato passa sotto il select di ricerca sulla sinistra, uno dei pochi casi in cui un filmato flash non copre in alcun modo un elemento della pagina (un altro caso sono le applet java).
Il metodo proprietario di Internet Explorer navigator.cookieEnabled, che dovrebbe restituire un flag sull'abilitazione dei cookie nel browser, funziona si e no solo sul manuale.. :-)