Séparer le comportement de la structure
Par Peter-Paul Koch
Dans ma chronique précédente, j'émettais certaines réserves sur les "fanatiques de l'accessibilité" qui sont en fait des fanatiques anti-Javascript. Plus d'une fois j'ai constaté une hostilité à l'idée d'utiliser le moindre Javascript, bien qu'heureusement cette attitude reste confinée aux franges du développement Web.
Ces anti-Javascripts avancent quelques arguments justes, mais ils ne sont pas bien
informés des avancées récentes dans la théorie de Javascript. Il est temps de concéder
qu'ils ont entièrement raison sur certains points, de proposer un changement dans les habitudes de
programmation, et de faire disparaître une fois pour toute cette absurde notion selon laquelle le Javascript, c'est mal.
Nous allons séparer le comportement de la structure. Voilà qui devrait convaincre même les irréductibles.
L'école de pensée anti-Javascript
Tout d'abord, un peu d'histoire. Au départ, la révolution CSS ne s'entendait pas vraiment avec Javascript. Il y avait deux raisons à cela :
- Il n'est pas possible de créer des calques mobiles et autres en CSS. Beaucoup de gens croyaient qu'un site devait être complexe pour être bon, et comme les calques mobiles étaient étonnemment compliqués, le scripting traditionnel garda sa popularité.
- La théorie n'avait pas encore progressé suffisamment pour prendre en compte Javascript. Les pionniers étaient occupés à séparer la présentation de la structure et à explorer les frontières de CSS. Incorporer le Javascript à ce nouveau mode de pensée n'était pas une priorité.
Combinés, ces facteurs constituèrent un obstacle effectif au changement. Les développeurs web continuèrent à utiliser des bibliothèques de Javascript chaotiques qui faisaient habilement remplir aux calques toutes les fonctions d'une fenêtre normale de l'OS -- sans, bien sûr, ouvrir une nouvelle fenêtre. Ce serait tricher.
Ces scripts étaient si compliqués, et les interfaces qu'ils créaient si ostensiblement inutiles, que les pionniers du CSS arrêtèrent largement d'utiliser du Javascript élaboré. Ils en arrivèrent là de façon informelle, non dogmatique, et à ce moment donné ils avaient raison. Le Javascript de pointe avait proliféré de façon insensée.
Cette mesure essentiellement temporaire conduisit à la naissance de l'école de pensée anti-Javascript, qui se divisa à terme en une aile modérée et une aile radicale.
Les anti-Javascript semblent avoir quatre problèmes avec Javascript -- bien que je n'aie en fait jamais trouvé d'article exposant ceux-ci de façon claire et concise :
- Ergonomie. Il y a un certain nombre d'effets Javascript irritants. Les popups, les messages dans la barre d'état, les calques animés et autres effets du même acabit, peuvent être extrêmement ennuyeux. Cela dit, ce n'est pas un argument contre Javascript dans son ensemble. La meilleure façon de traiter ces scripts est de ne pas les utiliser.
- Accessibilité. Certains utilisateurs n'ont pas (activé) Javascript. Je pense que ce problème est en passe d'être résolu. Un problème fondamental -- pourquoi devrais-je rendre mon site accessible ? -- s'est transformé en technique : comment puis-je rendre mon site accessible ?
- Laideur. Même les scripts utiles peuvent nécessiter un code vraiment laid. Cela signifie en fait que le comportement et la structure ne sont pas séparés proprement, et c'est le sujet de cet article.
- Chevauchement. CSS peut remplacer certaines fonctions traditionnelles de Javascript, comme les survols de souris et les menus déroulants. Je trouve l'idée intéressante et j'en discuterai dans ma prochaine chronique.
Cette chronique propose une rapide visite guidée de la pensée Javascript moderne, et une innovation simple en matière de techniques de programmation web. J'espère vous montrer que ces problèmes relatifs à l'utilisation de Javascript -- dans les sites modernes en XHTML/CSS -- peuvent être résolus, et qu'il n'y a aucune raison fondamentale de ne pas utiliser ce beau langage.
Changer la structure du document
Javascript est un complément puissant aux pages par ailleurs accessibles en XHTML/CSS. Il sert à améliorer l'ergonomie d'un site. Mieux, il le fait en changeant subtilement la structure XHTML.
Simon Willison, en particulier, a fait du bon travail sur ce concept. Son Améliorations de balisages structurels avec JavaScript donne des exemples simples et utiles de modifications de structures XHTML avec Javascript, pour ajouter de petites touches d'ergonomie à votre site sans sacrifier l'accessibilité.
Si vous parcourez ses exemples, vous remarquerez qu'ils ne sont pas voyants. Ils ne déplacent ou n'agitent rien, ils ne malmènent pas les interfaces, ils reposent sur un balisage solide et structuré, et ils manquent cruellement de tous ces artifices qui impressionnent le débutant.
C'est bien pour cela que je les aime tellement. Les scripts de Simon font seulement ce qui doit être fait, et ils le font toujours en ne modifiant que très légèrement la structure du document. De plus, ils n'exigent pas des bibliothèques de 40ko et des flopées d'objets inutiles.
Mon propre script de formulaires ergonomiques est basé sur des principes similaires, bien que le script lui-même et les modifications qu'il apporte à la structure du document sont plus complexes que les exemples de Simon.
Scripting discret
Le DHTML discret de Stuart Landridge assène quelques vérités sur ce que les menus DHTML devraient être ou pas.
Je paraphrase les idées de Suart comme suit :
- Ergonomique. Un script devrait être discret pour l'utilisateur. Pas de trucs voyants ou de calques animés, juste un petit bénéfice au niveau de l'ergonomie, qui aidera les utilisateurs à retirer quelque chose de leur visite plutôt que de les gêner.
- Accessible. Un script devrait être discret lorsqu'il ne fonctionne pas. Le site ne devrait pas dépendre du script.
- Facile à implémenter. Un script devrait être discret pour
les développeurs web. Typiquement, un développeur web ne devrait avoir qu'à inclure un script et à ajouter une
class
ou unid
à un ou plusieurs éléments XHTML, que le script interprèterait comme :applique tel comportement ici
.
Le dernier principe de discrétion de Stuart fait un pas en avant très important, et l'article de Simon fait de même. Ils séparent le comportement de la structure.
Néanmoins, je trouve que Simon et Stuart ne mettent pas assez l'accent sur cette séparation, c'est pourquoi je vais l'expliquer plus en détail. Parallèlement, j'aimerais vous rappeler une avancée similaire que nous avons fait voici quatre ans.
L'approche <FONT>
Quand les pionniers ont commencé à expliquer les avantages de CSS, ils ont utilisé les balises <FONT>
comme symbole de ce qui n'allait pas avec l'ancien HTML. Ces balises étaient extrêmement laides, elles devaient être répétées dans chaque <TD>
, multipliant leur nombre au-delà de tout contrôle, et elles étaient faciles à remplacer par des CSS.
C'est pourquoi elles ont constitué un excellent point de départ pour la révolution. En fait,
quand la part de marché de Netscape 3 est devenue suffisamment faible pour commencer à utiliser CSS, j'ai sommairement banni les balises <FONT>
de l'entreprise où je travaillais. Puis, j'ai expliqué comment les remplacer.
Bien sûr, à cette époque, nous ne savions pas vraiment quoi faire de plus. Les navigateurs n'étaient pas ce qu'on pouvait appeler coopératifs, et les subtilités des modules les plus complexes de CSS nous échappaient encore. Nous avons déplacé les définitions de polices dans des fichiers CSS, mais nous avons continué à utiliser des mises en pages en tableaux.
Néanmoins, j'avais introduit avec succès le concept de CSS. Bien qu'il nous a fallu des années pour en maîtriser les détails, c'était un premier pas. Je suppose que les autres développeurs web ont commencé de la même manière.
Je propose de faire un premier pas similaire pour Javascript.
Nettoyer le désordre
Vous souvenez vous de ces rollovers infernaux ?
<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]
La pensée structurelle a prévalu. Les maquettes-tableaux et les gifs d'espacement ont pris la porte, remplacés par du simple 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]
Cet extrait de code XHTML ne spécifie pas la présentation de la liste de liens, et c'est bien ainsi. La présentation est le travail de CSS, pas de XHTML.
Toutefois, le code spécifie le comportement de la liste de liens. En fait, les horribles définitions de comportement nous sautent au visage. Jetez-y un oeil :
onmouseover="setMouseOvers(this,'turtles',false)" onmouseout="removeMouseOvers('turtles',4)"
Peut-on appeler ceci du code propre qui se glisserait élégamment dans une page XHTML moderne ? Respecte-t-il pleinement la sémantique ?
Débarrassons-nous des déchets et voyons ce qu'il advient :
<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]
C'est beaucoup mieux, vous ne trouvez pas ? Le XHTML crée maintenant la structure, et uniquement la structure. Pas de présentation. Pas de comportement non plus.
Séparer le comportement de la structure
Je vous propose de séparer le comportement de la structure. Ici et maintenant.
J'invite tous les développeurs web à arrêter d'écrire les instructions Javascript dans des fichiers XHTML.
Tout comme les définitions de polices appartiennent à la couche de présentation, dans un fichier CSS, les définitions de rollover appartiennent à la couche de comportement, dans un fichier Javascript. Aucune d'entre elles ne devrait encombrer la couche structurelle XHTML.
Le processus est très simple :
Une fois ceci effectué, vous avez placé la couche de comportement là où elle doit
être, dans un fichier .js
externe.
Ce déplacement présente exactement les mêmes avantages que le placement de la couche de
présentation dans un fichier .css
externe. En plus de créer un code plus propre,
la couche de comportement devient facilement modifiable sur tout votre site.
Si vous voulez que votre image d'en-tête réagisse elle aussi au survol de la souris,
il suffit d'ajouter quelques lignes au fichier .js
. C'est bien plus efficace
que d'insérer manuellement des gestionnaires d'événements onmouseover
et
onmouseout
dans chaque page de contenu.
Bien sûr, vous devez associer cette couche de comportement nouvellement créée à la couche structurelle XHTML, et marquer certains éléments comme ayant un comportement spécifique :
-
Vous avez besoin d'une balise
<script>
liant votre fichier.js
à la page, exactement comme une balise<link>
lie votre fichier.css
:<script src="mouseovers.js" type="text/javascript"></script>
-
Il vous faut une manière de dire "Ajoute le comportement ici", tout comme CSS nécessite une manière de dire "Utilise ce style ici". Dans l'exemple du rollover, le
id="mouseover"
remplit cette fonction, mais vous pouvez aussi utiliser d'autres attributs, ou ajouter un comportement, disons, à tous les<span>
qui n'ont pas declass
.
Le dernier point nécessite de structurer soigneusement votre XHTML, mais vous devriez le faire de toute façon.
Exemples
La majorité des instructions Javascript dans les fichiers XHTML sont des gestionnaires d'événements en-ligne comme ceux de l'exemple du rollover. Enlever ceux-ci est donc la mesure la plus importante que vous devez prendre.
Bien sûr, il faut les remplacer par des structures de code qui remplissent
la même fonction -- mais qui ne gâchent pas votre XHTML -- tout comme vous avez dû remplacer <FONT
FACE="Verdana" SIZE=3>
par p { font: 12px verdana,sans-serif; }
.
Vous devez définir vos gestionnaires d'événements d'une autre façon, plus propre. Voici quatre exemples qui vous aideront à comprendre cette manière de procéder.
(Pour comprendre complètement ces exemples, vous devrez peut-être actualiser
votre connaissance des gestionnaires d'événement Javascript, tout comme il y a
quatre ans vous avez dû maîtriser les bases de CSS pour vous débarasser de la balise <FONT>
.
Changer ses habitudes de programmation signifie apprendre de nouvelles choses.)
Exemple 1 : Pour assigner un comportement de rollover à la liste de notre exemple, utilisez le code suivant. Ce code ira, bien entendu, dans votre fichier Javascript lié.
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 } }
Exécuter cette fonction attribue le comportement de survol sans utiliser le moindre
gestionnaire d'événement dans le code structurel. Quand l'utilisateur passe la souris
au-dessus de n'importe quelle image dans <ul id="mouseovers">
, la
fonction mouseGoesOver()
est appelée. Quand l'utilisateur quitte l'image,
mouseGoesOut()
est appelée.
Vous avez toujours besoin du code pour ces deux fonctions. Je ne l'ai pas inclu ici pour gagner de l'espace. À la place, vous pouvez étudier le script d'exemple (1) que j'ai préparé sur mon propre site. Il est simple, il fonctionne dans tous les navigateurs modernes, et il n'utilise pas de gestionnaire d'événement en-ligne.
Exemple 2 : Pour attribuer un comportement à tous les
<span>
qui n'ont pas de class
, faites :
function initSpanBehavior() { var spans = document.getElementsByTagName('span'); for (var i=0;i<spans.length;i++) { if (spans[i].className) continue; spans[i].onsomeevent = doSomething; } }
Exemple 3 : Vous devez toujours exécuter la fonction
initMouseOvers()
ou initSpanBehavior()
quand la page est chargée.
Ne faites pas :
<body onload="initMouseOvers()">
Ceci mélange structure et comportement en introduisant un appel de fonction Javascript dans votre XHTML, où il n'a pas lieu d'être. Commes les autres, cette instruction devrait être déplacée dans votre fichier Javascript lié :
window.onload = initMouseOvers;
Pour exécuter les deux fonctions d'initialisations, faites :
window.onload = function () { initMouseOvers(); initSpanBehavior(); }
(Il y a quelques problèmes avec l'approche
window.onload
, mais ils sont de nature technique, et non conceptuelle. Le code
ci-dessus illustre le concept correct. Du reste, il est suffisamment sûr pour des
pages simples.)
Exemple 4 : Chris Heilmann nous fournit l'exemple final. Son article Javascript navigation - cleaner, not meaner explique comment assigner un comportement DHTML à une navigation basée sur une simple liste. Chris ne parle pas du DHTML lui-même, mais se concentre sur la séparation élégante du comportement et de la structure, tout en conservant une accessibilité globale.
(J'ai attaqué Chris sans pitié quand il a écrit de mauvais articles, ce n'est que justice de le féliciter quand il en écrit des bons.)
Il prône donc le même changement d'habitudes de programmation que moi. J'ai néanmoins l'impression que Chris, comme Simon et Stuart, n'accordent pas suffisamment d'importance à l'idée fondamentale.
Faire le premier pas
À mon avis, les avancées récentes dans la théorie de Javascript vont dans le sens de la suppression des gestionnaires d'événements que certains développeurs web -- et tous les éditeurs WYSIWYG -- déploient en masse dans leurs fichiers XHTML, là où des gestionnaires n'ont rien à faire.
Les déplacer vers des fichiers .js
sépare le comportement de la structure, tout
comme la suppression des balises <FONT>
a initié la séparation entre la
présentation et la structure. Plus haut, j'ai cité quatre problèmes de Javascript.
Supprimer tous les gestionnaires d'événement en-ligne résoudra largement le problème de la
laideur. Ne pas utiliser de scripts idiots résout le problème de l'ergonomie, et le problème
de l'accessibilité est bien cerné, bien que pas encore résolu.
J'espère que ceci convaincra les anti-Javascripts modérés que Javascript va dans le sens d'une intégration avec les pages XHTML/CSS, et qu'il n'y a pas de raison fondamentale de l'éviter.
Je les invite aussi à faire le premier pas, à essayer d'ajouter une couche de comportement mineure et inoffensive à un site, à pratiquer la séparation du comportement et de la structure, et à prendre des décisions informées en matière d'accessibilité.
Mais quid du problème de chevauchement ? Quid des CSS capables de mimer la plupart des fonctions Javascript traditionnelles ? En d'autres mots, quid de la séparation du comportement et de la présentation ? Ce sera le sujet de ma prochaine chronique.
» 1 : NDLR : La ressource vers laquelle pointe le lien — www.quirksmode.org/js/mouseov.html — a disparu et nous l’avons donc remplacé par un lien menant à une version archivée. Une version plus récente de ce script est par ailleurs disponible.
http://www.digital-web.com/articles/separating_behavior_and_structure_2/