Questo articolo è stato pubblicato originariamente su Digital Web Magazine (http://www.digital-web.com). Appare qui in traduzione con il permesso dell'editore.
Titolo originale: Separating bahavior and structure
URL: http://www.digital-web.com/articles/separating_behavior_and_structure_2/
In un articolo precedente ho espresso un certo timore per quei "fanatici dell'accessibilità" che diventano nei fatti fieri oppositori di Javascript. Più di una volta ho riscontrato una reazione ostile all'idea stessa di usare questo linguaggio, sebbene questo atteggiamento sia per fortuna diffuso tra poche frange di sviluppatori web.
Questi avversari di Javascript espongono spesso concetti validi a sostegno delle loro tesi, ma non sono ben informati sui recenti sviluppi teorici del linguaggio. È giunto il momento di riconoscere che per certi versi essi hanno assolutamente ragione, di proporre un cambiamento nelle modalità di scrittura del codice e di porre fine una volta per tutte all'assurdità secondo cui "Javascript è il male".
Vedremo come si può separare l'azione (behavior) dalla struttura. Un fatto che dovrebbe convincere anche i più ostinati.
La scuola di pensiero anti-Javascript
Per iniziare un po' di storia. Inizialmente, la rivoluzione dei CSS non è avanzata in accordo e armonia con Javascript. Per due motivi:
- Con i CSS non è possibile creare livelli dinamici e simili. Dal momento che molti pensavano che un sito, per essere un buon sito, doveva essere complesso, e poiché i livelli dinamici sono straordinariamente complicati, la vecchia scuola di scripting ha mantenuto intatta la sua popolarità.
- D'altra parte, la teoria non aveva fatto sufficienti progressi per tenere conto di Javascript. I pionieri erano impegnati a separare la presentazione dalla struttura e ad esplorare le nuove frontiere dei CSS. Incorporare Javascript in questo nuovo approccio non era una priorità.
La combinazione di questi fattori ha fatto sì che nulla cambiasse. Gli sviluppatori web hanno continuato ad usare certe librerie-spazzatura che facevano compiere nei livelli di una pagina web tutte le funzioni che si possono compiere nella finestra di un normale sistema operativo -ovviamente senza aprire una nuova finestra. Ché sarebbe stata una specie di truffa!
Poiché questi script erano incredibilmente complicati, e le interfacce che generavano chiaramente inutili, i pionieri dei CSS smisero quasi tutti di usare questo tipo di Javascript. Lo hanno fatto con modi informali, non dogmatici, e in quel particolare momento avevano ragione. Quel tipo di Javascript era ormai fuori controllo.
Quella che doveva essere un atteggiamento temporaneo ha portato alla nascita di una scuola di pensiero anti-Javascript, che poi si è differenziata in un'ala moderata e in una radicale.
Gli avversari di Javascript sembrano voler sollevare quattro problemi intorno a questo linguaggio -sebbene io non abbia mai trovato un articolo che riuscisse a sintetizzarli tutti in maniera chiara e coincisa:
- Usabilità. Ci sono alcuni effetti Javascript davvero irritanti. Finestre popup, messaggi sulla barra di stato, livelli dinamici e simili possono risultare estremamente fastidiosi. Questo, però, non è un argomento contro Javascript. Il modo migliore per affrontare i problemi sollevati d questo tipo di script è non usarli.
- Accessibilità. Alcuni utenti non hanno sui loro browser il supporto Javascript (o non lo hanno abilitato). Penso che per questo problema la soluzione sia vicina. Da una questione di ordine generale -perché dovrei rendere accessibile il mio sito?- siamo passati ad una di tipo tecnico: come dovrei rendere accessibile il mio sito?
- Codice scritto male. Anche gli script utili possono avere un codice scritto molto male. Ciò significa che l'azione e la struttura non sono separati come si dovrebbe (è proprio l'argomento di questo articolo).
- Sovrapposizione. Con i CSS si possono implementare in maniera più elegante alcune funzionalità tradizionalmente realizzate con Javascript, come effetti di rollover e menu a tendina. Trovo questa idea interessante e ne parlerò nel mio prossimo articolo.
In questo, vorrei presentare al lettore una breve visita guidata nella moderna teoria su Javascript e una serie di tecniche di codifica innovative. Spero di dimostrare che questi problemi relativi all'uso di Javascript in siti moderni, basati su XHTML e CSS, possono essere risolti, e che non c'è motivo per non usare questo splendido linguaggio.
Cambiare la struttura del documento
Javascript rappresenta un'importante e potente aggiunta per pagine accessibili fatte con XHTML e CSS. Serve a migliorare l'usabilità del sito. Lo fa modificando leggermente la struttura XHTML del documento.
È stato soprattutto Simon Willison a fare un grande lavoro intorno a questo concetto. Il suo articolo "Enhancing Structural Markup with JavaScript" fornisce una serie di semplici e utili esempi di modifica della struttura XHTML con Javascript per migliorare l'usabilità senza sacrificare l'accessibilità.
Se si esaminano quegli esempi, si noterà che non offrono i tipici effetti sbalorditivi. Non spostano niente, non muovono niente, risultano poco invasivi sull'interfaccia, sono fondati su un markup solido e strutturale, non hanno nulla di quegli script fatti apposta per impressionare e stupire.
Ecco perché mi piacciono. Gli script di Simon fanno solo ciò che è necessario, e lo fanno solo modificando leggermente la struttura del documento. Inoltre, non richiedono pesanti librerie di 40kb e tonnellate di inutili oggetti.
Il mio script sui form usabili è basato sugli stessi principi, sebbene lo script stesso e i cambiamenti di struttura siano più complessi di quelli presenti negli esempi di Simon.
Script non invasivi
Il DHTML non invasivo di Stuart Langridge fissa alcuni punti cruciali sul modo in cui i menu DHTML dovrebbero e non dovrebbero essere fatti.
Parafrasando le idee di Stuart possiamo dire:
- Usabile. Uno script non dovrebbe risultare invasivo per l'utente. Niente roba strabiliante o livelli dinamici, solo piccoli benefici di usabilità che aiutino l'utente a orientarsi sul sito piuttosto che confonderlo.
- Accessibile. Uno script non dovrebbe risultare invasivo quando non funziona. Il sito non dovrebbe dipendere da quello script particolare per funzionare a dovere.
- Facile da implementare. Uno script non dovrebbe esssere invasivo per gli sviluppatori web. In genere, uno sviluppatore dovrebbe solo includere uno script e aggiungere una classe o un id ad uno o più elementi XHTML. Lo script interpreta tutto ciò in questo modo: "Applica l'azione in questo punto".
La terza idea di Stuart ci porta ad un passo molto importante, e lo stesso fanno gli articoli di Simon. Separano l'azione e la struttura.
Eppure, credo che Simon e Stuart non diano molta enfasi a questa separazione: ecco perché tenterò di spiegarla più approfonditamente. Vorrei però ricordare anche un piccolo passo che abbiamo compiuto quattro anni fa.
L'approccio da tag <FONT>
Quando i pionieri hanno iniziato a spiegare i vantaggi dei CSS, hanno usato il tag <FONT> come il simbolo di ciò che c'era di sbagliato nel vecchio modo di scrivere codice HTML. Questi tag erano davvero orribili, dovevano essere ripetuti su ogni <TD> cosicché il loro numero cresceva senza controllo, era facile sostituirli con i CSS.
Ecco perché hanno rappresentato un ottimo punto di partenza per la rivoluzione. Infatti, quando la quota di mercato di Netscape 3 scese abbastanza da rendere possibile l'uso dei fogli di stile, io ho abolito il tag <FONT> nella società per cui lavoravo. Quindi spiegai come sostituirli.
Certo, dopo quella scelta non sapevamo bene in che direzione muoverci. I browser non ci aiutavano e ci sfuggivano ancora i vantaggi di altri moduli dei CSS. Abbiamo spostato la definizione dei font nei CSS, continuando però ad usare le tabelle per il layout.
Eppure, ero riuscito ad introdurre con successo il concetto che sta alla base dei CSS. Abbiamo impiegato anni per affinare i dettagli, ma l'inizio fu positivo. Credo che altri abbiano iniziato allo stesso modo.
Ecco: quello che io propongo è di fare la stessa cosa con Javascript.
Fare pulizia
Ricordate quei maledetti menu con rollover?
<TR VALIGN=TOP><TD WIDTH="130" VALIGN=CENTER><IMG
src="arrow.gif height="32" width=130
name="clouds2"><TD><A HREF="clouds.html"
onMouseOver="setMouseOvers(this,'clouds','clouds2',false)"
onMouseOut="removeMouseOvers('clouds','clouds2',4)"
><IMG SRC="clouds.jpg" NAME="clouds"
width="125" HEIGHT="73"></A></TD>
<TR VALIGN=TOP><TD WIDTH="130" VALIGN=CENTER><
IMG SRC="spacer.gif" height="5" width=130><TD
valign=CENTER></TR>
<TR VALIGN=TOP><TD WIDTH="130" VALIGN=CENTER><IMG
src="arrow.gif height="32" width=130
name="turtles2"><TD><A HREF="turtles.html"
onMouseOver="setMouseOvers(this,'turtles','turtles2',false)"
onMouseOut="removeMouseOvers('turtles','turtles2',4)">
<IMG SRC="turtles.jpg" NAME="turtles"
width="125" HEIGHT="73"></A></TD>
[etc]
Alla fine ha prevalso il pensare in termini strutturali. Via tabelle per il layout,via gif da 1 pixel per creare spazio, si fa tutto con semplice XHTML:
<ul>
<li><a href="clouds.html"
onmouseover="setMouseOvers(this,'clouds',false)"
onmouseout="removeMouseOvers('clouds',4)">
<img src="clouds.gif" alt="Clouds" name="clouds"
id="clouds" width="125" height="73" />
</a></li>
<li><a href="turtles.html"
onmouseover="setMouseOvers(this,'turtles',false)"
onmouseout="removeMouseOvers('turtles',4)">
<img src="turtles.gif" alt="Turtles" name="turtles"
id="turtles" width="125" height="73" />
</a></li>
[etc]
In questo pezzo di codice XHTML non c'è nulla che specifica l'aspetto della lista di link: è così che si dovrebbe fare. Aspetto e presentazione si definiscono con i CSS, non con XHTML.
Questo codice però continua ad incorporare l'azione nella lista di link. La definizione dell'azione non scompare, e ci colpisce come un pugno in faccia. Diamoci un'occhiata:
onmouseover="setMouseOvers(this,'turtles',false)"
onmouseout="removeMouseOvers('turtles',4)"
È questo il codice pulito che dovrebbe trovare posto in una moderna pagina XHTML? È davvero un codice strutturale?
Facciamo piazza pulita di ciò che non ci serve e vediamo cosa accade:
<ul id="mouseovers">
<li> <a href="clouds.html">
<img src="clouds.gif" alt="Clouds"
width="125" height="73" /> </a> </li>
<li> <a href="turtles.html">
<img src="turtles.gif" alt="Turtles"
width="125" height="73" /> </a> </li>
[etc]
Molto meglio, vero? Ora nel codice XHTML abbiamo definito solo la struttura. Niente presentazione. Niente azione.
Separare l'azione dalla struttura
Io propongo di separare l'azione dalla struttura. Ora. Invito tutti gli svilppatori web a non inserire più istruzioni Javascript nei documenti XHTML. Come la definizione dell'aspetto dei font appartiene al livello della presentazione, in un file CSS, allo stesso modo la definizione di istruzioni di mouseover appartiene al livello dell'azione, e andrebbe inserita in un file Javascript. Nessuna delle due dovrebbe intaccare il livello della struttura impostato con XHTML.
Il processo può essere così rappresentato:
Questo approccio ha esattamente gli stessi vantaggi dell'inserire il livello della presentazione in un file .css esterno. Oltre ad un codice più pulito, consente di modificare facilmente il livello dell'azione nell'intero sito.
Se vogliamo creare un effetto rollover sull'immagine della nostra testata, basta aggiungere poche righe di codice in un file .js. È molto più comodo che inserire manualmente eventi onmouseover e onmouseout in ogni singola pagina.
Ovviamente dovremo collegare il livello dell'azione appena creato alla struttura, ovvero alla pagina XHTML. Inoltre dovremo far sì che certi elementi attivino le azioni definite nello script:
- Abbiamo bisogno di un tag <script> che inserisca il file .js nella pagina, proprio come con il tag <link> incorporiamo un file .css:
<script src="mouseovers.js" type="text/javascript"></script> - Dobbiamo trovare un modo per dire: "Aggiungi l'azione qui", proprio come con i CSS diciamo: "Usa questi stili in questo punto". Nell'esempio del rollover sarà sufficiente utilizzare un id="mouseovers", ma potremmo usare altri attributi, oppure aggiungere l'azione a tutti gli elementi <span> che non hanno una classe.
Esempi
La maggior parte delle istruzioni Javascript nei documenti XHTML sono gestori di eventi inseriti nel codice, come quelle dell'esempio sul rollover. Il passo più importante da compiere è rimuoverli dal codice XHTML.
Natuaralmente bisogna sostituirli con parti di codice che svolgeranno la stessa funzione - ma che non 'sporcano' la struttura -, proprio come si rimpiazza un <FONT FACE=verdana" SIZE=3> con un p {font: 12px verdana;}.
Definiremo, insomma, i gestori di eventi in modi alternativi, più corretti. Per far comprendere le basi di queste modifiche, presenterò quattro esempi. (Per capire al meglio gli esempi è consigliata una buona conoscenza dei gestori di eventi JavaScript, come quattro anni fa era necessario conoscere i fondamenti dei CSS per fare piazza pulita dei tag <FONT>. Cambiare le abitudini nella scrittura del codice significa spesso dover imparare cose nuove).
Esempio 1. Per assegnare alla nostra lista l'azione che attiva il rollover, usiamo questo codice. Esso va inserito, ovviamente, in un file .js:
function initMouseovers()
{
var nav = document.getElementById('mouseovers');
var imgs = nav.getElementsByTagName('img');
for (var i=0;i<imgs.length;i++)
{
imgs[i].onmouseover = mouseGoesOver;
imgs[i].onmouseout = mouseGoesOut;
}
}
Con questa funzione impostiamo il rollover e gli eventi onmouseover e onmouseout senza far ricorso a gestori di eventi incorporati nel codice. Quando l'utente passa con il mouse su un'immagine compresa nella lista con id="mouseovers" (<ul id="mouseovers">), viene richiamata la funzione mouseGoesOver(). Quando invece sposta il mouse fuori dall'immagine, viene richiamata la funzione mouseGoesOut().
Dobbiamo ancora definire il codice per queste due funzioni. Non l'ho incluso in questo articolo per ragioni di spazio. È comunque possibile studiare lo script di esempio che ho preparato sul mio sito. È semplice, funziona in tutti i browser moderni e non usa nessun gestore di eventi nel codice XHTML.
Esempio 2. Per assegnare un'azione a tutti gli elementi <span> che non hanno una classe, facciamo così:
function initSpanBehavior()
{
var spans = document.getElementsByTagName('span');
for (var i=0;i<spans.length;i++)
{
if (spans[i].className) continue;
spans[i].onsomeevent = doSomething;
}
}
Esempio 3. Dobbiamo ancora fare in modo che le funzioni initMouseovers() o initSpanBehavior() vengano eseguite al caricamento della pagina. Non lo faremo nel modo tradizionale:
window.onload = initMouseovers;
Per inizializzare le due funzioni, facciamo invece così:
window.onload = function () {
initMouseOvers();
initSpanBehavior();
}
(Ci sono alcuni problemi con l'approccio basato su window.onload, ma sono di natura tecnica non concettuale. Il codice riportato qui sopra illustra il concetto corretto. Inoltre, è sufficientemente sicuro per pagine semplici).
Esempio 4. Chris Heilmann fornisce l'esempio finale. Il suo articolo "Javascript navigation - cleaner, not meaner" spiega come assegnare azioni DHTML ad una navigazione basata su liste. Chris non tratta in particolare la parte DHTML, ma si concentra sulla separazione tra struttura e azione che rispetta l'accessibilità. (Ho duramente attaccato Chris quando ha scritto articoli non validi, così mi sembra corretto dargli il giusto credito quando ne scrive di buoni).
In effetti sostiene gli stessi cambiamenti nella scrittura del codice che sostengo io. Credo però che Chris, come Simon e Stuart, non sottolinei come si dovrebbe questa idea fondamentale.
Fare il primo passo
Secondo il mio parere, i recenti sviluppi nella teoria di Javascript dovrebbero portare alla rimozione dal codice XHTML dei gestori di eventi, cosa che continua ad essere fatta da molti sviluppatori e da tutti gli editor WYSIWYG.
Spostandoli in un file .js separiamo l'azione dalla struttura, così come con l'eliminazione del tag <FONT> è iniziata la separazione tra struttura e presentazione.
Sopra ho esposto i quattro problemi di Javascript. L'eliminazione dei gestori di eventi dal codice risolve il problema del codice scritto male. Il non usare script inutili risolve quello dell'usabilità. Sappiamo, infine, come affrontare il problema dell'accessibilità, anche se quest'ultimo non è ancora stato risolto. Spero che quanto scritto possa convincere gli avversari di Javascript che questo linguaggio sta facendo molti passi verso l'integrazione in pagine accessibili fatte con XHTML e CSS, e che non c'è motivo per evitarne l'uso.
Li invito anche a fare il primo passo, a provare ad aggiungere al sito un livello dell'azione non invasivo, a mettere in pratica la separazione tra azione e struttura, a prendere decisioni consapevoli sull'accessibilità.
E il problema della sovrapposizione? Dei CSS che possono imitare molte delle tradizionali funzioni di Javascript? In altre parole, è possibile separare l'azione dalla presentazione? Sarà l'argomento del mio prossimo articolo.
Peter-Paul Koch è uno sviluppatore web indipendente, mantiene il sito Quirksmode.org. È anche Amministratore delle mailing list WDF e WDF-DOM.