Définir un balisage HTML optimisé
Structurez et automatisez votre balisage HTML avec les bonnes techniques, données structurées et bonnes pratiques.

Écrivez votre HTML une seule fois, sous forme de template où chaque balise est reliée à un champ de données et dispose d’une solution de repli. En SEO programmatique, une canonique manquante ou un H1 dupliqué n’est jamais un bug d’une seule page. Un template correct, ce sont des milliers de pages correctes.
Voici le template du site d’emploi illustratif du chapitre sur le zoning, dans une syntaxe de type Handlebars. La suite du chapitre explique les choix qu’il contient.
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{metaTitle}}</title>
<meta name="description" content="{{metaDescription}}">
{{#if isIndexable}}
<link rel="canonical" href="{{canonicalUrl}}">
{{else}}
<meta name="robots" content="noindex, follow">
{{/if}}
</head>
<body>
<header><!-- navigation du site --></header>
<nav aria-label="Fil d’Ariane">
<ol>
<li><a href="/">Accueil</a></li>
<li><a href="/emploi/{{roleSlug}}">Emploi {{roleName}}</a></li>
<li aria-current="page">{{cityName}}</li>
</ol>
</nav>
<main>
<h1>Emploi {{roleName}} à {{cityName}}</h1>
<p>{{liveJobs}} offres en ligne, mises à jour le {{updatedAt}}.</p>
<section>
<h2>Dernières offres {{roleName}}</h2>
<ul>
{{#each jobs}}
<li><a href="{{url}}">{{title}}</a>, {{employer}}</li>
{{/each}}
</ul>
</section>
{{#if hasPayData}}
<section>
<h2>Salaire {{roleName}} à {{cityName}}</h2>
<p>Salaire courant annoncé : {{medianPay}}.</p>
</section>
{{/if}}
</main>
<footer><!-- contact, mentions légales --></footer>
</body>
</html>
Servez ce HTML depuis le serveur ou au moment du build, comme le fait un générateur statique tel qu’Astro. Google sait exécuter le JavaScript, mais ne comptez pas sur tous les crawlers pour en faire autant, y compris ceux qui collectent du contenu pour les réponses générées par IA.
Des titres qui décrivent la page
Le H1 est unique sur chaque page, porte le pattern de requête principal et ouvre le contenu. Les H2 divisent les grandes sections, les H3 les subdivisent. Les niveaux H4 à H6 servent aux contenus vraiment détaillés, comme les sous-parties d’une longue spécification, et la plupart des pages générées n’en ont jamais besoin.
Deux habitudes gardent tout cela propre à grande échelle. Choisissez le niveau d’un titre selon sa place dans le plan et laissez le CSS gérer la taille. Et faites varier les H2 avec les données, comme dans le template, pour que le plan de la page dise quelque chose de ce métier et de cette ville au lieu de répéter « Nos offres » 3 000 fois.
Utilisez aussi les éléments sémantiques : main, nav, section, ul, ol. Ils ne coûtent rien, aident les technologies d’assistance et permettent à n’importe quel parseur de distinguer votre contenu du décor de la page.
Des balises title et description construites par règles
Il n’existe pas de limite officielle de caractères pour les titres. Google tronque selon la largeur d’affichage, et il peut réécrire le lien de titre s’il estime qu’un autre texte décrit mieux la page. Environ 60 caractères est une cible raisonnable pour le titre, et 150 à 160 pour la description. La vraie difficulté vient de la longueur très variable des données, d’où l’intérêt d’une solution de repli :
function buildTitle({ role, city, jobCount }) {
const full = `${jobCount} offres ${role} à ${city} | EmploiHotellerie`;
return full.length <= 60 ? full : `Emploi ${role} à ${city}`;
}
Cette fonction marche dans un script de build comme dans Google Apps Script si vos données vivent dans un Sheet. Pour les descriptions, intégrez une valeur qui change d’une page à l’autre, comme le nombre d’offres ou le principal employeur. Une description identique partout à un mot près se fait réécrire ou ignorer, et rapporte peu de clics dans tous les cas.
Des règles d’indexation pilotées par les données
N’appliquez pas les directives robots à la main. Déduisez-les de l’état des données de la page :
| État de la page | Robots | Canonique | Dans le sitemap |
|---|---|---|---|
| Assez d’offres en ligne | Aucune balise (indexable par défaut) | Elle-même | Oui |
| Sous votre seuil | noindex, follow |
Aucune | Non |
URL triée ou filtrée, comme ?sort=date |
Aucune balise | L’URL propre | Non |
index, follow est la valeur par défaut, l’écrire n’apporte rien. N’oubliez pas qu’une page bloquée dans le robots.txt ne peut pas montrer son noindex à Google, puisqu’il ne la récupère jamais. Utilisez l’un ou l’autre selon le but recherché. La liste complète des directives se trouve dans la documentation de Google sur la balise meta robots. L’ordre de mise en ligne relève du chapitre sur la mise en production et l’indexation.
Des images qui décrivent quelque chose
Utilisez des noms de fichiers descriptifs (commis-cuisine-lyon.webp plutôt que image123.jpg) et rédigez un texte alternatif qui dit ce que montre l’image. Générer « emploi commis de cuisine Lyon » dans l’attribut alt de chaque image répète un mot-clé et n’apprend rien à quelqu’un qui utilise un lecteur d’écran. Si une image est purement décorative, utilisez alt="".
Le lazy loading économise de la bande passante, avec une exception. L’image principale en haut de page doit se charger immédiatement, sinon vous dégradez votre Largest Contentful Paint :
<img src="/img/hero.webp" alt="Chef dressant une assiette dans un restaurant lyonnais"
width="1200" height="630" fetchpriority="high">
<img src="/img/employer.webp" alt="Salle du restaurant"
width="600" height="400" loading="lazy">
Les attributs width et height réservent l’espace et évitent les décalages de mise en page.
Des liens que les crawlers peuvent suivre
Les liens internes doivent être de vrais éléments <a href>. Un gestionnaire de clic sur un div fonctionne à la souris et ne laisse rien à suivre aux crawlers. Les liens contextuels et le fil d’Ariane ont tous deux besoin de cette forme, et le fil d’Ariane du template sert aussi de navigation aux utilisateurs.
Pour les liens externes, pointez vers des sources fiables quand elles appuient ce que dit la page. Je n’utiliserais pas nofollow pour retenir de l’autorité. Cette tactique n’a plus de sens depuis longtemps, et Google traite les valeurs rel comme des indications. Utilisez rel="sponsored" pour les liens payants, rel="ugc" pour les liens soumis par les utilisateurs, et nofollow quand vous ne voulez vraiment pas cautionner une destination.
Des données structurées fidèles à la page
Prenez le type qui correspond à la page : Article ou BlogPosting pour l’éditorial, Product avec Offer pour les fiches produit, BreadcrumbList presque partout, et dans notre exemple JobPosting uniquement sur les pages d’offre individuelles, car les consignes de Google excluent les pages qui listent plusieurs offres. Générez les valeurs à partir des mêmes champs que le contenu visible :
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Accueil", "item": "https://www.example.com/" },
{ "@type": "ListItem", "position": 2, "name": "Emploi commis de cuisine", "item": "https://www.example.com/emploi/commis-de-cuisine" },
{ "@type": "ListItem", "position": 3, "name": "Lyon" }
]
}
</script>
FAQPage reste un vocabulaire schema.org valide, mais ne comptez pas sur un résultat enrichi : Google les a limités en 2023 aux sites gouvernementaux et de santé faisant autorité, et a aussi supprimé les résultats enrichis HowTo. Les données structurées rendent quand même votre page plus facile à lire pour les machines, y compris celles qui composent les réponses générées par IA. Le chapitre sur les microdonnées détaille chaque type.
Automatisez le balisage, puis vérifiez-le
Les placeholders ci-dessus peuvent être remplis depuis l’endroit où vivent vos données. Sur de petits projets, Google Sheets avec Apps Script génère titres et descriptions ligne par ligne. L’API d’un CMS, sur Webflow ou WordPress, permet à un script de pousser ces champs sur chaque élément. Sur une stack sur mesure, Astro ou n’importe quel générateur statique les construit à la compilation.
L’automatisation reproduit aussi fidèlement les erreurs, alors vérifiez ce qui sort. Crawlez un échantillon et cherchez dans le HTML rendu les fuites comme {{, undefined, NaN ou les balises <h1> vides. Confirmez que les titres sont uniques, testez quelques URL dans le test des résultats enrichis et avec l’outil d’inspection d’URL de la Search Console, et lisez cinq pages comme le ferait un visiteur. L’utilité d’une page vient des données et du zoning. Un balisage propre garantit seulement que cette utilité arrive jusqu’à la machine.
Votre prochaine étape
Écrivez votre template avec les vrais noms de variables de votre base, puis générez vos pages éligibles la plus riche et la plus pauvre. Passez-les toutes les deux aux contrôles ci-dessus et corrigez toute fuite. Définissez ensuite vos types de données structurées, champ par champ, avant de brancher le template en production.