HTML Orienté Objet avec CSS

Ou Comment avoir (presque) l’impression de manipuler de l’objet en CSS.

HTML sémantique

Pour cela, il faut partir d’un code HTML sémantiquement fort. Les règles que j’utilise sont les suivantes :

  1. différencier les types de structures génériques des données spécifiques ;
  2. réfléchir à la forme HTML la plus appropriée pour chaque structure générique ;
  3. rester simple.

La première règle s’applique lorsqu’il n’existe pas de balises HTML existante permettant de décrire exactement le type de la structure. Un paragraphe est un <p>, une liste est un <ul>, mais un menu ? Un fil d’Ariane ? Une propriété d’un formulaire ?
Il faut de plus différencier ces structures génériques de leur réalité. Par exemple, une même page peut avoir plusieurs menus (même structure générique) mais l’un est le menu principal, l’autre le menu secondaire, etc. De la même façon, il existe plusieurs propriétés dans un formulaire mais chacune désigne une certaine donnée : identifiant, mot de passe, nom, prénom…

À chaque structure non existante, il est nécessaire de réfléchir à la structure la plus appropriée, à la fois sémantiquement et hiérarchiquement. Communément un menu est représenté par une liste d’éléments (<ul> et <li>). Un fil d’Ariane pourrait l’être par une liste ordonnée (<ol>). Une propriété d’un formulaire pourrait l’être par une liste de définitions (<dl>, <dt> pour le label, <dd> pour le champ). Il n’y a rarement qu’une seule bonne solution.
Lorsque les propriétés seules ne sont pas suffisantes, une pratique courante est d’augmenter le sens d’une balise existante grâce à un attribut HTML, notamment avec l’attribut class qui permet d’être différencié en CSS (voir les microformats). Ainsi, on pourra par exemple ajouter la classe menu sur le <ul> pour désigner un menu (<ul class="menu">), ou encore la classe “breadcrumb” sur un <ol> pour désigner un fil d’Ariane.

Enfin, il est essentiel de rester simple dans la construction du HTML : pas de profusion de <div>, de <p> et de <span> ! Pas besoin d’encapsuler un <h1> dans un <div class="title"> : le <h1> EST un titre.
Tant que c’est raisonnablement possible, fusionner les <div>, <p> et <span> avec les balises porteuses de sens et s’appuyer sur le contexte pour pouvoir distinguer les balises. Ainsi, on peut transformer <div class="ContactPage"><div class="ContactForm"><form>... en <div class="ContactPage"><form>..., voire en <form class="ContactPage>.

Après cette introduction, nous pouvons entrer dans le vif du sujet en commençant par utiliser de manière orientée objet les attributs HTML.

Classification et identification du HTML

Deux attributs permettent de s’approcher de la notion d’objets en HTML : class et id. Class peut être utilisé pour représenter la ou les classes (au sens POO du terme). De la même façon qu’un objet peut être de la classe Student qui hérite de User, un <div> a comme attribut class="Student User". L’attribut id sert quant à lui à identifier une instance d’un objet HTML : la <div id="student3188" class="Student"> correspond ainsi à une instance (appelée student3188) d’une classe Student.

Chaque partie du code HTML peut être décrite de cette manière. Par exemple, une liste d’utilisateurs peut être écrite sous la forme :

<ul class="Users">
   <li class="User" id="johndoe">
      <p class="Name">John Doe</p>
      <p class="Age"><span class="Value">25</span> years old</p>
   </li>
   <li class="User" id="janedoe">
      <p class="Name">Jane Doe</p>
      <p class="Age"><span class="Value">27</span> years old</p>
   </li>
</ul>

Une fois que le code HTML du site est organisé de cette manière, il est possible d’utiliser le CSS pour accéder aux différentes parties.

Écriture des sélecteurs CSS

L’écriture du code CSS s’appuie fortement sur la caractérisation des balises HTML expliquée précédemment. Grâce aux attributs class (sans balise HTML) il va être possible de mettre en forme de manière générique les données. L’attribut id servira quant à lui au besoin pour différencier les cas.
On peut donc écrire par exemple :

.Users {
   margin: 15px;
}
   .Users .User {
      border: 1px solid grey;
      padding: 10px;
   }
      .Users .User .Name {
         font-weight: bold;
      }
      .Users .User .Age {
         font-size: 0.8em;
      }
         .Users .User .Value {
            font-size: 1.5em;
         }
   .Users .User#janedoe {
      border-color: blue;
   }

