Développement web et mobile
Les bases du HTML : structure sémantique, formulaires, médias et accessibilité
Débutant11 min de lectureMis à jour
Cette page a été traduite de l'anglais avec l'aide de l'IA, puis vérifiée par rapport à l'original. Lire la version anglaise
Le HTML moderne est un standard vivant, pas une version numérotée, et les éléments que vous choisissez forment une interface pour les navigateurs, les technologies d'assistance et les moteurs de recherche à la fois. Ce guide parcourt le squelette du document, les éléments sémantiques et ce que chacun signale, la validation native des formulaires, les images et médias responsives, les tableaux accessibles et les métadonnées du head que d'autres machines lisent.
Ce que vous allez apprendre
- Construire un squelette de document valide et expliquer à quoi servent réellement le doctype, le charset et l'attribut lang
- Choisir les éléments sémantiques selon leur sens et les relier aux landmarks d'accessibilité qu'ils exposent
- Utiliser les contrôles de formulaire natifs, les types d'input et la validation par contraintes avant de recourir à JavaScript
- Servir des images responsives et des médias accessibles grâce à srcset, picture, au texte alternatif et aux sous-titres
- Rédiger les métadonnées du head qui pilotent le titre, l'URL canonique, les aperçus sur les réseaux sociaux et l'affichage mobile
Le HTML a la réputation d'être la partie facile du développement front-end, et c'est en un sens mérité : rien ne lève d'exception, rien ne refuse de compiler, et une page aux balises mal fermées s'affiche quand même. C'est précisément cette tolérance qui permet de mal l'écrire sans s'en rendre compte. Le parser répare vos erreurs en silence : un document peut être dénué de toute structure et s'afficher correctement sur votre écran, pendant qu'un lecteur d'écran l'annonce comme un bloc de texte indifférencié et qu'un robot d'indexation peine à comprendre de quoi parle la page.
Mieux vaut considérer le balisage comme une interface qui a plusieurs consommateurs. Le navigateur s'en sert pour construire le DOM et l'arbre d'accessibilité. Les technologies d'assistance parcourent cet arbre par landmark, par titre et par contrôle. Les moteurs de recherche en extraient la structure et les métadonnées. Votre propre JavaScript l'interroge. Choisir ses éléments avec soin sert ces quatre consommateurs d'un coup. Ce guide couvre les parties du langage où ce soin est payant : le squelette du document, le vocabulaire sémantique, le head, les formulaires, les médias et les règles d'accessibilité que le balisage seul permet de respecter.
La spécification de référence
Il n'y aura pas de HTML6. Depuis 2019, il n'existe qu'une seule spécification, le HTML Living Standard du WHATWG, mise à jour en continu plutôt que publiée par versions. Quand on dit « HTML5 » aujourd'hui, on parle du jeu d'éléments moderne et des API du navigateur arrivées avec lui, pas d'une édition figée. Au quotidien, la documentation MDN se lit plus facilement que la spécification elle-même, et elle fournit les tableaux de compatibilité des navigateurs que la spécification ne donne pas.
Voici un document minimal et correct :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Order history — Northwind</title>
</head>
<body>
<!-- content -->
</body>
</html>
Chaque ligne a sa raison d'être. <!DOCTYPE html> n'est plus une déclaration de version : c'est l'interrupteur qui fait passer le navigateur en mode standard plutôt qu'en mode quirks, conservé pour les documents écrits dans les années 1990. L'attribut lang indique aux lecteurs d'écran quelles règles de prononciation appliquer et aide les outils de traduction ; sans lui, une page en anglais est lue avec une phonétique française sur un système configuré en français. La déclaration d'encodage doit figurer dans les 1024 premiers octets du fichier, d'où sa place en tête, et elle doit toujours indiquer UTF-8. La balise meta viewport empêche les navigateurs mobiles d'afficher la page à une largeur de bureau simulée, puis de dézoomer.
Remarquez aussi ce qui manque : aucune barre oblique finale n'est requise sur les éléments vides, les valeurs d'attribut n'ont besoin de guillemets que si elles contiennent des espaces ou des caractères spéciaux, et les balises <html>, <head> et <body> sont techniquement facultatives puisque le parser les déduit. Écrivez-les quand même. Les règles d'inférence sont subtiles, et être explicite ne coûte que trois lignes.
Des éléments porteurs de sens
Les éléments de sectionnement et de regroupement existent pour que la forme d'un document soit lisible par une machine. La plupart correspondent directement à un landmark d'accessibilité, ce qui permet à un utilisateur de lecteur d'écran de sauter directement à la navigation ou au contenu principal au lieu de tout réécouter depuis le début.
| Élément | À utiliser pour | Landmark exposé |
|---|---|---|
header | Le contenu d'introduction de la page ou d'une section | banner, s'il est enfant direct de body |
nav | Un bloc de liens de navigation principaux | navigation |
main | Le contenu principal, une seule fois par page | main |
article | Un élément autonome qui aurait du sens s'il était syndiqué | article |
section | Un regroupement thématique, normalement avec un titre | region, seulement s'il a un nom accessible |
aside | Un contenu annexe, comme une barre latérale ou une citation mise en exergue | complementary |
footer | Les informations de clôture de la page ou d'une section | contentinfo, s'il est enfant direct de body |
figure / figcaption | Un média accompagné d'une légende | aucun |
Deux d'entre eux sont couramment mal employés. section n'est pas une boîte générique : elle ne devient une région navigable que si elle possède un nom accessible, généralement fourni par un titre référencé via aria-labelledby. Et article ne veut pas dire « billet de blog » : un commentaire, une fiche produit ou une réponse sur un forum sont tous des articles, car le critère est de savoir si le bloc garderait son sens une fois extrait et affiché seul.
Les titres forment l'autre moitié de la structure. Les utilisateurs de lecteurs d'écran naviguent par les titres plus que par tout autre moyen ; les niveaux doivent donc décrire une vraie hiérarchie : un seul h1 qui nomme la page, des h2 pour ses grandes parties, des h3 pour leurs subdivisions. Ne choisissez jamais un niveau pour sa taille de police par défaut, c'est le rôle du CSS, et ne sautez jamais de niveau en descendant. Une div reste la bonne réponse quand un conteneur n'existe que pour la mise en page et qu'aucun élément ne décrit son contenu ; le problème, c'est seulement d'y recourir en premier.
Le head et les métadonnées que lisent les autres machines
Le head est l'endroit où vous vous adressez à des systèmes qui n'affichent jamais votre page. Un document en production contient en général bien plus que le minimum :
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Refund policy — Northwind Support</title>
<meta name="description" content="How refunds are calculated, how long they take and what to do if one is late." />
<link rel="canonical" href="https://example.com/support/refunds" />
<meta property="og:type" content="article" />
<meta property="og:title" content="Refund policy" />
<meta property="og:description" content="How refunds are calculated and how long they take." />
<meta property="og:image" content="https://example.com/img/refunds-card.png" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<meta name="theme-color" content="#0f172a" />
<link rel="preconnect" href="https://fonts.example.net" crossorigin />
</head>
Le title est la chaîne la plus précieuse de la page : il devient l'onglet du navigateur, le favori, la première chose qu'annonce un lecteur d'écran au chargement et, le plus souvent, le titre du résultat de recherche. Mettez le spécifique en tête et le nom du site à la fin. La description n'est pas un facteur de classement, mais elle est souvent reprise telle quelle comme extrait dans les résultats : elle doit donc se lire comme une phrase, pas comme une liste de mots-clés. Le lien canonique règle les problèmes d'URL en double (paramètres de tracking, barres obliques finales, versions imprimables) en désignant l'adresse que vous voulez voir indexée.
Les balises Open Graph déterminent l'affichage d'un lien collé dans une messagerie ou un réseau social. Elles ne coûtent presque rien à ajouter et brillent par leur absence dans la plupart des outils internes. Les resource hints comme preconnect et preload réduisent la latence vers les origines tierces ; employés sans discernement, ils produisent l'effet inverse, et leurs compromis méritent d'être compris en même temps que les techniques plus générales présentées dans performance applicative.
Formulaires, champs et validation offerte
Un formulaire est la partie la plus dense fonctionnellement de la plupart des pages, et c'est là que du JavaScript écrit à la main remplace le plus souvent quelque chose que le navigateur fait déjà mieux.
<form action="/subscribe" method="post">
<fieldset>
<legend>Delivery details</legend>
<label for="email">Email address</label>
<input id="email" name="email" type="email" autocomplete="email" required />
<label for="postcode">Postcode</label>
<input id="postcode" name="postcode" type="text" inputmode="numeric"
pattern="[0-9]{5}" autocomplete="postal-code" required
aria-describedby="postcode-hint" />
<p id="postcode-hint">Five digits, no spaces.</p>
<label for="qty">Quantity</label>
<input id="qty" name="qty" type="number" min="1" max="20" step="1" value="1" />
</fieldset>
<button type="submit">Subscribe</button>
</form>
Chaque contrôle a besoin d'un nom accessible, et le moyen fiable de lui en donner un est un label dont l'attribut for correspond à l'id du champ. Un placeholder n'est pas un label : il disparaît dès que l'on commence à taper, il ne respecte pas les exigences de contraste dans la plupart des maquettes, et certaines technologies d'assistance l'ignorent. L'attribut name est ce qui apparaît dans les données soumises : un contrôle qui n'en a pas n'envoie rien.
Choisir le bon type vous apporte des comportements que vous auriez sinon codés à la main : un clavier mobile adapté, un sélecteur de date, un sélecteur de couleur, la vérification du format. Ajoutez required, pattern, min, max, step et maxlength, et vous obtenez une validation déclarative qui fonctionne sans une ligne de script, expose :invalid et :user-invalid au CSS et reste accessible au clavier par construction. Pour des règles sur mesure, la Constraint Validation API permet de conserver la même mécanique : appelez setCustomValidity() sur l'élément, ou ajoutez novalidate au formulaire et gérez vous-même les messages.
Renseigner correctement les jetons autocomplete est une petite modification à l'effet disproportionné sur le taux de complétion, car elle permet au navigateur et au gestionnaire de mots de passe de remplir les valeurs connues. Et rien de tout cela ne constitue une frontière de sécurité : les attributs se modifient dans les devtools et les requêtes peuvent être envoyées directement à votre endpoint ; le serveur doit donc tout revalider et répondre avec un code de statut précis. La distinction entre un corps mal formé et un corps sémantiquement invalide est traitée dans la référence des codes de statut HTTP.
Images, médias et diffusion responsive
Les images représentent généralement la plus grosse part des octets d'une page : c'est donc ici que les choix de balisage pèsent le plus sur le temps de chargement.
<figure>
<img src="/img/chart-800.avif"
srcset="/img/chart-400.avif 400w,
/img/chart-800.avif 800w,
/img/chart-1600.avif 1600w"
sizes="(min-width: 60rem) 40rem, 100vw"
width="1600" height="900"
loading="lazy" decoding="async"
alt="Monthly refund volume falling from 1,200 in January to 300 in June." />
<figcaption>Refund volume after the policy change.</figcaption>
</figure>
srcset propose au navigateur plusieurs résolutions de la même image, et sizes lui indique la largeur réelle à laquelle elle sera affichée, pour qu'il puisse choisir avant même d'avoir analysé le CSS. Définissez toujours width et height : ils permettent au navigateur de réserver le bon emplacement avant l'arrivée du fichier, ce qui supprime le décalage de mise en page qui fait sauter le texte pendant le chargement. loading="lazy" diffère le chargement des images hors écran, mais ne l'appliquez jamais à l'image en haut de page : c'est justement celle que vous voulez récupérer en premier.
Quand il vous faut des sources vraiment différentes et non simplement des tailles différentes (un recadrage carré sur mobile, ou un format moderne avec un repli), utilisez picture avec plusieurs éléments source et un img final. Quel que soit le conteneur, c'est l'img qui porte le texte alt, et bien le rédiger est l'habitude d'accessibilité la plus rentable qui soit : décrivez l'information que l'image transmet dans son contexte, pas le fichier. Un ornement décoratif reçoit alt="" pour être entièrement ignoré ; omettre l'attribut pousse au contraire les lecteurs d'écran à lire le nom du fichier à voix haute. Avant de mettre des ressources en ligne, il vaut la peine de les passer dans un optimiseur comme le compresseur d'images ou de réduire les originaux surdimensionnés avec le redimensionneur d'images.
La vidéo et l'audio obéissent à la même logique. Ajoutez controls, sauf si vous les remplacez par des contrôles accessibles, fournissez des sous-titres avec un élément track de kind="captions", prévoyez une image poster et évitez autoplay avec le son. Préférez preload="metadata" à la valeur par défaut, pour qu'une page contenant plusieurs clips ne commence pas à tous les télécharger.
Des tableaux qui résistent à un lecteur d'écran
Les tableaux servent aux données, jamais à la mise en page. Le balisage qui en rend un navigable tient en peu de choses :
<table>
<caption>Refunds by region, first half of 2026</caption>
<thead>
<tr><th scope="col">Region</th><th scope="col">Requests</th><th scope="col">Median days</th></tr>
</thead>
<tbody>
<tr><th scope="row">North</th><td>1,204</td><td>3.1</td></tr>
<tr><th scope="row">South</th><td>884</td><td>4.6</td></tr>
</tbody>
</table>
La caption donne un nom au tableau, th avec scope indique aux technologies d'assistance quelles cellules servent d'en-têtes et dans quelle direction, et marquer la première cellule de chaque ligne comme en-tête de ligne permet à un lecteur d'écran d'annoncer « North, median days, 3.1 » plutôt qu'un nombre isolé. Pour les tableaux irréguliers à cellules fusionnées, les attributs headers et id permettent d'associer les cellules explicitement. Si un tableau est large, placez-le dans un conteneur défilant doté de tabindex="0" et d'un rôle, pour que les utilisateurs au clavier puissent atteindre la partie qui déborde.
Les API fournies par la plateforme
En plus des éléments, les navigateurs exposent une vaste bibliothèque standard qu'il vaut la peine de connaître avant d'ajouter une dépendance pour la même chose. localStorage et sessionStorage stockent de petites chaînes de façon synchrone et conviennent parfaitement à une préférence de thème, mais pas du tout à une donnée sensible, puisque n'importe quel script de l'origine peut les lire. IndexedDB gère un stockage structuré, plus volumineux et asynchrone. canvas offre une surface de pixels pour les graphiques et le traitement d'images, tandis que le SVG inline reste net et demeure dans le DOM, où l'on peut le styliser et le rendre accessible. La History API réécrit la barre d'adresse sans rechargement : c'est ainsi que fonctionnent les routeurs côté client. Les Web Workers déportent les calculs coûteux hors du thread principal. Les custom elements permettent d'empaqueter un widget sous forme de vraie balise, avec ses propres styles encapsulés. On accède à la plupart de ces API via JavaScript, et les notions du langage dont vous aurez besoin sont présentées dans les fondamentaux de JavaScript.
Valider, et les erreurs qui survivent à la revue
Faites passer votre balisage au validateur du W3C, ou à un linter équivalent intégré à votre build, et traitez ses retours comme des erreurs de build. Puisque le parser répare les erreurs en silence, la validation est le seul moyen peu coûteux de repérer les problèmes de structure. Les plus fréquents :
- Des valeurs d'
iden double, généralement dues à un template répété. Les associations de labels et les liens vers des ancres pointent alors sur le premier élément rencontré. - Des champs sans label, cachés derrière un placeholder ou une icône dépourvue de nom accessible.
- Des niveaux de titre choisis pour leur taille, qui donnent un plan sautant de
h1àh4. - Des éléments
divinteractifs dotés d'un gestionnaire de clic mais sans prise en charge du clavier. Si cela se comporte comme un bouton, faites-en unbutton. - Un texte
altqui répète la légende ou commence par « image de », ce que les lecteurs d'écran annoncent déjà. - L'absence de
widthetheightsur les images, cause la plus fréquente de décalage de mise en page. - Des contrôles interactifs imbriqués, comme un lien dans un bouton, dont le comportement au clavier n'est pas défini.
- De l'ARIA pour rafistoler un mauvais balisage. Un mauvais rôle est pire que pas de rôle du tout ; la première règle d'ARIA est d'utiliser plutôt l'élément natif.
Points clés à retenir
- Le HTML est un standard vivant sans numéro de version : écrivez en suivant la spécification du WHATWG et vérifiez la compatibilité sur MDN plutôt que d'attendre la prochaine version.
- Les éléments forment une interface à la fois pour les navigateurs, les technologies d'assistance et les robots d'indexation : choisissez-les selon leur sens, et les landmarks d'accessibilité comme le plan du document viennent tout seuls.
- Le head détermine la façon dont les machines voient la page : un titre exact, une vraie description, une URL canonique et des balises Open Graph prennent quelques minutes et rapportent durablement.
- Les contrôles de formulaire natifs, les types d'input et la validation par contraintes offrent une validation accessible et utilisable au clavier sans script, mais ne remplacent jamais la validation côté serveur.
- Les images responsives avec
srcset, des dimensions explicites, un textealthonnête et des médias sous-titrés sont les gains de performance et d'accessibilité les moins chers qui existent. - Validez votre balisage et traitez les défauts récurrents (ids en double, champs sans label, div cliquables, ARIA plaqué sur le mauvais élément) comme des bugs, pas comme des questions de style.
Sources et lectures complémentaires
Questions fréquentes
- HTML5 est-il toujours la version actuelle du HTML ?
- Non. Le HTML n'est plus publié sous forme de versions numérotées depuis 2019, date à laquelle le W3C et le WHATWG ont convenu que le HTML Living Standard du WHATWG serait l'unique spécification. Il est mis à jour en continu, si bien que les nouveautés arrivent sans changement de version. Le terme HTML5 survit comme raccourci pour désigner le jeu d'éléments moderne et les API du navigateur apparues en même temps, mais il n'y a aucun HTML6 à l'horizon.
- Quand utiliser une div plutôt qu'un élément sémantique ?
- Utilisez une div quand le conteneur n'existe que pour le style ou la mise en page et qu'aucun élément existant ne décrit son contenu. Si le bloc est la navigation du site, un contenu autonome, le pied de page ou le contenu principal du document, l'élément sémantique correspondant offre gratuitement un landmark aux technologies d'assistance. Partir d'une div puis ajouter un rôle ARIA après coup demande plus de travail et laisse bien plus de place à l'erreur.
- La validation côté client reste-t-elle utile si le serveur valide déjà ?
- Oui, mais pour une autre raison. La validation par contraintes du navigateur fournit un retour immédiat, accessible au clavier, et bloque les soumissions manifestement mal formées : c'est un gain d'ergonomie. Ce n'est pas un dispositif de sécurité, car n'importe qui peut désactiver JavaScript, modifier les attributs ou envoyer directement une requête à votre endpoint. Considérez chaque champ comme non fiable côté serveur et renvoyez un code de statut précis en cas d'échec.
- Quelle différence entre srcset et l'élément picture ?
- srcset, combiné à sizes, laisse le navigateur choisir parmi plusieurs versions d'une même image qui ne diffèrent que par leur résolution ; il tranche selon la largeur du viewport, la densité de pixels de l'écran et ses propres heuristiques. L'élément picture sert aux cas où vous devez maîtriser ce choix vous-même : un recadrage différent sur petit écran, ou un fichier AVIF avec un repli en JPEG pour les navigateurs incapables de le décoder.