MFormations
Modern Frontend Engineering

Chapitre 3

Chapitre 03 — HTML : HyperText Markup Language

Chapitre 03 — HTML : HyperText Markup Language

Chapitre 03 — HTML : Cours Complet

1. Histoire et Évolution du HTML

1.1 Les Origines : SGML

Le HTML trouve ses racines dans le SGML (Standard Generalized Markup Language, ISO 8879:1986), un métalangage de balisage conçu pour la structuration de documents. SGML est extrêmement puissant mais complexe — sa spécification fait plus de 500 pages. Tim Berners-Lee, au CERN en 1989, avait besoin d'un format plus simple pour partager des documents scientifiques hypertextes.

Diagramme en cours de génération...

1.2 HTML 1.0 → HTML 4.01

  • HTML 1.0 (1991-1993) : 18 balises, pas de standard formel
  • HTML 2.0 (RFC 1866, 1995) : Premier standard IETF, formulaires basiques
  • HTML 3.2 (1997) : Tables, applets, scripts, feuilles de style
  • HTML 4.0 (1997) : Séparation structure/présentation, CSS encouragé, frames
  • HTML 4.01 (1999) : Dernière révision majeure du W3C pendant 15 ans

1.3 La Guerre des Standards : XHTML vs HTML5

En 2000, le W3C pousse XHTML 1.0 (XML strict) pour forcer des documents bien formés. Mais l'approche XML est impopulaire auprès des développeurs. En 2004, Apple, Mozilla et Opera quittent le W3C et forment le WHATWG (Web Hypertext Application Technology Working Group), qui commence à travailler sur ce qui deviendra HTML5.

Le WHATWG Living Standard est aujourd'hui la spécification de référence unique.

2. HTML Sémantique

2.1 Qu'est-ce que le HTML Sémantique ?

Le HTML sémantique consiste à utiliser des balises qui décrivent le sens du contenu, pas son apparence.

BaliseRôleUsage typique
<header>En-tête (section ou page)Logo, navigation, titre
<nav>Navigation principaleMenus, tables des matières
<main>Contenu principal uniqueContenu central de la page
<article>Contenu autonomeArticle de blog, commentaire
<section>Section thématiqueRegroupement logique
<aside>Contenu tangentielSidebar, notes, publicités
<footer>Pied de pageCopyright, liens, infos

2.2 Pourquoi le HTML Sémantique ?

SEO : Google privilégie le contenu structuré. Les balises sémantiques aident les crawlers à comprendre la hiérarchie et la pertinence du contenu. Les rich snippets (étoiles, prix, recettes) n'existent que grâce au balisage sémantique.

Accessibilité : Les lecteurs d'écran utilisent les landmarks ARIA dérivés du HTML sémantique pour naviguer. Un utilisateur de NVDA ou JAWS peut sauter de <nav> à <main> à <footer> sans toucher la souris.

Maintenabilité : Un code sémantique est auto-documenté. Un développeur qui lit <article> comprend immédiatement qu'il s'agit d'un contenu autonome.

2.3 Structure Type d'un Document

<body>
  <header>
    <nav>
      <ul>
        <li><a href="/">Accueil</a></li>
        <li><a href="/blog">Blog</a></li>
      </ul>
    </nav>
  </header>
  <main>
    <article>
      <header><h1>Mon Article</h1></header>
      <section>
        <h2>Introduction</h2>
        <p>Contenu...</p>
      </section>
      <footer>Publié le 01/01/2026</footer>
    </article>
    <aside>
      <h2>Articles connexes</h2>
      <ul>...</ul>
    </aside>
  </main>
  <footer>
    <p>© 2026 Mon Site</p>
  </footer>
</body>

3. Accessibilité Web : WCAG et ARIA

3.1 WCAG (Web Content Accessibility Guidelines)

Les WCAG sont organisés en 4 principes (POUR) :

PrincipeDescriptionExemple
PerceivablePerceptibleAlternatives textuelles, sous-titres
OperableUtilisableNavigation clavier, pas d'épilepsie
UnderstandableCompréhensibleLangage clair, comportement prévisible
RobustRobusteCompatibilité avec les technologies d'assistance

Trois niveaux de conformité : A (minimum), AA (standard légal), AAA (expert).

3.2 ARIA (Accessible Rich Internet Applications)

ARIA ne modifie pas le comportement d'un élément, seulement sa représentation dans l'arbre d'accessibilité.

Règles d'or ARIA :

  1. Ne pas utiliser ARIA si le HTML natif suffit : <button> > <div role="button">
  2. Les attributs ARIA doivent être dynamiquement maintenus : aria-expanded doit changer avec l'état
  3. Ne pas cacher des éléments focusables : aria-hidden="true" sur un élément focusable le rend invisible mais focusable → bug