Cette notation en classes donne l’impression d’écrire des accès à des variables en programmation orientée objet. En effet, les langages utilisent souvent le caractère . (point) pour accéder à la propriété d’un objet. Ainsi, on accède à l’attribut name de l’objet user par user.name. L’utilisation d’une organisation du code HTML et de sélecteurs CSS basés sur les classes permet d’approcher syntaxiquement cela : .User .Name.
Le fait de s’appuyer quasi uniquement sur l’arborescence de classes permet notamment :

  • d’éviter les conflits d’identifiant ;
  • de pouvoir accéder de manière lisible et compréhensible (sémantique) aux éléments ;
  • de réduire les soucis de priorité des sélecteurs CSS ;
  • de rester suffisamment souple et précis pour pouvoir tolérer des modifications du code HTML sans retouche du code CSS (encapsulation dans un autre bloc, modification du type de balise HTML…).

De cette manière les codes HTML et CSS approchent les qualités de modularité et de structuration de la programmation orientée objet.

Gérer les redirections et erreurs des formulaires HTML

La création de formulaires HTML amène invariablement à une question d’architecture : comment gérer les  redirections et les messages d’erreur ou de succès qui peuvent avoir lieu lors de la validation de la saisie de l’utilisateur ?

La réponse que j’ai adoptée se base sur quelques règles de conception web simples, applicables à l’ensemble d’un site et qui permettent d’offrir à l’utilisateur un certain confort de navigation :

  • l’utilisateur doit être en mesure de se servir pleinement les fonctions de base de son navigateur (précédent, suivant, rafraîchir, mise dans les favoris…) ;
  • pour une URL donnée, le contenu doit rester identique ou très similaire ;
  • à l’inverse, un contenu identique ne doit pas se trouver sur plusieurs URL différentes.

Soit un formulaire en page /monformulaire.php et contenant plusieurs champs qui peuvent entraîner des erreurs de saisie par l’utilisateur (exemple : email incorrect, nombre trop grand, date invalide, etc.). En cas d’erreur de la saisie on souhaite afficher un message d’avertissement à l’utilisateur et réafficher le formulaire (avec éventuellement le champ erroné clairement indiqué, par exemple sur fond rouge pour faire dans l’originalité).

Suivant les principes énoncés plus haut, le formulaire devra toujours avoir comme URL /monformulaire.php : après soumission du formulaire l’utilisateur doit donc se trouver au final sur la page /monformulaire.php. L’idée est ici de donner comme URL de soumission du formulaire la même URL que l’affichage du formulaire : <form action="/monformulaire.php" ...

Les avantages de cette technique sont les suivants :

  • les erreurs éventuelles lors de la soumission n’ont pas besoin d’être transmises à d’autres pages comme c’est le cas en cas de redirections ;
  • l’utilisateur peut pleinement utiliser les fonctions précédent/suivant de son navigateur pour par exemple retrouver les valeurs des champs de formulaire ;
  • en cas de réactualisation de la page, le navigateur propose de reposter les champs du formulaire et l’utilisateur se retrouve donc sur la même page (et on reste donc dans le respect de la première règle énoncée, ouf !) ;
  • en cas de chargement direct de la page (par exemple si la page a été enregistrée dans les favoris) c’est bien le formulaire qui est chargé avec des valeurs vides, comme pouvait s’y attendre l’utilisateur ;
  • d’un point de vue plus technique, tout le code de gestion et d’affichage du formulaire se situe sur une même page.

Par conséquent, c’est seulement en cas de succès que l’utilisateur est redirigé, ce qui apparaît finalement plus logique du point de vue de la navigation : page précédente renvoie sur le formulaire valide, rafraîchir la page ne propose pas de reposter le formulaire…

Cercle ou carré ?

Cercle ou carré ?

La conception me fait penser à ces jeux pour enfants qui consistent à faire entrer des formes en bois dans les trous qui correspondent. Trouver une bonne solution architecturale est un peu comme trouver la bonne forme : d’abord on essaye le triangle qui dépasse fortement, puis l’étoile, beaucoup trop compliquée, et on arrive enfin à mettre la main sur le cercle et tout rentre parfaitement. En conception, quand on tombe sur la bonne solution tout devient clair et logique, tout s’assemble parfaitement. La mauvaise solution, le carré, c’est celle qui rentre seulement en forçant, en limant les coins et en laissant plein d’espaces vides, et qui reste bloquée dans le trou.

Alors, cette solution, cercle ou carré ?

au fin al