2004-07-20

Xhtml et élément object

J'ai mis à jour mon formulaire pour écrire des billets, désormais il permet de faire automatiquement de la coloration syntaxique de code xhtml. J'en profite alors pour écrire ce billet que j'avais en tête depuis quelques temps.

On peut avoir envie d'insérer du contenu multimédia dans son document xhtml : une animation Flash, une vidéo ou toute autre friandise offerte par un plug-in de votre navigateur web.

Je me suis penché sur la question, sachant à l'avance que je nagerais dans le flou : je remarque souvent des problèmes de compatibilité sur certains sites avec tel ou tel navigateur, et quand on regarde de plus près sur comment intégrer ce contenu, on remarque qu'il y a deux éléments utilisés : l'élément object, et l'élément embed. Voici un exemple typique :

<object id="flash00" classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" width="400" height="300">
  <param name="movie" value="plop.swf">
  <embed src="plop.swf" width="400" height="300" type="application/x-shockwave-flash"></embed>
</object>

Mais c'est quoi tous ces trucs ? Pourquoi est-ce si compliqué ? Le classid c'est quoi ? Et pourquoi un élément embed dans un élément object ? N'y a-t-il pas double emploi ? Pourquoi on indique le type dans l'élément embed et pas dans l'élément object ? Et si on souhaite scripter facilement le contenu, comment faire vu qu'on a un élément imbriqué dans l'autre ?

Quand je vois un truc trop compliqué, ça m'énerve, et je tente de comprendre pourquoi les choses sont faites ainsi. Procédons par ordre. J'ai dans un premier temps consulté la documentation xhtml, et ô joie, j'ai eu déjà des réponses. Ainsi, en xhtml, l'élément embed n'existe pas. Zouuuuuuuu, aux oubliettes le embed. Mon code devient alors minimal et plus compréhensible :

<object id="flash00" classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" width="400" height="300">
  <param name="movie" value="plop.swf" />
</object>

Heu, sauf que ça fonctionne bien sous IE, mais pas sous Gecko, le moteur de rendu de Mozilla. Je tâche alors de me renseigner sur la question, et je découvre que la syntaxe qui fonctionne sous Gecko est la suivante :

<object id="flash00" type="application/x-shockwave-flash" data="plop.swf" width="400" height="300">
</object>

Malheureusement j'obtiens alors l'effet inverse, ça fonctionne sous Gecko mais plus sous IE. Je tripatouille le code dans tous les sens, en faisant une fusion des deux techniques, et ça ne passe pas. Soit ça fonctionne dans IE, soit dans Gecko. Je vous épargne les étapes du processus, mais j'en viens à la conclusion qu'il convient d'avoir une syntaxe différente pour IE et pour Gecko. Reste alors à trouver la solution pour proposer une syntaxe ou l'autre selon le navigateur.

La première idée qui me vient en tête c'est d'utiliser du javascript. Au déclenchement de l'événement onload de la page, j'appelle une fonction qui va me rajouter au document un élément object avec les paramètres qui vont bien, selon le navigateur. Malheureusement je me casse les dents sur cette solution, j'ai l'impression que mes navigateurs ont du mal avec la création d'éléments object dynamiques (autrement que par une méthode document.write, malvenue pour du xhtml). De plus, quid des navigateurs qui ont le javascript désactivé ? Et puis le javascript est une technologie que je préfère employer uniquement quand je n'ai pas le choix, quand une solution xhtml ou css n'existe pas.

J'ai enfin trouvé la solution. En fin de compte, après réflexion, la méthode qui fonctionne sous Gecko est la méthode conforme aux standards web. Quant à IE, ce qui fonctionne avec lui est une méthode qui lui est propre. J'ai donc décidé d'utiliser les propres armes d'IE pour lui montrer du code qu'il aime bien, et lui cacher ce qu'il aime moins (du code aux normes !). Cette arme ce sont les commentaires conditionnels. Voilà ce que ça donne :

<!--[if !IE]> Standard XHTML object instanciation <!-->
<object id="flash00" type="application/x-shockwave-flash" data="plop.swf" width="400" height="300">
<!--><![endif]-->

<!--[if IE]>
<object id="flash00" classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" width="400" height="300">
<![endif]-->

<param name="movie" value="plop.swf" />
</object>

Grâce à ça, on n'a qu'un seul élément object, au même niveau, avec le même id. Ça fonctionne avec le javascript désactivé. Et si on souhaite travailler avec cet object, on utilisera le même code javascript ou le même code css selon qu'on est sous IE ou un navigateur conforme aux standards ! ^^,

À noter que ce code a du mal dans Opera, ce dernier ne sachant pas gérer l'élément object. Ma position est de laisser Opera s'adapter. Cette attitude m'avait donné raison lorsque je m'étais rendu compte que ce navigateur de savait pas interpréter le javascript pour des documents xhtml desservis en application/xhtml+xml. Après la sortie de Opera 7.50, c'était chose faite, le javascript était bien géré :)