<!-- Mauvais usage -->
<div role="button" onclick="submit()">Envoyer</div>

<!-- Bon usage -->
<button type="submit" aria-busy="false">Envoyer</button>

3.3 Landmarks

Les landmarks sont des régions de la page que les lecteurs d'écran exposent pour la navigation rapide. Le HTML sémantique les génère automatiquement :

Rôle ARIAÉlément HTMLUsage
banner<header> (contexte body)En-tête du site
navigation<nav>Bloc de navigation
main<main>Contenu principal
complementary<aside>Contenu complémentaire
contentinfo<footer> (contexte body)Infos de pied de page
region<section> (avec label)Section thématique

4. Formulaires HTML5

4.1 Nouveaux Types d'Input

HTML5 a introduit des types d'input qui améliorent l'expérience mobile et la validation :

<input type="email">     <!-- Validation email côté navigateur -->
<input type="url">       <!-- Validation URL -->
<input type="tel">       <!-- Clavier téléphone sur mobile -->
<input type="number">    <!-- Stepper, validation numérique -->
<input type="range">     <!-- Slider -->
<input type="date">      <!-- Date picker natif -->
<input type="color">     <!-- Color picker -->
<input type="search">    <!-- Champ de recherche (UI différente) -->

4.2 Validation Native

La validation native utilise des attributs sans JavaScript :

<form novalidate>
  <label for="email">Email :</label>
  <input
    type="email"
    id="email"
    name="email"
    required
    minlength="5"
    maxlength="100"
    pattern="[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}"
  />
  <span class="error" aria-live="polite"></span>
  <button type="submit">Envoyer</button>
</form>

<script>
  const form = document.querySelector('form');
  const email = document.getElementById('email');
  const errorSpan = document.querySelector('.error');

  email.addEventListener('input', () => {
    if (email.validity.valid) {
      errorSpan.textContent = '';
      errorSpan.hidden = true;
    } else {
      errorSpan.textContent = email.validationMessage;
      errorSpan.hidden = false;
    }
  });

  form.addEventListener('submit', (e) => {
    if (!form.checkValidity()) {
      e.preventDefault();
      // Focus sur le premier champ invalide
      form.querySelector(':invalid')?.focus();
    }
  });
</script>

4.3 Constraint Validation API

L'API expose ValidityState sur chaque élément de formulaire :

const state = input.validity;
// state.valueMissing     → required non rempli
// state.typeMismatch     → type email/URL invalide
// state.patternMismatch  → regex non respectée
// state.tooLong          → dépasse maxlength
// state.tooShort         → ne fait pas minlength
// state.rangeUnderflow   → valeur < min
// state.rangeOverflow    → valeur > max
// state.stepMismatch     → pas aligné sur step
// state.badInput         → entrée non convertible
// state.customError      → setCustomValidity() défini
// state.valid            → tout est bon

Méthodes clés : checkValidity(), reportValidity(), setCustomValidity(message).

5. Attributs Globaux

Les attributs globaux s'appliquent à (presque) tous les éléments HTML :

AttributRôle
classSélection CSS / JS
idIdentifiant unique (ancre, target)
langLangue du contenu (accessibilité, traduction)
dirDirection du texte (ltr, rtl, auto)
hiddenÉlément non affiché (display: none natif)
inertÉlément inerte (ni cliquable, ni focusable, ni accessible)
data-*Données personnalisées accessibles via dataset
slotAttribution à un slot Shadow DOM
spellcheckCorrection orthographique
translateTraduction automatique (yes/no)
tabindexOrdre de tabulation
aria-*Accessibilité
roleRôle ARIA

inert : Le Nouvel Attribut Puissant

inert (supporté partout depuis 2022) rend un élément et ses descendants totalement inactifs :

  • Pas de focus (ni clavier, ni programmatique)
  • Pas de clics
  • Pas d'événements
  • Invisible dans l'arbre d'accessibilité
<!-- Modal pattern avec inert -->
<div id="modal-backdrop" inert>
  <dialog open>
    <h2>Modal</h2>
    <button>Fermer</button>
  </dialog>
</div>

6. HTML Templates et Shadow DOM

6.1 L'Élément <template>

Le <template> contient du HTML inactif (ni rendu, ni chargé) qui peut être instancié en JavaScript :

<template id="card-template">
  <article class="card">
    <img src="" alt="" loading="lazy">
    <h3 class="card-title"></h3>
    <p class="card-description"></p>
  </article>
</template>

