Passer son blog Wordpress à la sémantique HTML5 et ARIA
HTML5 introduit de nouveaux éléments qui sont parfaits pour ajouter de la sémantique à un blog ou un journal. ARIA fait de même concernant l’accessibilité aussi étant donné la facilité permise par Wordpress pour modifier son markup, il serait dommage de se priver, même si vous êtes un débutant Wordpress comme moi. Nous allons donc voir :
- l'utilisation des nouvelles balises
<article>, <time>, <nav> ...
- certains rôles ARIA
- les améliorations des formulaires
- les ajouts JS/CSS à apporter
- les fichiers à modifier dans wordpress
Le tout bien sur compatible sur tous les navigateurs, IE6 inclus.
Même si vous n’êtes pas un utilisateur Wordpress, les remarques sur la sémantique HTML5 et les rôles ARIA restent valables quel que soit le site.
Travail préparatoire
Tout passage à HTML5 doit passer par 2 ajouts à votre site, afin d’avoir un comportement normal des nouveaux éléments, que les anciens navigateurs ne pouvaient bien sur pas connaître. Je les reprend de mon précédent article sur le passage à HTML5, la situation n’ayant pas évolué depuis.
JavaScript
IE ne sait pas styler les éléments inconnus. Heureusement il existe une solution JS reconnue appelée HTML5 shim pour contourner ce problème, qui consiste à créer dynamiquement au moins une fois ce nouvel élément. Ceci marche avec IE6 et supérieur. Notez que ce code doit être exécuté obligatoirement dans <HEAD>
. Plusieurs choix alors :
- pour des gains de performances, vous avez enlevé les inclusions de fichiers JS du
<HEAD>
. Il vous faut alors éditer header.php pour rajouter ce script inline, avant<HEAD>
- vous ou votre thème inclue déjà modernizr, ce script est déjà inclus dedans. Si modernizr est dans le
<HEAD>
vous n'avez rien à ajouter - vous avez un fichier javascript global inclus dans le
<HEAD>
, c'est dans ce fichier qu'il faut rajouter ces lignes.
// inspiré de http://code.google.com/p/html5shim/source/browse/trunk/html5.js
// crée tous les tags HTML5 au moins une fois pour que IE sache les styler
// Commentaires et discussions, voir http://remysharp.com/2009/01/07/html5-enabling-script/
(function(){
if(!/*@cc_on!@*/0)
return;
var e = 'abbr,article,aside,audio,bb,canvas,datagrid,datalist,details,dialog,eventsource,figure,footer,header,hgroup,mark,menu,meter,nav,output,progress,section,time,video'
.split(',');
for(var i=0, iTotal = e.length; i<iTotal;i++) {
document.createElement(e[i]);
}
})();
CSS
Tous les éléments inconnus pour les navigateurs sont de type display:inline
par défaut, ce qui peut rapidement casser un design : si vous passez d’une <DIV>
à un <ARTICLE>
, vous allez être obligé de rétablir display:block
pour chaque élément. Il est préférable de s’inspirer de la stratégie des CSS reset et de définir un comportement par défaut à toutes les balises HTML5 possibles. Notez que l’on définit également les balises qui devraient être inline, ceci afin de prévenir le cas où un navigateur déciderait de mettre une des ces balises en display:block
. Dans le fichier style.css, après le CSS reset :
/* tags HTML5 qui se comportent comme des blocs */
article, aside, audio, canvas, datagrid, datalist, details, dialog, figure, footer, header, menu, nav, section, video { display: block; }
/* tags de type en ligne */
abbr, eventsource, mark, meter, time, progress, output, bb { display:inline; }
doctype
Nous allons maintenant remplacer votre doctype par le désormais célèbre nouveau doctype HTML5. dans header.php, première ligne : <!DOCTYPE html>
. Vérifiez que votre blog s’affiche toujours comme avant sur tous vos navigateurs cible, je n’ai jamais entendu que ce nouveau doctype posait problème. Vous êtes officiellement passé en HTML5 :)
Les articles
La sémantique en théorie
Il y a 4 nouvelles balises toutes trouvées (en plus du <Hx>
) qui vont enrichir sémantiquement nos articles. Ce qui change avec HTML5, c’est que non seulement la balise a un sens, mais ce sens peut varier en fonction des éléments parents :
<ARTICLE>
: surpris ? Allons un peu plus loin : la définition du W3C dit qu'elle représente une section isolable du site, qui peut s'autosuffire en dehors du contexte de la page (dans un lecteur RSS par exemple). Cette balise peut aussi être enfant d'un autre<ARTICLE>
, comme dans l'interprétation qu'en a fait HTML5 Doctor, auquel cas elle pourrait représenter les commentaires relatifs à un article. Nous n'allons pas le faire ici car ce point est parfois discuté et cela demande beaucoup plus de modifications dans wordpress car les styles de l'articles et des commentaires n'ont pas été prévus pour s'imbriquer.<HEADER>
: cette balise n'est pas exclusivement réservée à l'en-tête du site ! A l'intérieur d'un<ARTICLE>
, elle sert à repérer les titres et méta-données de l'article comme la date de publication et le nom de l'auteur. Dans Wordpress, cela correspond exactement aux éléments avec les classes.entry-title, .entry-header, .author, .published
et.comment-count
<FOOTER>
: elle non plus n'est pas réservée au pied de page du site. Placée dans un<ARTICLE>
, elle marque les informations relatives à l'article mais non indispensables, telles que tags et catégories. Dans Wordpress, cela correspond aux classes.entry-footer, .entry-categories
et.entry-tags
<TIME>
: elle sert à indiquer une date. Rajoutez y l'attributpubdate
pour signifier au parseur qu'il s'agit de la date de publication de l'<ARTICLE>
parent. L'attributdatetime
doit contenir la date à un format standardisé qui peut varier de "2010-08-20" à "2010-08-20T20:00+09:00". PHP à la rescousse : il y a une constante pour ce format qui s'appelleDATE_W3C
et que vous pouvez passer à la fonction wordpress d'affichage de la date.
Le code final :
Voici le code original simplifié d’une installation Wordpress 3 avec le thème par défaut :
<div class="hentry" id="post-777">
<h2 class="entry-title">Titre + lien</h2>
<div class="entry-meta">
<span class="meta-prep meta-prep-author">Publié le</span>
<span class="entry-date">Vendredi 20 août 2010</span>
<span class="author vcard">Auteur</span>
</div><!-- .entry-meta -->
<div class="entry-content">
corps de l article
</div><!-- .entry-content -->
<div class="entry-utility entry-footer">
catégories, tags, commentaires ...
</div><!-- .entry-utility -->
</div><!-- .hentry -->
notez les très pratiques commentaires qui marquent les balises de fermeture. Nous allons donc :
- remplacer la
DIV.hentry
par une baliseARTICLE
, en conservant les classes - remplacer la
DIV.entry-utility
(ou.entry-footer
dans mon thème) par une baliseFOOTER
, en conservant les classes - entourer le <
H2>
et laDIV.entry-meta
par une baliseHEADER
- remplacer le
<H2>
par un<H1>
: en HTML5, lesHx
sont relatifs à l'élément parent pour lequel cela a un sens :<ARTICLE>
,<SECTION>
ouBODY
. Contrairement à certaines recommandations SEO, il est donc possible d'avoir plusieurs H1 par page - entourer ou remplacer le
SPAN.entry-date
par ce code :<time pubdate datetime="<?php the_time( DATE_W3C ); ?>"> ... </time>
pour obtenir ce markup :
<article class="hentry" id="post-777">
<header>
<h1 class="entry-title">Titre + lien</h1>
<div class="entry-meta">
<span class="meta-prep meta-prep-author">Publié le</span>
<time pubdate datetime="2010-08-20T11:34:47+00:00"
class="entry-date">
Vendredi 20 août 2010
</time>
<span class="author vcard">Auteur</span>
</div><!-- .entry-meta -->
</header>
<div class="entry-content">
corps de l article
</div><!-- .entry-content -->
<footer class="entry-utility entry-footer">
catégories, tags, commentaires ...
</footer><!-- .entry-utility -->
</article><!-- .hentry -->
Que modifier ?
Il va falloir apporter ces modifications à beaucoup d’endroits, voici une liste non exhaustive (selon votre thème) :
- archive.php
- single.php
- page.php
- index.php
- category.php
- author.php
- tag.php
- search.php (à la différence que
<ARTICLE>
ne doit pas remplacer le<LI>
mais être son premier et unique fils) - date.php
Je déteste dupliquer le code, donc si vous êtes bons en Wordpress vous devriez peut être inclure un template unique d’article dans tous ces fichiers, car c’est quasiment le même markup à chaque fois. La partie difficile étant bien sur de coder le “quasiment” :) Voilà, vous êtes passé à la sémantique HTML5 sur la partie importante du blog que sont les articles. Logiquement Google ou d’autres programmes devraient utiliser un jour ce standard, au même titre que les microformats, microdata ou RDFa pour comprendre plus facilement votre site et donc proposer des fonctionalités spécifiques à vos lecteurs (un affichage spécifique dans les résultats Google, une meilleure indexation, les navigateurs pourraient mettre en avant l’article …).
HTML5 Forms et rôles ARIA dans votre layout
Pour le reste du site, nous allons ajouter plus de sémantique. Notez que les rôles ARIA sont déjà correctement définis dans le thème par défaut, mais ce n’est probablement pas celui que vous utilisez, donc je vais les répéter.
Formulaires
Forms 2 a été renommé en HTML5 Forms et continue de définir de nouveaux types de champs ainsi que d’ajouter du comportemental sans JavaScript. Par défaut il n’y a pas de JavaScript qui régisse les formulaires de Wordpress (commentaires et recherche), on ne perd donc pas de fonctionnalité pour les anciens navigateurs : on en rajoute pour ceux qui supportent HTML5 Forms :) Si vous voulez ajouter facilement ces fonctionnalités pour pour d’autres navigateur sans taper de code JS, vous pouvez partir sur la librairie WebForms2
Dans comments.php :
- la
<DIV>
avec l'id#respond
devient une<SECTION>
: comme une<DIV>
, la<SECTION>
n'a pas de valeur sémantique particulière, sinon qu'elle contient un titre, ce qui est ici le cas avec un<H3>
comme enfant direct. Ce<H3>
est d'ailleurs promu au rang de<H1>
car c'est le titre le plus important de cette<SECTION>
- dans le formulaire de commentaire, on modifie le type de 2 champs : celui de l'email et du site Web pour les passer très logiquement en
type="email"
ettype="url"
. Cela ne change rien pour la plupart des navigateurs mais outre la lisibilité du code, le seul bénéfice connu actuel est le changement de clavier sur iOS ... Mais dans les mois qui viennent, d'autres clients pourraient l'utiliser pour une meilleure autocomplétion des champs ou pour signaler un type de données invalides. En attendant cela ne coûte rien - rajouter l'attribut
required
ainsi quearia-required="true"
aux champs obligatoires (au minimum l'email et le champs de commentaires). En code Wordpress cela donne :
<input name="email" id="email" type="email" value="<?php echo $comment_author_email; ?>" tabindex="2" <?php if ( $req ) echo "aria-required='true' required"; ?> />
Les navigateurs supportant required
(FF4, Opéra 9+, Webkits) ne laisseront pas l’utilisateur valider le formulaire tant qu’il n’a pas rempli correctement les champs. Voir cette démo faite par Opéra.
Vous pouvez ensuite styler en CSS grâce aux pseudo-sélecteurs les champs non ou mal remplis :
input:invalid,
input:invalid + label {
background-color : red;
}
Votre code final généré pour la zone de saisie de commentaires devrait ressembler à ceci :
<section id="respond">
<h3 id="leave-a-reply">Laisser un commentaire</h3>
<!--BEGIN #comment-form-->
<form action="...">
<!--BEGIN #form-section-url-->
<div class="form-section" id="form-section-url">
<input type="url" required="required" aria-required="true" value="http://braincracking.org/" id="url" name="url">
<label class="required" for="url">Site Web</label>
<!--END #form-section-url-->
</div>
../..
<!--END #comment-form-->
</form>
<!--END #respond-->
</section>
Notez que l’on pourrait passer de même tous les widgets avec <SECTION>
et leur titre en <H1>
.
Dans searchform.php :
Si votre thème n’a peut-être pas ce fichier ou équivalent, sachez que le formulaire de recherche par défaut se trouve dans general-template.php, dans la fonction get_search_form
. Nous allons rajouter ici 3 choses :
- le rôle ARIA sur le formulaire lui même :
<form role="search" ...>
- le type "search" sur le champs de formulaire :
<input type="search" />
. Notez que sous les webkits sur Mac OS, votre champs apparaît stylé comme Spotlight : arrondi avec une croix d'annulation - un "placeholder", grand classique du Web : un texte par défaut disparaît lorsque l'on clique sur le champs et ré-apparaît si rien n'a été écrit :
<input placeholder="Rechercher" />
ce qui se devrait se traduire par ce code final :
<form role="search" action="http://braincracking.org/blog" method="get" class="searchform">
<input type="search" placeholder="Rechercher" name="s" class="search" />
<button type="submit" class="search-btn">Rechercher</button>
<!--END #searchform-->
</form>
Layout
sidebar.php
Ceci affiche la ou les colonnes latérales, qui est donc un contenu sans forcément un rapport direct avec le contenu principal du site. ARIA et HTML5 ont tout prévu pour cela : role="complementary"
et balise <ASIDE>
. Vous devez donc modifier une (ou plusieurs selon le thème) <DIV>
parentes pour obtenir ceci :
<aside role="complementary" id="..." class="...">
widget et contenus relatifs
</aside>
header.php
Nous avons déjà modifié ce fichier pour y rajouter le doctype, notre JS et le CSS afin de préparer le blog à HTML5. Passons maintenant aux ajouts sémantiques :
- la balise
<HEADER>
, pour marquer cette zone - la balise
<NAV>
pour indiquer une zone de liens. Selon votre thème, cela peut être la liste des catégories ou des pages à part. Nous lui ajouterons le rôle ARIAnavigation
qui lui correspond exactement - le rôle ARIA
banner
qui signale titre et logo - si votre formulaire de recherche n'est pas déjà modifié, c'est le moment de rajouter
role="search"
sur le formulaire ettype="search" placeholder="Rechercher"
dans le champs de recherche
Les résultats varient grandement selon le thème, mais voici un exemple simplifié à partir du code du thème par défaut Wordpress 3 :
<header class="header">
<nav id="access" role="navigation">
<ul class="nav">
<li class="current_page_item"><a href="http://braincracking.org/blog/" title="Accueil">Accueil</a></li>
<li class="page_item page-item-2"><a href="http://braincracking.org/blog/a-propos/" title="A propos">A propos</a></li>
</ul>
</nav>
<!-- END #access -->
<div id="branding" role="banner">
<h1 id="blog_header"><a href="http://braincracking.org/blog">BrainCracking</a></h1>
</div> <!-- #branding -->
</header><!-- #header -->
footer.php
Là aussi, sans grande surprise nous allons utiliser la balise <FOOTER>
ainsi que le role=contentinfo
qui sont tous deux faits pour baliser une zone contenant copyrights, liens vers mentions légales et autres textes relatifs au site, mais pas forcément au contenu de cette page. Attention, chez Wordpress cela ne correspond pas exactement à la DIV id="footer"
du template par défaut, celle ci contenant également d’autres widgets.
Concrètement :
<!--BEGIN #footer-->
<div id="footer">
<div id="footer-widget-area">
code généré par les widgets
</div><!-- End #footer-widget-area -->
<footer id="copyright" role="contentinfo">© 2009-2010
<nav role="navigation">
Liens vers mentions légales, vie privée, qui somme nous ...
</nav>
</footer>
<!--END #footer-->
</div>
Notez que pour ceux qui font des liens, on peut tout à fait rajouter la balise <NAV>
.
Conclusion
Avec ce tutoriel et 2 à 3 heures de travail, vous pouvez passez assez facilement à la sémantique HTML5 sur votre blog dès aujourd’hui. En fait en le codant, il devient même évident que les spécifications HTML5 et ARIA on été influencées par la sémantique Wordpress tant la correspondance est facile.
Du côté de HTML5, il est probable que sur ce thème par défaut, Wordpress ait préféré faire l’impasse pour ne pas dépendre de Javascript ou de spécifications qui ne sont pas totalement fixées. Je pense personnellement que ces 2 limites ne sont pas un problème :
- les éléments que j'ai cité ici ont tous ont été largement discutés, et il est peu probable que le W3C revienne dessus. Si c'est cependant le cas les modifications à faire ne sont pas complexes
- j'estime la population avec IE et javascript désactivé comme négligeable, au pire ils auront un design cassé mais sur un blog le contenu principal (l'article) restera exploitable.
Les rôles ARIA sont déjà inclus dans le thème par défaut de Wordpress 3, mais nombre de thèmes ont oublié de les répliquer. En créant ce blog, je cherchais des thèmes exploitant déjà la sémantique HTML5, mais ils sont peu nombreux donc le choix en graphismes est limité, et à l’heure d’écrire cet article aucun n’exploitait autant ARIA et HTML5.
Références, outils, remerciements :
- 2 thèmes Wordpress tout faits (mais incomplets) : Toolbox et JustCSS
- les specifications HTML5 et ARIA
- la démo d'Opéra sur les formulaires HTML5
- HTML5 Doctor pour l'ensemble de leur oeuvre d'explication des specifications
- Merci à Johan Bleuzen d'avoir relu et validé la partie Wordpress
- les validateurs W3C et WHATWG que passe maintenant braincracking.org
- le plugin Wave pour vérifier ARIA sur son site
- le bookmarklet h5o pour analyser une page HTML5 selon l'algorithme W3C