<script>
  class CardList extends HTMLElement {
    connectedCallback() {
      const data = JSON.parse(this.getAttribute('data-items') || '[]');
      const template = document.getElementById('card-template');
      const fragment = template.content.cloneNode(true);
      // Remplir le template...
      this.appendChild(fragment);
    }
  }
</script>

6.2 Shadow DOM

Le Shadow DOM encapsule le style et la structure d'un composant :

class MonWidget extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style>
        :host { display: block; border: 1px solid #ccc; padding: 1rem; }
        :host([theme="dark"]) { background: #333; color: white; }
        ::slotted(p) { margin: 0; }
      </style>
      <slot name="title">Titre par défaut</slot>
      <slot></slot>
    `;
  }
}
customElements.define('mon-widget', MonWidget);

Modes Open vs Closed

  • open : element.shadowRoot accessible depuis l'extérieur (testable, inspectable)
  • closed : element.shadowRoot retourne null (ne JAMAIS utiliser — casse l'accessibilité, le testing)

6.3 <slot> : Projection de Contenu

Les slots permettent de projeter du contenu de l'hôte dans le Shadow DOM :

<mon-widget>
  <h2 slot="title">Mon Titre</h2>
  <p>Contenu projeté dans le slot par défaut</p>
</mon-widget>

7. Web Components : Standard du Web

Les Web Components reposent sur 3 technologies :

Diagramme en cours de génération...

7.1 Lifecycle des Custom Elements

class MonElement extends HTMLElement {
  constructor() {
    super(); // Toujours appeler super() en premier
    // Initialisation des états, Shadow DOM
  }

  // Appelé quand l'élément est ajouté au DOM
  connectedCallback() {
    // Setup : event listeners, fetching data
  }

  // Appelé quand l'élément est retiré du DOM
  disconnectedCallback() {
    // Cleanup : removeEventListener, annuler requêtes
  }

  // Appelé quand un attribut observé change
  attributeChangedCallback(name, oldValue, newValue) {
    // Réagir aux changements d'attributs
  }

  // Déclarer les attributs à observer
  static get observedAttributes() {
    return ['open', 'disabled', 'value'];
  }
}

7.2 Bonnes Pratiques Web Components

  1. Toujours définir observedAttributes pour que attributeChangedCallback fonctionne
  2. Utiliser les getters/setters pour synchroniser propriétés et attributs
  3. Éviter closed Shadow DOM (casse l'accessibilité et le test)
  4. Définir les Custom Elements avec des noms kebab-case (obligatoire)
  5. Ne pas étendre les éléments natifs (extends est déprécié)

8. SEO Meta : Open Graph, Twitter Cards, Schema.org

8.1 Open Graph (OG)

<meta property="og:title" content="Titre de la page">
<meta property="og:description" content="Description pour les réseaux sociaux">
<meta property="og:image" content="https://example.com/image.jpg">
<meta property="og:url" content="https://example.com/page">
<meta property="og:type" content="article">
<meta property="og:locale" content="fr_FR">

8.2 Twitter Cards

<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@monsite">
<meta name="twitter:title" content="Titre">
<meta name="twitter:description" content="Description">
<meta name="twitter:image" content="https://example.com/image.jpg">

8.3 Schema.org avec JSON-LD

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "Titre de l'article",
  "author": {
    "@type": "Person",
    "name": "Jean Dupont"
  },
  "datePublished": "2026-07-28",
  "description": "Résumé de l'article"
}
</script>

8.4 Structure de Données avec microdata

<article itemscope itemtype="https://schema.org/Article">
  <h1 itemprop="headline">Titre</h1>
  <p itemprop="description">Description</p>
  <span itemprop="author" itemscope itemtype="https://schema.org/Person">
    <span itemprop="name">Jean Dupont</span>
  </span>
</article>

9. Performance des Scripts et Ressources

9.1 async vs defer

Diagramme en cours de génération...
<!-- BLOCKING : mauvais -->
<script src="heavy.js"></script>

<!-- ASYNC : ordre non garanti, exécution dès chargement -->
<script async src="analytics.js"></script>

<!-- DEFER : exécution ordonnée après parse HTML -->
<script defer src="app.js"></script>
<script defer src="vendor.js"></script>

9.2 Resource Hints

<!-- Preload : charger une ressource critique immédiatement -->
<link rel="preload" href="fonts/inter-var.woff2" as="font" crossorigin>

<!-- Prefetch : charger une ressource pour la page suivante -->
<link rel="prefetch" href="/blog/page-2.html">

<!-- Preconnect : établir connexion anticipée -->
<link rel="preconnect" href="https://api.example.com">

<!-- DNS-Prefetch : fallback pour navigateurs anciens -->
<link rel="dns-prefetch" href="https://api.example.com">

<!-- Prerender : pré-rendre toute la page suivante (lourd) -->
<link rel="prerender" href="/blog/page-2.html">

10. Bonnes Pratiques et Structure

10.1 Checklist de Base

  • <!DOCTYPE html> HTML5
  • Attribut lang sur <html> (ex: <html lang="fr">)
  • <meta charset="UTF-8"> en premier dans <head>
  • <meta name="viewport" content="width=device-width, initial-scale=1">
  • Structure sémantique : header → main → footer
  • Navigation accessible avec <nav> et aria-current="page"
  • Images avec alt descriptif (ou alt="" pour décoratives)
  • Titres hiérarchiques : h1 → h2 → h3 (pas de sauts)
  • Formulaires avec <label> associé
  • Boutons = <button>, pas <div> ou <a>
  • Liens avec texte descriptif (pas "cliquez ici")
  • Validation HTML via W3C Validator

10.2 Erreurs des Juniors

Div-itis : L'utilisation excessive de <div> au lieu d'éléments sémantiques.

<!-- Junior -->
<div class="header">
  <div class="nav">
    <div class="nav-item">Accueil</div>
  </div>
</div>

<!-- Senior -->
<header>
  <nav>
    <ul>
      <li><a href="/">Accueil</a></li>
    </ul>
  </nav>
</header>

Mauvais nesting : Les éléments de bloc dans les éléments inline, les boutons dans les liens, etc.

<!-- INVALIDE : <p> ne peut pas contenir <div> -->
<p>Texte <div>bloc</div></p>

<!-- VALIDE -->
<div><p>Texte</p></div>

Oubli de l'attribut alt : Image sans alternative textuelle = inaccessible.

<!-- Mauvais : image décorative sans alt -->
<img src="decorative-bg.jpg">

<!-- Correct : alt vide pour décorative -->
<img src="decorative-bg.jpg" alt="" role="presentation">

<!-- Correct : alt descriptif pour image informative -->
<img src="logo.png" alt="Logo de l'entreprise Acme Inc.">

Heading skips : Sauter des niveaux de titre (h1 → h3).

<!-- Mauvais : h1 → h3 (skipping h2) -->
<h1>Titre principal</h1>
<h3>Sous-section</h3>

<!-- Correct -->
<h1>Titre principal</h1>
<h2>Sous-section</h2>

Boutons non focusables ou sans rôle :

<!-- Mauvais : pas focusable, pas accessible -->
<div onclick="submit()">Envoyer</div>

<!-- Correct -->
<button type="submit">Envoyer</button>

11. Standards et Validation

11.1 Living Standard vs W3C

Depuis 2021, le WHATWG Living Standard est la norme unique. Le W3C a cessé de publier des versions snapshot. Les navigateurs implémentent le Living Standard.

11.2 Validité HTML

Utiliser le W3C Validator :

# Linter HTML avec HTML-validate
npx html-validate src/**/*.html

# Vérification avec Nu HTML Checker
curl -H "Content-Type: text/html; charset=utf-8" \
  --data-binary @index.html \
  https://validator.w3.org/nu/?out=json

11.3 Polyfills et Progression

Pour les fonctionnalités modernes dans les navigateurs anciens :

<script>
  if (!('inert' in HTMLElement.prototype)) {
    // Charger le polyfill inert
    const script = document.createElement('script');
    script.src = 'https://cdn.jsdelivr.net/npm/wicg-inert@3/dist/inert.min.js';
    document.head.appendChild(script);
  }
</script>

12. Internationalisation (i18n)

<html lang="fr" dir="ltr">
<head>
  <meta charset="UTF-8">
</head>
<body>
  <!-- Attribut lang sur chaque élément de langue différente -->
  <p>Ceci est en français.</p>
  <p lang="en">This is in English.</p>

  <!-- Attr dir pour les langues RTL -->
  <p lang="ar" dir="rtl">مرحبا بالعالم</p>
</body>
</html>

Résumé

Le HTML moderne est puissant et expressif. La sémantique, l'accessibilité et la performance ne sont pas optionnelles — ce sont des piliers du développement web professionnel. Un ingénieur front-end maîtrise :

  1. La structure sémantique du document
  2. L'accessibilité (WCAG AA minimum)
  3. Les formulaires (validation native + API)
  4. Les Web Components (Custom Elements + Shadow DOM)
  5. Le SEO technique (Open Graph, Schema.org)
  6. La performance (async/defer, preload)
  7. L'internationalisation