Skip to content

HTML Aide-mémoire

Le langage de balisage standard pour créer des pages web.

01

Structure du document

Modèle de page de base

Chaque document HTML5 commence par <!DOCTYPE html>, suivi de <html> avec un attribut lang pour l'accessibilité et le SEO. Le <head> contient les métadonnées (charset, viewport, title), et le <body> contient le contenu visible. La balise méta viewport assure un rendu correct sur les appareils mobiles.

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Web Page</title>
</head>
<body>
  <h1>Hello, World!</h1>
  <p>Welcome to my page.</p>
</body>
</html>

Section head & métadonnées

L'élément <head> contient des métadonnées lisibles par machine. charset déclare l'encodage de caractères (UTF-8 couvre presque tous les caractères). La balise méta description est cruciale pour le SEO — les moteurs de recherche l'affichent dans les résultats. Utilisez defer sur les scripts pour les charger après le parsing HTML.

html
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Page Title - Site Name</title>
  <meta name="description" content="A brief description for SEO">
  <meta name="author" content="John Doe">
  <link rel="stylesheet" href="style.css">
  <script src="app.js" defer></script>
</head>

Commentaires & commentaires conditionnels

Les commentaires HTML commencent par <!-- et se terminent par -->. Ils ne sont pas affichés dans le navigateur mais sont visibles dans le code source de la page. Les commentaires sont utiles pour laisser des notes, marquer des sections (TODO, FIXME) et la documentation. Les commentaires conditionnels (IE uniquement) sont obsolètes mais peuvent apparaître dans le code legacy.

html
<!-- This is a single-line comment -->

<!--
  This is a
  multi-line comment
-->

<!-- TODO: Add form validation -->
<!-- FIXME: Fix layout on mobile -->

<!--[if lt IE 9]>
  <script src="html5shiv.js"></script>
<![endif]-->

Hiérarchie des titres

HTML fournit six niveaux de titres, h1 (le plus élevé) à h6 (le plus bas). Utilisez-les dans l'ordre hiérarchique sans sauter de niveaux. Les moteurs de recherche utilisent les titres pour comprendre la structure de la page. Bonne pratique : un h1 par page, suivi de h2 pour les sections majeures, h3 pour les sous-sections, etc.

html
<h1>Main Page Title</h1>
<h2>Major Section</h2>
<h3>Subsection</h3>
<h4>Sub-subsection</h4>
<h5>Minor Heading</h5>
<h6>Lowest Level Heading</h6>

<!-- Use only one h1 per page for SEO -->
<h1>Blog Post Title</h1>
<h2>Introduction</h2>
<h3>Background</h3>

Conteneurs Div & Span

<div> est un conteneur de niveau bloc utilisé pour regrouper des éléments et appliquer des styles. <span> est un conteneur en ligne pour styliser de petites portions de texte. Les deux sont des éléments génériques sans signification sémantique — préférez les balises sémantiques (header, nav, main, article) quand approprié pour une meilleure accessibilité et SEO.

html
<div class="container">
  <div id="header" class="header">
    <span class="logo">MySite</span>
    <span class="tagline">Best Content</span>
  </div>
  <div class="content">
    <p>Main <span class="highlight">content</span> here.</p>
  </div>
</div>
02

Formatage de texte

Gras, italique & emphase

<strong> indique un texte important (les lecteurs d'écran l'accentuent), tandis que <b> est purement visuel. De même, <em> indique une emphase de stress (sémantique), tandis que <i> est de l'italique visuel. Préférez <strong> et <em> pour l'accessibilité. <b> et <i> sont acceptables à des fins stylistiques sans importance sémantique.

html
<p>This is <strong>important</strong> text.</p>
<p>This is <b>bold</b> text.</p>
<p>This is <em>emphasized</em> text.</p>
<p>This is <i>italic</i> text.</p>
<p><strong>Warning:</strong> Do not touch!</p>

Mark, Delete & Insert

<mark> surligne le texte comme pertinent (comme un surlignage de recherche). <del> marque le texte supprimé, <ins> marque le texte inséré — utile pour montrer les éditions. <s> barre les infos obsolètes. <small> est pour les commentaires latéraux ou le copyright. <u> devrait être utilisé avec précaution car il ressemble à des liens.

html
<p>Please <mark>highlight this</mark> word.</p>
<p>The price is <del>$99</del> <ins>$79</ins> now.</p>
<p><s>Old information</s> is struck through.</p>
<p>Use <u>underline</u> sparingly.</p>
<p>Small <small>print</small> for side comments.</p>

Exposant & indice

<sub> crée du texte en indice (sous la ligne de base) pour les formules chimiques (H2O) et les variables mathématiques. <sup> crée du texte en exposant (au-dessus de la ligne de base) pour les exposants (x²), les nombres ordinaux (1er) et les notes de bas de page. Les deux sont des éléments en ligne qui ajustent la position verticale et la taille de police.

html
<p>H<sub>2</sub>O is water.</p>
<p>E = mc<sup>2</sup> is Einstein's equation.</p>
<p>1st<sup>st</sup> January 2024</p>
<p>CO<sub>2</sub> emissions are rising.</p>
<p>x<sup>2</sup> + y<sup>2</sup> = r<sup>2</sup></p>

Citations & références

<blockquote> est pour les citations de niveau bloc (indentées, multi-lignes). <q> est pour les citations courtes en ligne (ajoute automatiquement des guillemets). L'attribut cite fournit l'URL source. <cite> étiquette le titre d'une œuvre ou le nom de l'auteur. Ces éléments améliorent le balisage sémantique du contenu cité.

html
<blockquote cite="https://example.com/source">
  <p>The best way to predict the future is to invent it.</p>
  <footer>— <cite>Alan Kay</cite></footer>
</blockquote>

<p>As <q cite="https://example.com">someone once said</q>,
knowledge is power.</p>

Code & texte préformaté

<code> marque les extraits de code en ligne (police monospace). <pre> préserve les espaces et les sauts de ligne pour le texte préformaté. Combiner <pre><code> affiche des blocs de code avec indentation correcte. <kbd> représente l'entrée clavier. <samp> est pour la sortie de programme, et <var> pour les variables dans les expressions mathématiques.

html
<p>Use the <code>console.log()</code> function.</p>
<p>Press <kbd>Ctrl</kbd> + <kbd>C</kbd> to copy.</p>

<pre><code>function hello() {
  console.log("Hello, World!");
  return true;
}</code></pre>

Sauts de ligne & règles horizontales

<br> crée un saut de ligne dans le texte (utilisez avec parcimonie, préférez CSS). <hr> crée une règle horizontale représentant une rupture thématique entre les sections. <wbr> suggère une opportunité de saut de ligne pour les longs mots ou URLs, permettant au navigateur de casser aux points optimaux. Évitez d'utiliser <br> pour l'espacement — utilisez des marges CSS à la place.

html
<p>First line<br>Second line<br>Third line</p>

<p>Paragraph one.</p>
<hr>
<p>Paragraph two after a thematic break.</p>

<wbr><!-- word break opportunity for long URLs -->
https://example.com/<wbr>very<wbr>long<wbr>url
04

Images & multimédia

Images

Incluez toujours du texte alt pour l'accessibilité et le SEO — il décrit l'image pour les lecteurs d'écran et quand l'image ne se charge pas. loading='lazy' diffère le chargement des images hors écran, améliorant la vitesse de page. srcset et sizes permettent des images responsives — le navigateur sélectionne la meilleure image selon la résolution de l'appareil et le viewport. Spécifiez toujours width et height pour prévenir le décalage de mise en page.

html
<!-- Basic image -->
<img src="photo.jpg" alt="A sunset over mountains" width="800" height="600">

<!-- Image with lazy loading -->
<img src="hero.jpg" alt="Hero banner" loading="lazy" decoding="async">

<!-- Responsive image with srcset -->
<img
  src="medium.jpg"
  srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"
  sizes="(max-width: 600px) 480px, 800px"
  alt="Responsive photo"
>

Élément Picture

<picture> fournit la direction artistique et un repli de format. Les éléments <source> offrent des alternatives — le navigateur choisit le premier format supporté (WebP/AVIF sont plus petits). L'attribut media permet des images différentes pour différentes tailles d'écran. Le <img> final est le repli et doit toujours être présent. C'est supérieur à srcset pour servir des images entièrement différentes.

html
<picture>
  <source srcset="webp-image.webp" type="image/webp">
  <source srcset="avif-image.avif" type="image/avif">
  <source srcset="wide.jpg" media="(min-width: 800px)">
  <img src="fallback.jpg" alt="Art-directed image">
</picture>

Audio

<audio> intègre du contenu sonore. controls ajoute des contrôles lecture/pause/volume. De multiples éléments <source> fournissent des replis de format (MP3 est le plus largement supporté). autoplay est restreint par les navigateurs — l'autoplay muet est généralement autorisé. loop répète l'audio. Le texte à l'intérieur est affiché si l'audio n'est pas supporté. Fournissez toujours des contrôles pour l'expérience utilisateur.

html
<audio controls>
  <source src="song.mp3" type="audio/mpeg">
  <source src="song.ogg" type="audio/ogg">
  Your browser does not support the audio element.
</audio>

<!-- Autoplay (muted required in most browsers) -->
<audio autoplay muted loop>
  <source src="background.mp3" type="audio/mpeg">
</audio>

Vidéo

<video> intègre de la vidéo avec des contrôles pour lecture, pause, volume et plein écran. poster définit une miniature avant la lecture. De multiples sources fournissent un repli de format (MP4/H.264 est le plus compatible). <track> ajoute des sous-titres, légendes ou descriptions pour l'accessibilité. playsinline empêche le plein écran forcé sur iOS. Incluez toujours des contrôles sauf si autoplay muet.

html
<video controls width="640" height="360" poster="thumbnail.jpg">
  <source src="movie.mp4" type="video/mp4">
  <source src="movie.webm" type="video/webm">
  <track kind="subtitles" src="subs.vtt" srclang="en" label="English">
  Your browser does not support video.
</video>

<!-- Autoplay muted loop (common for backgrounds) -->
<video autoplay muted loop playsinline>
  <source src="bg.mp4" type="video/mp4">
</video>

Figure & Figcaption

<figure> regroupe le contenu autonome comme les images, diagrammes, listes de code ou citations avec leur légende. <figcaption> fournit une légende. Ce regroupement sémantique améliore l'accessibilité — les lecteurs d'écran annoncent la relation. Les figures peuvent être référencées depuis le texte (« voir Figure 1 ») et déplacées dans la mise en page sans perdre le contexte.

html
<figure>
  <img src="chart.png" alt="Quarterly sales chart showing 20% growth">
  <figcaption>Figure 1: Q4 2024 sales growth by region.</figcaption>
</figure>

<figure>
  <blockquote>
    <p>The best way to predict the future is to invent it.</p>
  </blockquote>
  <figcaption>— Alan Kay, 1971</figcaption>
</figure>

Intégrations Iframe

<iframe> intègre du contenu externe (vidéos, cartes, autres pages). Incluez toujours un attribut title pour l'accessibilité. loading='lazy' améliore la performance pour les iframes hors écran. L'attribut allow spécifie les politiques de fonctionnalités. L'attribut sandbox restreint les capacités de l'iframe pour la sécurité. Soyez prudent — les iframes peuvent impacter la performance et la sécurité.

html
<!-- Embed a YouTube video -->
<iframe
  src="https://www.youtube.com/embed/dQw4w9WgXcQ"
  width="560" height="315"
  title="YouTube video"
  frameborder="0"
  allow="accelerometer; autoplay; encrypted-media"
  allowfullscreen>
</iframe>

<!-- Embed a map -->
<iframe
  src="https://maps.google.com/maps?q=Paris&output=embed"
  title="Map of Paris" loading="lazy">
</iframe>
05

Listes

Listes non ordonnées

<ul> crée une liste non ordonnée (à puces). Chaque élément est enveloppé dans <li>. La propriété CSS list-style-type change le style de puce (disc, circle, square, none). Les listes non ordonnées sont pour les éléments où l'ordre n'a pas d'importance. Utilisez list-style: none et un style personnalisé pour les menus de navigation et listes de fonctionnalités.

html
<ul>
  <li>Apple</li>
  <li>Banana</li>
  <li>Cherry</li>
</ul>

<!-- Custom bullet style via CSS -->
<ul style="list-style-type: square;">
  <li>First item</li>
  <li>Second item</li>
</ul>

Listes ordonnées

<ol> crée une liste ordonnée (numérotée) pour les éléments séquentiels. L'attribut start définit le numéro de départ. reversed affiche les éléments en ordre descendant. L'attribut type change le style de numérotation (1, A, a, I, i). Utilisez <ol> pour les étapes, classements ou toute séquence où l'ordre compte.

html
<ol>
  <li>First step</li>
  <li>Second step</li>
  <li>Third step</li>
</ol>

<!-- Start from a specific number -->
<ol start="5">
  <li>Fifth item</li>
  <li>Sixth item</li>
</ol>

<!-- Reverse order -->
<ol reversed>
  <li>Countdown 3</li>
  <li>Countdown 2</li>
  <li>Countdown 1</li>
</ol>

Listes de descriptions

<dl> crée une liste de descriptions associant des termes (<dt>) à des descriptions (<dd>). C'est idéal pour les glossaires, pages FAQ et paires terme-définition. De multiples <dd> peuvent décrire un <dt>, et vice versa. Les listes de descriptions fournissent une signification sémantique que les tables de définition n'ont pas, améliorant l'accessibilité.

html
<dl>
  <dt>HTML</dt>
  <dd>HyperText Markup Language</dd>

  <dt>CSS</dt>
  <dd>Cascading Style Sheets</dd>

  <dt>JavaScript</dt>
  <dd>A programming language for the web</dd>
</dl>

Listes imbriquées

Les listes peuvent être imbriquées en plaçant un <ul> ou <ol> dans un <li>. Les navigateurs indentent automatiquement les listes imbriquées et peuvent changer les styles de puce. L'imbrication crée des structures hiérarchiques comme les tables des matières, arbres de fichiers ou menus multi-niveaux. Gardez l'imbrication raisonnable (2-3 niveaux) pour l'utilisabilité. Les listes profondément imbriquées deviennent difficiles à lire.

html
<ul>
  <li>Fruits
    <ul>
      <li>Apple</li>
      <li>Banana</li>
    </ul>
  </li>
  <li>Vegetables
    <ol>
      <li>Carrot</li>
      <li>Spinach</li>
    </ol>
  </li>
</ul>

Liste avec liens (navigation)

Les listes de liens dans <nav> créent des menus de navigation sémantiques. Les éléments <ul> imbriqués forment des sous-menus déroulants. Cette structure est accessible aux lecteurs d'écran et facilement stylée avec CSS. Utilisez les attributs aria (aria-expanded, aria-haspopup) pour les déroulants interactifs. La navigation basée sur des listes est le motif standard pour les menus accessibles.

html
<nav>
  <ul class="menu">
    <li><a href="/">Home</a></li>
    <li><a href="/products">Products</a>
      <ul class="submenu">
        <li><a href="/products/a">Product A</a></li>
        <li><a href="/products/b">Product B</a></li>
      </ul>
    </li>
    <li><a href="/contact">Contact</a></li>
  </ul>
</nav>
06

Tableaux

Tableau de base

<table> crée des données tabulaires. <thead> regroupe les lignes d'en-tête, <tbody> regroupe les lignes du corps, <tfoot> regroupe les lignes de pied. <tr> est une ligne de tableau, <th> est une cellule d'en-tête (gras, centré), <td> est une cellule de données. Utiliser thead/tbody/tfoot améliore l'accessibilité et permet un meilleur style. Les tableaux devraient être utilisés pour les données, pas la mise en page.

html
<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Age</th>
      <th>City</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Alice</td>
      <td>30</td>
      <td>New York</td>
    </tr>
    <tr>
      <td>Bob</td>
      <td>25</td>
      <td>London</td>
    </tr>
  </tbody>
</table>

Cellules fusionnées

colspan fait fusionner une cellule sur plusieurs colonnes (fusion horizontale). rowspan fait fusionner une cellule sur plusieurs lignes (fusion verticale). Ces attributs créent des mises en page de tableau complexes comme des en-têtes qui regroupent plusieurs colonnes. Soyez prudent avec la fusion — cela peut rendre les tableaux plus difficiles à parser pour les lecteurs d'écran. Testez toujours l'accessibilité.

html
<table border="1">
  <tr>
    <th colspan="2">Name</th>
    <th rowspan="2">Age</th>
  </tr>
  <tr>
    <th>First</th>
    <th>Last</th>
  </tr>
  <tr>
    <td>Alice</td>
    <td>Smith</td>
    <td>30</td>
  </tr>
</table>

Légende & portée du tableau

<caption> fournit un titre pour le tableau, améliorant l'accessibilité. L'attribut scope sur <th> indique aux lecteurs d'écran si un en-tête s'applique à une colonne (scope='col') ou une ligne (scope='row'). C'est essentiel pour les tableaux complexes. Pour les tableaux encore plus complexes, utilisez les attributs id et headers pour associer explicitement les cellules à leurs en-têtes.

html
<table>
  <caption>Employee Salary Report 2024</caption>
  <thead>
    <tr>
      <th scope="col">Name</th>
      <th scope="col">Department</th>
      <th scope="col">Salary</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Alice</th>
      <td>Engineering</td>
      <td>$95,000</td>
    </tr>
  </tbody>
</table>

Groupes de colonnes

<colgroup> regroupe les colonnes pour le style. Les éléments <col> à l'intérieur appliquent des styles (surtout la largeur) à des colonnes spécifiques. C'est plus efficace que de définir la largeur sur chaque cellule. Les groupes de colonnes supportent aussi l'attribut span pour styler plusieurs colonnes à la fois. Utilisez-le pour des largeurs de colonnes cohérentes à travers toutes les lignes.

html
<table>
  <colgroup>
    <col style="width: 30%;">
    <col style="width: 50%;">
    <col style="width: 20%;">
  </colgroup>
  <tr>
    <th>Product</th>
    <th>Description</th>
    <th>Price</th>
  </tr>
  <tr>
    <td>Laptop</td>
    <td>15-inch laptop</td>
    <td>$999</td>
  </tr>
</table>

Style des tableaux

border-collapse: collapse fusionne les bordures adjacentes en une. Utilisez :nth-child(even) pour des lignes zébrées (améliore la lisibilité). :hover surligne les lignes au survol. Le style th différencie les en-têtes. Gardez le style de tableau propre et lisible — évitez les bordures excessives. Les tableaux responsives peuvent nécessiter overflow-x: auto sur un wrapper pour les petits écrans.

html
<style>
  table { border-collapse: collapse; width: 100%; }
  th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
  th { background-color: #f4f4f4; }
  tr:nth-child(even) { background-color: #f9f9f9; }
  tr:hover { background-color: #e0e0e0; }
</style>
<table>
  <tr><th>Name</th><th>Score</th></tr>
  <tr><td>Alice</td><td>95</td></tr>
  <tr><td>Bob</td><td>87</td></tr>
</table>
07

Formulaires & entrée

Structure de formulaire

<form> enveloppe les contrôles d'entrée. action spécifie l'URL de soumission, method est GET (visible dans l'URL) ou POST (caché). enctype='multipart/form-data' est requis pour les téléversements de fichiers. <fieldset> regroupe les champs liés, <legend> fournit une légende. Associez toujours <label> aux entrées avec correspondance for/id pour l'accessibilité.

html
<form action="/submit" method="POST" enctype="multipart/form-data">
  <fieldset>
    <legend>Personal Information</legend>

    <label for="name">Name:</label>
    <input type="text" id="name" name="name" required>

    <label for="email">Email:</label>
    <input type="email" id="email" name="email" required>
  </fieldset>

  <button type="submit">Submit</button>
</form>

Types d'entrée

HTML5 a introduit de nombreux types d'entrée avec validation intégrée et claviers adaptés au mobile. type='email' valide le format email. type='number' fournit des spinners. type='date' et 'time' affichent des sélecteurs natifs. type='color' ouvre un sélecteur de couleur. type='range' crée un slider. type='file' avec accept restreint les types de fichiers. type='hidden' stocke des données non montrées aux utilisateurs.

html
<input type="text" name="username" placeholder="Username">
<input type="email" name="email" required>
<input type="password" name="pwd" minlength="8">
<input type="number" name="age" min="0" max="120" step="1">
<input type="date" name="birthday">
<input type="time" name="appointment">
<input type="color" name="favcolor" value="#ff0000">
<input type="range" name="volume" min="0" max="100">
<input type="file" name="upload" accept="image/*">
<input type="hidden" name="token" value="abc123">

Select & Textarea

<select> crée une liste déroulante. <optgroup> regroupe les options liées avec un label. <option> définit les choix ; l'attribut selected pré-sélectionne un. <textarea> est pour l'entrée de texte multi-lignes. rows et cols définissent la taille visible. maxlength limite le nombre de caractères. placeholder fournit un indice. Les deux supportent les attributs required et disabled.

html
<label for="country">Country:</label>
<select id="country" name="country">
  <optgroup label="North America">
    <option value="us">United States</option>
    <option value="ca">Canada</option>
  </optgroup>
  <optgroup label="Europe">
    <option value="uk">United Kingdom</option>
    <option value="fr">France</option>
  </optgroup>
</select>

<label for="bio">Bio:</label>
<textarea id="bio" name="bio" rows="4" cols="40"
  maxlength="500" placeholder="Tell us about yourself"></textarea>

Cases à cocher & boutons radio

Les cases à cocher permettent des sélections multiples ; les boutons radio n'en permettent qu'une (quand ils partagent le même nom). L'attribut checked pré-sélectionne une option. Enveloppez toujours les entrées dans <label> pour du texte cliquable. Utilisez <fieldset> et <legend> pour regrouper les choix liés pour l'accessibilité. La valeur est envoyée au serveur seulement si sélectionnée.

html
<fieldset>
  <legend>Select your interests:</legend>
  <label><input type="checkbox" name="interest" value="tech" checked> Tech</label>
  <label><input type="checkbox" name="interest" value="music"> Music</label>
  <label><input type="checkbox" name="interest" value="sports"> Sports</label>
</fieldset>

<fieldset>
  <legend>Choose a plan:</legend>
  <label><input type="radio" name="plan" value="free" checked> Free</label>
  <label><input type="radio" name="plan" value="pro"> Pro</label>
  <label><input type="radio" name="plan" value="enterprise"> Enterprise</label>
</fieldset>

Validation de formulaire

HTML5 fournit une validation côté client intégrée. required empêche la soumission si vide. minlength/maxlength contraignent la longueur du texte. pattern utilise les regex pour une validation personnalisée (l'attribut title guide les utilisateurs). type='email' et type='url' valident le format. min/max fonctionnent avec les nombres et dates. Ajoutez novalidate au formulaire pour désactiver la validation.

html
<form>
  <input type="text" name="username" required
         minlength="3" maxlength="20"
         pattern="[A-Za-z0-9_]+"
         title="3-20 alphanumeric characters">

  <input type="email" name="email" required>

  <input type="url" name="website"
         placeholder="https://example.com">

  <input type="number" name="age" min="18" max="99">

  <button type="submit">Submit</button>
</form>

Boutons & Datalist

type='submit' soumet le formulaire, type='reset' efface tous les champs, type='button' est un bouton personnalisé. <datalist> fournit des suggestions d'autocomplétion pour les éléments <input> — liez-les avec list/id. Contrairement à <select>, les utilisateurs peuvent entrer des valeurs personnalisées. Cela combine la flexibilité de l'entrée texte avec la commodité des suggestions.

html
<!-- Button types -->
<button type="submit">Submit Form</button>
<button type="reset">Reset</button>
<button type="button" onclick="alert('Hi')">Click Me</button>

<!-- Datalist for autocomplete suggestions -->
<label for="browser">Choose a browser:</label>
<input list="browsers" name="browser" id="browser">
<datalist id="browsers">
  <option value="Chrome">
  <option value="Firefox">
  <option value="Safari">
  <option value="Edge">
</datalist>
08

HTML sémantique

Header & Navigation

<header> représente le contenu introductif — typiquement un logo, un titre et une navigation. Il peut apparaître en haut d'une page ou dans un <article> ou <section>. <nav> identifie les liens de navigation, aidant les lecteurs d'écran à sauter à la navigation. Une page peut avoir de multiples headers (par exemple, un par section). Header n'est pas la même chose que head — c'est du contenu visible.

html
<header>
  <h1>My Website</h1>
  <nav>
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/blog">Blog</a></li>
      <li><a href="/contact">Contact</a></li>
    </ul>
  </nav>
</header>

Main & Article

<main> enveloppe le contenu dominant de la page (un seul par page). <article> représente le contenu autonome qui pourrait être distribué indépendamment (article de blog, article de news, post de forum). <time> avec datetime fournit des dates lisibles par machine pour le SEO. <section> regroupe le contenu thématiquement lié avec un titre. Ces balises améliorent le plan du document et l'accessibilité.

html
<main>
  <article>
    <h1>Blog Post Title</h1>
    <p>Published on <time datetime="2024-01-15">January 15, 2024</time></p>
    <p>The main content of the article...</p>
    <section>
      <h2>Subsection</h2>
      <p>More content...</p>
    </section>
  </article>
</main>

Section & Aside

<section> regroupe le contenu lié avec un titre — utilisez-le quand le contenu a un titre naturel. <aside> représente le contenu tangentiellement lié au contenu principal (barres latérales, citations tirées, pubs, liens connexes). Les deux améliorent la structure du document. Les sections peuvent être imbriquées. Les asides sont typiquement stylés comme barres latérales mais sont sémantiques, pas de présentation.

html
<section>
  <h2>Services</h2>
  <p>We offer the following services:</p>
  <article>
    <h3>Web Design</h3>
    <p>Custom website design...</p>
  </article>
</section>

<aside>
  <h3>Related Articles</h3>
  <ul>
    <li><a href="/post1">Related Post 1</a></li>
    <li><a href="/post2">Related Post 2</a></li>
  </ul>
</aside>

Footer

<footer> contient le contenu de pied pour une page ou section — copyright, liens vers documents connexes, infos de contact, plan du site. Une page peut avoir de multiples footers (par exemple, un par section d'article). Les footers ne sont pas requis d'être visuellement en bas, mais représentent sémantiquement le contenu de conclusion. Utilisez &copy; pour le symbole copyright.

html
<footer>
  <div>
    <h3>About Us</h3>
    <p>Company information...</p>
  </div>
  <nav>
    <a href="/privacy">Privacy Policy</a>
    <a href="/terms">Terms of Service</a>
    <a href="/sitemap">Sitemap</a>
  </nav>
  <p>&copy; 2024 My Company. All rights reserved.</p>
</footer>

Details & Summary

<details> crée un widget de divulgation interactif — le contenu est caché jusqu'à ce que l'utilisateur clique sur <summary>. L'attribut open l'affiche déplié par défaut. C'est du HTML natif, pas besoin de JavaScript. Génial pour les FAQ, sections repliables et divulgation progressive. Les details imbriqués créent des accordéons multi-niveaux. Stylisez avec le sélecteur d'attribut [open].

html
<details>
  <summary>Click to expand FAQ</summary>
  <p>This content is hidden by default and shown when the summary is clicked.</p>
</details>

<!-- Open by default -->
<details open>
  <summary>What is HTML?</summary>
  <p>HTML (HyperText Markup Language) is the standard language for creating web pages.</p>
</details>

<!-- Nested details -->
<details>
  <summary>Advanced Topics</summary>
  <details>
    <summary>Sub-topic</summary>
    <p>Nested content...</p>
  </details>
</details>
09

Balises méta & SEO

Charset & Viewport

charset='UTF-8' déclare l'encodage de caractères — essentiel pour afficher tous les caractères correctement. La balise méta viewport est critique pour le design responsive : width=device-width correspond à la largeur de l'appareil, initial-scale=1.0 définit le niveau de zoom. Sans elle, les navigateurs mobiles rendent des pages à largeur desktop. Ces deux balises méta devraient être dans chaque document HTML.

html
<head>
  <!-- Character encoding -->
  <meta charset="UTF-8">

  <!-- Responsive viewport -->
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0">

  <!-- Internet Explorer compatibility -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>

Description & Keywords

La balise méta description est la plus importante pour le SEO — les moteurs de recherche l'affichent sous votre titre dans les résultats (gardez-la sous 160 caractères). keywords est largement ignoré par les moteurs modernes. robots contrôle l'indexation : index/noindex, follow/nofollow. author crédite le créateur du contenu. Écrivez des descriptions convaincantes pour améliorer les taux de clic.

html
<meta name="description"
      content="Free HTML tutorials for beginners. Learn HTML tags, attributes, and semantic markup with examples.">

<meta name="keywords"
      content="HTML, tutorial, web development, markup">

<meta name="author" content="John Doe">
<meta name="robots" content="index, follow">

Open Graph (Facebook)

Les balises méta Open Graph (og:) contrôlent comment votre page apparaît quand partagée sur Facebook, LinkedIn et autres plateformes. og:title, og:description, og:image et og:url sont les plus importantes. og:type peut être article, website, product, etc. L'image devrait faire au moins 1200x630 pixels. Testez avec le Sharing Debugger de Facebook avant de déployer.

html
<meta property="og:title" content="My Amazing Article">
<meta property="og:description" content="A brief description of the article.">
<meta property="og:image" content="https://example.com/image.jpg">
<meta property="og:url" content="https://example.com/article">
<meta property="og:type" content="article">
<meta property="og:site_name" content="My Website">
<meta property="og:locale" content="en_US">

Twitter Cards

Les balises méta Twitter Card contrôlent comment les liens apparaissent sur Twitter/X. twitter:card peut être summary, summary_large_image ou player. La carte grande image est la plus engageante. twitter:site et twitter:creator lient aux comptes Twitter. Si les balises Open Graph sont présentes, Twitter y revient, mais les balises Twitter explicites donnent plus de contrôle. Testez avec Twitter Card Validator.

html
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="My Amazing Article">
<meta name="twitter:description" content="A brief description.">
<meta name="twitter:image" content="https://example.com/image.jpg">
<meta name="twitter:site" content="@mywebsite">
<meta name="twitter:creator" content="@author">

Canonical & données structurées

La balise de lien canonical indique aux moteurs de recherche l'URL préférée pour une page, prévenant les pénalités de contenu dupliqué. Les données structurées JSON-LD aident les moteurs à comprendre votre contenu et activent les extraits enrichis (étoiles de notation, fils d'Ariane, accordéons FAQ dans les résultats de recherche). Utilisez les types schema.org comme Article, Product, Event ou FAQPage. Validez avec le Rich Results Test de Google.

html
<!-- Canonical URL (prevents duplicate content issues) -->
<link rel="canonical" href="https://example.com/article">

<!-- Structured data (JSON-LD) -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "My Article Title",
  "author": "John Doe",
  "datePublished": "2024-01-15",
  "image": "https://example.com/image.jpg"
}
</script>
10

SVG & Canvas

Bases de SVG

SVG (Scalable Vector Graphics) crée des graphiques indépendants de la résolution qui scalent sans perte de qualité. Le SVG en ligne peut être stylé avec CSS et manipulé avec JavaScript. Formes courantes : <circle>, <rect>, <line>, <ellipse>, <polygon>, <path>. SVG est idéal pour les icônes, logos et diagrammes. Contrairement aux images raster, les SVG sont nets à n'importe quelle taille.

html
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="100" cy="100" r="50" fill="blue" stroke="black" stroke-width="2"/>
  <text x="100" y="105" text-anchor="middle" fill="white">Circle</text>
</svg>

<!-- Inline SVG (can be styled with CSS) -->
<svg width="100" height="100">
  <rect x="10" y="10" width="80" height="80" fill="red" rx="10"/>
</svg>

Formes SVG

Les formes SVG utilisent des attributs basés sur des coordonnées. <rect> a besoin de x, y, width, height ; rx/ry créent des coins arrondis. <circle> a besoin de cx, cy (centre) et r (rayon). <ellipse> utilise rx et ry pour différents rayons x/y. <line> connecte x1,y1 à x2,y2. <polygon> prend une liste de points. fill définit la couleur intérieure, stroke définit le contour.

html
<svg width="300" height="200">
  <!-- Rectangle -->
  <rect x="10" y="10" width="80" height="50" fill="orange" rx="10" ry="10"/>

  <!-- Circle -->
  <circle cx="200" cy="50" r="40" fill="green"/>

  <!-- Ellipse -->
  <ellipse cx="100" cy="150" rx="60" ry="30" fill="purple"/>

  <!-- Line -->
  <line x1="10" y1="180" x2="290" y2="180" stroke="black" stroke-width="2"/>

  <!-- Polygon -->
  <polygon points="250,10 290,80 210,80" fill="pink"/>
</svg>

Chemins SVG

<path> est l'élément SVG le plus puissant, utilisant un attribut d avec des commandes : M (moveto), L (lineto), H/V (ligne horizontale/verticale), C (Bezier cubique), Q (Bezier quadratique), A (arc), Z (fermer le chemin). Majuscule = coordonnées absolues, minuscule = relatives. viewBox définit le système de coordonnées. Les icônes SVG utilisent des chemins pour des icônes scalables et stylables.

html
<svg width="200" height="200">
  <!-- M=move, L=line, C=curve, Z=close -->
  <path d="M 10 10 L 100 10 L 100 100 Z" fill="none" stroke="black"/>

  <!-- Bezier curve -->
  <path d="M 10 100 C 50 10, 150 10, 190 100" fill="none" stroke="red"/>

  <!-- Arc -->
  <path d="M 10 100 A 90 90 0 0 1 190 100" fill="none" stroke="blue"/>
</svg>

<!-- SVG icon example -->
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
  <path d="M12 2L2 7v10l10 5 10-5V7z"/>
</svg>

Bases de Canvas

<canvas> est une surface de dessin bitmap manipulée via JavaScript. Obtenez le contexte 2D avec getContext('2d'). Contrairement au SVG, canvas est basé sur les pixels (non scalable) et ne fait pas partie du DOM. Canvas est meilleur pour les animations complexes, les jeux et le traitement d'image. SVG est meilleur pour les graphiques statiques, icônes et graphiques interactifs. Choisissez selon vos besoins.

html
<canvas id="myCanvas" width="300" height="200"></canvas>

<script>
  const canvas = document.getElementById('myCanvas');
  const ctx = canvas.getContext('2d');

  // Draw a rectangle
  ctx.fillStyle = 'blue';
  ctx.fillRect(10, 10, 100, 80);

  // Draw a circle
  ctx.beginPath();
  ctx.arc(200, 50, 30, 0, Math.PI * 2);
  ctx.fillStyle = 'red';
  ctx.fill();

  // Draw text
  ctx.font = '20px Arial';
  ctx.fillText('Hello Canvas', 50, 150);
</script>

Icônes SVG en ligne

SVG <symbol> définit des icônes réutilisables qui sont référencées avec <use href='#id'>. C'est la technique de sprite SVG — définissez les icônes une fois, utilisez-les partout. Le symbol est caché (display:none) et instancié via <use>. Les icônes héritent de la couleur du 'color' CSS via fill='currentColor'. Cette approche est efficace (une définition, multiples usages) et entièrement stylable.

html
<!-- Reusable SVG symbol -->
<svg style="display:none">
  <symbol id="icon-home" viewBox="0 0 24 24">
    <path d="M12 2L2 12h3v8h6v-6h2v6h6v-8h3z"/>
  </symbol>
</svg>

<!-- Use the icon -->
<svg width="24" height="24" fill="currentColor">
  <use href="#icon-home"/>
</svg>

<!-- Styled icon -->
<svg width="32" height="32" class="icon" style="color: blue;">
  <use href="#icon-home"/>
</svg>
11

Accessibilité (ARIA)

Rôles ARIA

Les rôles ARIA définissent ce qu'un élément fait pour les lecteurs d'écran. Les rôles de repère (banner, navigation, main, complementary, contentinfo) permettent aux utilisateurs de lecteur d'écran de sauter entre les régions de la page. Les éléments sémantiques HTML5 (<header>, <nav>, <main>) ont des rôles ARIA implicites, donc ajouter des attributs role est souvent redondant — mais utile pour les anciens navigateurs. Préférez toujours le HTML sémantique à ARIA quand possible.

html
<!-- Landmark roles for page structure -->
<header role="banner">Site Header</header>
<nav role="navigation">Main Menu</nav>
<main role="main">Primary Content</main>
<aside role="complementary">Sidebar</aside>
<footer role="contentinfo">Footer</footer>
<form role="search">Search Form</form>

<!-- Document structure roles -->
<article role="article">Blog Post</article>
<section role="region" aria-label="Comments">Comments</section>

aria-label & aria-labelledby

aria-label définit un nom accessible quand aucun label visible n'existe (par exemple, boutons à icône seule). aria-labelledby référence l'ID d'élément(s) de texte visible(s) qui étiquettent le contrôle — utile quand un label visible est déjà à l'écran. Quand de multiples IDs sont listés, leur texte est concaténé dans l'ordre. Préférez aria-labelledby quand du texte visible existe, car il garde les labels synchronisés.

html
<!-- aria-label provides accessible name directly -->
<button aria-label="Close menu" onclick="closeMenu()">✕</button>
<input type="search" aria-label="Search products" />

<!-- aria-labelledby references visible text -->
<div id="billing-label">Billing Address</div>
<input type="text" aria-labelledby="billing-label" />

<!-- Multiple labels combined -->
<span id="city">City</span>
<span id="required">required</span>
<input aria-labelledby="city required" />

aria-describedby & infobulles

aria-describedby lie un élément à du texte descriptif supplémentaire via l'ID d'élément. Les lecteurs d'écran annoncent cette description après le label. C'est idéal pour le texte d'aide, les indices et les messages d'erreur. Utilisez role='alert' sur les messages d'erreur pour qu'ils soient annoncés immédiatement à leur apparition. Définissez aria-invalid='true' sur les champs avec erreurs pour que les lecteurs d'écran indiquent l'état invalide.

html
<label for="password">Password</label>
<input type="password" id="password"
       aria-describedby="pwd-help pwd-rules" />
<p id="pwd-help">Must be at least 8 characters</p>
<p id="pwd-rules">Include uppercase, number, and symbol</p>

<!-- Error messaging -->
<input type="email" id="email" aria-describedby="email-error" aria-invalid="true" />
<p id="email-error" role="alert">Please enter a valid email address</p>

Régions live (aria-live)

Les régions live annoncent les changements de contenu dynamiques aux utilisateurs de lecteur d'écran. aria-live='polite' attend une pause avant d'annoncer (bon pour les mises à jour de statut). aria-live='assertive' interrompt immédiatement (pour les erreurs critiques). aria-atomic='true' lit tout le contenu de la région au lieu de juste la portion modifiée. aria-relevant spécifie quels types de changements (ajouts, suppressions, texte) déclenchent les annonces. Essentiel pour les SPA, apps de chat et contenu auto-mis-à-jour.

html
<!-- Polite: announces when user is idle -->
<div aria-live="polite" id="status">Saving...</div>

<!-- Assertive: announces immediately, interrupts -->
<div aria-live="assertive" role="alert" id="errors">
  Connection lost!
</div>

<!-- aria-atomic reads entire region, not just changes -->
<div aria-live="polite" aria-atomic="true" id="cart">
  3 items in cart
</div>

<!-- aria-relevant controls what changes are announced -->
<div aria-live="polite" aria-relevant="additions text">
  Chat messages appear here
</div>

Gestion du focus & tabindex

tabindex contrôle le comportement du focus clavier. tabindex='0' rend les éléments non interactifs (divs, spans) focalisables dans l'ordre DOM naturel — utilisez pour les widgets personnalisés. tabindex='-1' rend les éléments focalisables seulement par programme via JS .focus() — utile pour les modales et cibles de saut. N'utilisez jamais de valeurs tabindex positives car elles surchargent l'ordre de tab naturel et créent de la confusion. Fournissez toujours des liens de saut comme premier élément focalisable sur une page.

html
<!-- tabindex="0": element is focusable in natural order -->
<div tabindex="0" role="button" onkeypress="handleKey()">
  Custom clickable div
</div>

<!-- tabindex="-1": focusable only via JS, removed from tab order -->
<div tabindex="-1" id="modal">Modal content</div>
<script>
  document.getElementById('modal').focus();
</script>

<!-- tabindex="1+": DO NOT USE — breaks natural tab order -->
<!-- Avoid: <div tabindex="2"> -->

<!-- Skip link for keyboard users -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<main id="main-content">...</main>

Contenu caché & lecteur d'écran uniquement

aria-hidden='true' supprime les éléments de l'arbre d'accessibilité tout en les gardant visibles — utilisez pour les icônes décoratives, le texte redondant ou le contenu hors écran. Le motif .sr-only cache le texte visuellement mais le garde lisible par les lecteurs d'écran — essentiel pour les boutons à icône seule. N'utilisez jamais aria-hidden sur des éléments focalisables, car cela crée une déconnexion entre la navigation clavier et lecteur d'écran. La technique clip est la méthode visuellement cachée la plus robuste.

html
<!-- aria-hidden: visible but hidden from screen readers -->
<div aria-hidden="true">
  <i class="icon-decoration"></i> Decorative only
</div>

<!-- visually hidden but available to screen readers -->
<style>
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap; border: 0;
}
</style>
<button>
  <span class="sr-only">Delete item</span>
  <i class="icon-trash" aria-hidden="true"></i>
</button>
12

APIs HTML5 (Géolocalisation, Stockage, Glisser-Déposer)

API Geolocation

L'API Geolocation vous permet de demander la position physique de l'utilisateur. Les navigateurs demandent toujours l'autorisation — l'utilisateur doit accorder explicitement l'accès. getCurrentPosition prend des callbacks de succès et d'erreur plus un objet options (enableHighAccuracy, timeout, maximumAge). Pour le suivi continu, utilisez watchPosition() qui renvoie un ID que vous pouvez passer à clearWatch(). Gérez toujours les erreurs gracieusement (permission refusée, position indisponible, timeout). La géolocalisation nécessite HTTPS dans les navigateurs modernes.

html
<!-- Request user location -->
<button onclick="getLocation()">Get My Location</button>
<p id="demo"></p>

<script>
function getLocation() {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(
      (pos) => {
        document.getElementById("demo").innerHTML =
          "Lat: " + pos.coords.latitude +
          "<br>Lon: " + pos.coords.longitude;
      },
      (err) => {
        alert("Error: " + err.message);
      },
      { enableHighAccuracy: true, timeout: 5000 }
    );
  } else {
    alert("Geolocation not supported.");
  }
}
</script>

Web Storage (localStorage & sessionStorage)

Web Storage fournit un stockage clé-valeur sur le client. localStorage persiste indéfiniment ; sessionStorage est effacé quand l'onglet se ferme. Les deux stockent seulement des chaînes — utilisez JSON.stringify/parse pour les objets. La limite de stockage est ~5-10MB par origine. Contrairement aux cookies, les données de stockage ne sont pas envoyées avec chaque requête HTTP. Soyez conscient : le stockage est synchrone et bloque le thread principal, et est accessible par n'importe quel script sur la même origine (non adapté aux données sensibles).

html
<!-- localStorage: persists until cleared -->
<script>
// Store data
localStorage.setItem("username", "alice");
localStorage.setItem("prefs", JSON.stringify({theme: "dark", lang: "en"}));

// Retrieve data
const user = localStorage.getItem("username");
const prefs = JSON.parse(localStorage.getItem("prefs") || "{}");

// Remove single item
localStorage.removeItem("username");

// Clear all items
localStorage.clear();

// sessionStorage: cleared when tab closes
sessionStorage.setItem("tempToken", "abc123");
</script>

API Drag and Drop

L'API HTML5 Drag and Drop permet des interactions de glisser natives. Définissez draggable='true' sur l'élément source. ondragstart se déclenche quand le glisser commence — utilisez dataTransfer.setData() pour stocker les données glissées. ondragover sur la cible de dépôt DOIT appeler preventDefault() pour permettre le dépôt. ondrop gère le dépôt réel — récupérez les données avec dataTransfer.getData(). Vous pouvez glisser des fichiers de l'OS vers le navigateur en utilisant event.dataTransfer.files. Pour les apps complexes, envisagez des bibliothèques comme SortableJS pour un meilleur support inter-navigateurs.

html
<div id="drag1" draggable="true" ondragstart="drag(event)">
  Drag me!
</div>
<div id="dropzone" ondrop="drop(event)" ondragover="allowDrop(event)">
  Drop here
</div>

<script>
function allowDrop(ev) {
  ev.preventDefault(); // necessary to allow dropping
}

function drag(ev) {
  ev.dataTransfer.setData("text", ev.target.id);
}

function drop(ev) {
  ev.preventDefault();
  const data = ev.dataTransfer.getData("text");
  ev.target.appendChild(document.getElementById(data));
}
</script>

API Page Visibility

L'API Page Visibility vous indique si la page est visible par l'utilisateur (pas minimisée, pas dans un onglet en arrière-plan). Utilisez-la pour mettre en pause les animations coûteuses, la lecture vidéo ou le polling quand l'utilisateur ne regarde pas — économisant batterie et CPU. document.hidden est un booléen ; document.visibilityState renvoie 'visible', 'hidden' ou 'prerender'. L'événement visibilitychange se déclenche sur les transitions. C'est plus fiable que blur/focus pour détecter la visibilité réelle.

html
<script>
document.addEventListener("visibilitychange", () => {
  if (document.hidden) {
    console.log("Tab is hidden — pause video/animation");
    video.pause();
  } else {
    console.log("Tab is visible — resume");
    video.play();
  }
});

// Check current state
if (document.visibilityState === "visible") {
  console.log("Page is visible");
}
</script>

API Fullscreen

L'API Fullscreen vous permet d'afficher n'importe quel élément en mode plein écran. requestFullscreen() doit être déclenché par un geste utilisateur (clic/touche). Différents navigateurs peuvent nécessiter des préfixes vendeur (webkit, moz, ms). L'événement fullscreenchange se déclenche à l'entrée ou sortie du plein écran. document.fullscreenElement référence l'élément plein écran courant (null si pas en plein écran). Utilisez la pseudo-classe CSS :fullscreen pour styler les éléments plein écran différemment.

html
<button onclick="openFullscreen()">Fullscreen</button>
<button onclick="closeFullscreen()">Exit</button>
<div id="container">Content to fullscreen</div>

<script>
function openFullscreen() {
  const elem = document.getElementById("container");
  if (elem.requestFullscreen) {
    elem.requestFullscreen();
  } else if (elem.webkitRequestFullscreen) {
    elem.webkitRequestFullscreen();
  }
}

function closeFullscreen() {
  if (document.exitFullscreen) {
    document.exitFullscreen();
  }
}

document.addEventListener("fullscreenchange", () => {
  console.log("Fullscreen:", !!document.fullscreenElement);
});
</script>
13

Web Components

Custom Elements

Les Custom Elements vous permettent de créer des balises HTML réutilisables avec un comportement encapsulé. La classe étend HTMLElement (ou des sous-classes de HTMLElement). connectedCallback se déclenche quand l'élément est ajouté au DOM — utilisez-le pour le rendu. attributeChangedCallback réagit aux changements d'attribut, mais seulement pour les attributs listés dans observedAttributes. Les noms doivent contenir un trait d'union (par exemple, 'my-greeting') pour éviter les conflits avec le HTML natif. customElements.define() enregistre l'élément. Évitez d'utiliser Shadow DOM sauf si vous avez besoin d'encapsulation de style.

html
<my-greeting name="World"></my-greeting>

<script>
class MyGreeting extends HTMLElement {
  constructor() {
    super();
    this.name = this.getAttribute("name") || "Guest";
  }
  connectedCallback() {
    this.innerHTML = `<h2>Hello, ${this.name}!</h2>`;
  }
  // Observe attribute changes
  static get observedAttributes() {
    return ["name"];
  }
  attributeChangedCallback(name, oldVal, newVal) {
    if (name === "name") {
      this.name = newVal;
      this.connectedCallback();
    }
  }
}
customElements.define("my-greeting", MyGreeting);
</script>

Shadow DOM

Shadow DOM fournit l'encapsulation de style et de DOM — les styles à l'intérieur de l'arbre shadow ne fuient pas, et les styles de page ne fuient pas à l'intérieur. attachShadow({mode:'open'}) crée une racine shadow accessible via element.shadowRoot. mode:'closed' refuse l'accès externe (rarement utilisé). Les éléments <slot> sont des placeholders où les enfants du light DOM sont projetés. Les slots nommés (<slot name='title'>) correspondent aux enfants avec des attributs slot correspondants. ::slotted() style le contenu projeté. Shadow DOM est clé pour construire des composants autonomes et réutilisables.

html
<my-card>
  <span slot="title">Card Title</span>
  <p slot="body">Card content here.</p>
</my-card>

<script>
class MyCard extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: "open" });
    shadow.innerHTML = `
      <style>
        .card { border: 1px solid #ccc; padding: 16px; border-radius: 8px; }
        ::slotted([slot="title"]) { font-size: 1.5em; font-weight: bold; }
      </style>
      <div class="card">
        <slot name="title"></slot>
        <slot name="body"></slot>
      </div>
    `;
  }
}
customElements.define("my-card", MyCard);
</script>

Templates HTML

L'élément <template> contient du HTML qui n'est pas rendu au chargement de la page — son contenu est inerte (les scripts ne s'exécutent pas, les images ne se chargent pas, les styles ne s'appliquent pas). Accédez au contenu via .content (un DocumentFragment) et clonez-le avec cloneNode(true) pour l'instancier. Les templates sont idéaux pour les structures répétitives générées par JavaScript. Contrairement à innerHTML, les templates sont parsés une fois et peuvent être clonés répétitivement sans re-parsing. Combinés aux Custom Elements et Shadow DOM, ils forment le standard Web Components.

html
<template id="row-template">
  <tr>
    <td class="name"></td>
    <td class="email"></td>
  </tr>
</template>

<script>
function addRow(name, email) {
  const template = document.getElementById("row-template");
  const clone = template.content.cloneNode(true);
  clone.querySelector(".name").textContent = name;
  clone.querySelector(".email").textContent = email;
  document.querySelector("tbody").appendChild(clone);
}

addRow("Alice", "[email protected]");
addRow("Bob", "[email protected]");
</script>

Callbacks de lifecycle

Les Custom Elements ont quatre callbacks de lifecycle. constructor() s'exécute quand l'élément est créé (évitez le travail lourd ici). connectedCallback() se déclenche à l'ajout au DOM — idéal pour le setup et le rendu. disconnectedCallback() se déclenche à la suppression — utilisez pour le nettoyage (écouteurs d'événements, minuteurs). adoptedCallback() se déclenche au déplacement vers un nouveau document via adoptNode() (rare). attributeChangedCallback() se déclenche seulement pour les attributs observés. L'ordre de mise à niveau est toujours : constructor → connectedCallback. Les changements d'attribut peuvent se déclencher avant connectedCallback.

html
<script>
class LifecycleDemo extends HTMLElement {
  constructor() {
    super();
    console.log("1. constructor: element created");
  }
  connectedCallback() {
    console.log("2. connected: added to DOM");
  }
  disconnectedCallback() {
    console.log("3. disconnected: removed from DOM");
  }
  adoptedCallback() {
    console.log("4. adopted: moved to new document");
  }
  attributeChangedCallback(attr, oldVal, newVal) {
    console.log(`5. attribute '${attr}' changed: ${oldVal} -> ${newVal}`);
  }
  static get observedAttributes() {
    return ["data-status"];
  }
}
customElements.define("lifecycle-demo", LifecycleDemo);
</script>

Éléments intégrés personnalisés

Les éléments intégrés personnalisés étendent les éléments HTML natifs (comme button, input, div) pour hériter de leur comportement intégré. Utilisez l'attribut 'is' au lieu d'un nom de balise personnalisé. Le troisième argument de customElements.define() spécifie quel élément natif est étendu. C'est utile quand vous voulez améliorer des éléments existants (par exemple, ajouter de la validation à <input>) plutôt que d'en créer de entièrement nouveaux. Note : Safari ne supporte pas les éléments intégrés personnalisés — envisagez les custom elements autonomes pour la compatibilité inter-navigateurs.

html
<!-- Extend a native button -->
<button is="my-button">Click me</button>

<script>
class MyButton extends HTMLButtonElement {
  constructor() {
    super();
    this.addEventListener("click", () => {
      this.textContent = "Clicked!";
      this.style.background = "lightgreen";
    });
  }
  connectedCallback() {
    this.style.fontWeight = "bold";
  }
}
customElements.define("my-button", MyButton,
  { extends: "button" });
</script>
14

Éléments média (Audio & Vidéo)

Élément Video

L'élément <video> intègre de la vidéo sans plugins. L'attribut controls affiche les contrôles intégrés lecture/pause/volume. poster spécifie une image de prévisualisation avant la lecture. De multiples balises <source> fournissent des replis de format — le navigateur utilise le premier qu'il supporte (MP4/H.264 est le plus largement supporté, WebM est ouvert et efficace). Les éléments <track> ajoutent des sous-titres, légendes ou descriptions via des fichiers WebVTT. Incluez toujours du texte de repli pour les très anciens navigateurs. Pour l'autoplay, ajoutez l'attribut muted — la plupart des navigateurs bloquent l'autoplay avec son.

html
<video width="640" height="360" controls poster="preview.jpg">
  <source src="movie.mp4" type="video/mp4">
  <source src="movie.webm" type="video/webm">
  <track kind="subtitles" src="subs_en.vtt"
         srclang="en" label="English" default>
  <track kind="captions" src="caps_en.vtt"
         srclang="en" label="English Captions">
  Your browser does not support the video tag.
</video>

Élément Audio

L'élément <audio> intègre du son. controls affiche l'UI du lecteur intégré. Sans controls, l'élément est invisible — contrôlez la lecture via JavaScript (play(), pause(), volume, currentTime). preload='auto' suggère au navigateur de mettre en tampon le fichier ; 'metadata' charge seulement la durée/info ; 'none' ne charge rien jusqu'à la lecture. MP3 a un support universel ; OGG Vorbis est ouvert mais non supporté dans Safari. Pour les jeux ou le timing précis, utilisez l'API Web Audio au lieu de <audio> pour une latence plus faible et des effets.

html
<!-- Basic audio player -->
<audio controls>
  <source src="song.mp3" type="audio/mpeg">
  <source src="song.ogg" type="audio/ogg">
  Your browser does not support audio.
</audio>

<!-- Audio controlled by JavaScript -->
<audio id="player" src="song.mp3" preload="auto"></audio>
<button onclick="document.getElementById('player').play()">Play</button>
<button onclick="document.getElementById('player').pause()">Pause</button>
<button onclick="document.getElementById('player').volume += 0.1">Vol+</button>

Picture & srcset (images responsives)

Les images responsives améliorent la performance en servant des images de taille appropriée. srcset avec des descripteurs de largeur (480w, 800w) plus des hints sizes laisse le navigateur choisir la meilleure image — c'est préféré pour la commutation de résolution. <picture> avec des media queries permet la direction artistique (recadrages différents pour différents écrans). <source> avec des attributs type fournit des replis de format moderne (WebP, AVIF) avec repli JPG/PNG. Incluez toujours un <img> régulier comme dernier enfant de <picture> pour le repli et l'accessibilité.

html
<!-- srcset: let browser choose resolution -->
<img src="small.jpg"
     srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"
     sizes="(max-width: 600px) 480px, 800px"
     alt="Responsive image">

<!-- picture: art direction with different images -->
<picture>
  <source media="(max-width: 600px)" srcset="mobile.jpg">
  <source media="(max-width: 1200px)" srcset="tablet.jpg">
  <img src="desktop.jpg" alt="Art-directed image">
</picture>

<!-- Modern format with fallback -->
<picture>
  <source type="image/webp" srcset="photo.webp">
  <source type="image/avif" srcset="photo.avif">
  <img src="photo.jpg" alt="With format fallback">
</picture>

Intégration iframe

Les iframes intègrent un autre document dans la page courante. L'attribut title est essentiel pour l'accessibilité — les lecteurs d'écran l'annoncent. L'attribut sandbox restreint les capacités de l'iframe pour la sécurité : valeur vide bloque tout ; ajoutez des tokens (allow-scripts, allow-forms, allow-same-origin) pour réactiver des fonctionnalités spécifiques. loading='lazy' diffère le chargement jusqu'au voisinage du viewport. allow spécifie les politiques de fonctionnalités (camera, microphone, autoplay). Soyez prudent en intégrant du contenu non fiable — sandboxez-le. Les iframes cross-origin ne peuvent pas être accédées via JavaScript.

html
<!-- Basic iframe -->
<iframe src="https://example.com"
        width="600" height="400"
        title="Embedded Content">
</iframe>

<!-- Sandboxed iframe for security -->
<iframe src="untrusted.html"
        sandbox="allow-scripts allow-same-origin"
        loading="lazy">
</iframe>

<!-- YouTube embed -->
<iframe src="https://www.youtube.com/embed/VIDEO_ID"
        allow="accelerometer; autoplay; encrypted-media"
        allowfullscreen
        title="YouTube video">
</iframe>

Embed & Object

<embed> et <object> sont des méthodes d'intégration plus anciennes, largement remplacées par <iframe> et <video>. <embed> est auto-fermant et simple mais n'offre aucun contenu de repli. <object> est plus flexible — le contenu à l'intérieur des balises sert de repli si la ressource intégrée ne peut pas être affichée. Utilisez <object> pour les PDF et SVGs où vous avez besoin de repli. Pour le développement web moderne, préférez <iframe> pour les pages externes, <video>/<audio> pour les médias, et <svg> en ligne pour les graphiques vectoriels. <embed> est principalement utilisé pour le contenu de plugin (Flash, maintenant déprécié).

html
<!-- embed: simple, self-closing -->
<embed src="animation.svg" type="image/svg+xml"
       width="300" height="200">

<!-- object: more flexible with fallback -->
<object data="document.pdf" type="application/pdf"
        width="100%" height="600px">
  <p>Unable to display PDF.
     <a href="document.pdf">Download it instead.</a>
  </p>
</object>

<!-- embed YouTube without iframe -->
<embed src="https://www.youtube.com/v/VIDEO_ID"
       type="application/x-shockwave-flash"
       width="560" height="315">
15

Approfondissement des types d'entrée

Entrées date & heure

Les types d'entrée date/heure HTML5 fournissent des sélecteurs natifs sans bibliothèques JavaScript. type='date' donne un calendrier ; type='time' donne un sélecteur d'heure ; type='datetime-local' combine les deux. type='month' et type='week' sélectionnent des mois et semaines. min/max contraignent la plage sélectionnable. step définit la granularité (par exemple, step='1800' pour des intervalles de 30 minutes en secondes). Le format affiché varie selon le navigateur/locale, mais la valeur soumise est toujours au format ISO 8601 (YYYY-MM-DD). Tous les navigateurs ne supportent pas tous les types également — testez inter-navigateurs.

html
<label for="birthday">Birthday:</label>
<input type="date" id="birthday" min="1900-01-01" max="2025-12-31">

<label for="appt">Appointment:</label>
<input type="time" id="appt" min="09:00" max="17:00" step="1800">

<label for="meeting">Meeting:</label>
<input type="datetime-local" id="meeting">

<label for="month">Pick a month:</label>
<input type="month" id="month">

<label for="week">Pick a week:</label>
<input type="week" id="week">

Entrées nombre & plage

type='number' fournit un contrôle spinner avec des flèches haut/bas. min, max et step contraignent les valeurs. Pour la monnaie, utilisez step='0.01'. type='range' rend un slider — associez-le toujours avec un <output> ou un label visible montrant la valeur courante, car la valeur n'est pas affichée par défaut. Les entrées nombre filtrent l'entrée non numérique mais permettent encore certains caractères invalides ; validez côté serveur. Pour les quantités qui n'ont pas besoin de spinner, envisagez type='text' avec inputmode='numeric' et validation de pattern.

html
<label for="qty">Quantity (1-100):</label>
<input type="number" id="qty" min="1" max="100"
       step="1" value="10">

<label for="price">Price ($):</label>
<input type="number" id="price" min="0" step="0.01"
       placeholder="0.00">

<label for="volume">Volume:</label>
<input type="range" id="volume" min="0" max="100"
       value="50" oninput="out.value=this.value">
<output id="out">50</output>

Entrées couleur & fichier

type='color' ouvre un sélecteur de couleur natif et renvoie une valeur hex (#rrggbb). type='file' laisse les utilisateurs sélectionner des fichiers. L'attribut accept filtre par type MIME ou extension (image/*, .pdf, image/png). L'attribut multiple permet de sélectionner plusieurs fichiers. Accédez aux fichiers sélectionnés via la propriété files (une FileList) en JavaScript. Utilisez URL.createObjectURL() pour créer une URL de prévisualisation locale pour les images. Pour les gros téléversements, envisagez les téléversements chunked ou l'API File pour le suivi de progression. Validez toujours les types et tailles de fichier côté serveur.

html
<label for="color">Pick a color:</label>
<input type="color" id="color" value="#ff0000">

<label for="avatar">Upload avatar:</label>
<input type="file" id="avatar" accept="image/*">

<label for="docs">Upload documents:</label>
<input type="file" id="docs" accept=".pdf,.doc,.docx" multiple>

<!-- File input with image preview -->
<input type="file" accept="image/*" onchange="preview(this)">
<img id="preview-img" hidden>
<script>
function preview(input) {
  const file = input.files[0];
  if (file) {
    document.getElementById("preview-img").src =
      URL.createObjectURL(file);
    document.getElementById("preview-img").hidden = false;
  }
}
</script>

datalist (suggestions d'entrée)

<datalist> fournit des suggestions d'autocomplétion pour les champs d'entrée. Liez-le à une entrée via l'attribut list correspondant à l'id du datalist. Contrairement à <select>, les utilisateurs peuvent encore taper n'importe quelle valeur — les suggestions sont optionnelles. Cela fonctionne avec les entrées text, number, date, color et range. Le navigateur montre les suggestions correspondantes au fur et à mesure que l'utilisateur tape. C'est une alternative légère aux bibliothèques d'autocomplétion JavaScript pour les cas d'usage simples. Note : le style des options dans datalist n'est pas supporté — elles s'affichent avec les défauts du navigateur.

html
<label for="browser">Favorite browser:</label>
<input list="browsers" id="browser" name="browser">
<datalist id="browsers">
  <option value="Chrome">
  <option value="Firefox">
  <option value="Safari">
  <option value="Edge">
  <option value="Opera">
</datalist>

<!-- Works with various input types -->
<label for="color">Choose color:</label>
<input type="color" list="preset-colors" id="color">
<datalist id="preset-colors">
  <option value="#ff0000">
  <option value="#00ff00">
  <option value="#0000ff">
</datalist>

Attributs de validation de formulaire

HTML5 fournit une validation côté client intégrée via des attributs. required empêche la soumission si vide. type='email'/'url' valident le format automatiquement. minlength/maxlength contraignent la longueur du texte. min/max contraignent les nombres et dates. pattern utilise les regex pour une validation personnalisée. Le navigateur montre des bulles d'erreur par défaut. Personnalisez les messages avec setCustomValidity() — mais effacez-le toujours à l'entrée (setCustomValidity('')) pour éviter les erreurs persistantes. La validation côté client améliore l'UX mais doit être associée à une validation côté serveur pour la sécurité, car elle peut être contournée.

html
<form>
  <label>Email: <input type="email" required></label>
  <label>Username:
    <input type="text" required minlength="3" maxlength="20"
           pattern="[a-zA-Z0-9_]+">
  </label>
  <label>Age:
    <input type="number" min="18" max="120" required>
  </label>
  <label>Website:
    <input type="url" placeholder="https://example.com">
  </label>
  <button type="submit">Submit</button>
</form>

<!-- Custom validation message -->
<input type="text" required
  oninvalid="this.setCustomValidity('Please enter your name')"
  oninput="this.setCustomValidity('')">
16

Service Worker & PWA

Enregistrement du Service Worker

Un service worker est un fichier JavaScript qui s'exécute en arrière-plan, séparé de la page web, permettant le support hors ligne, les notifications push et la synchronisation en arrière-plan. Enregistrez-le depuis la page principale — il doit être servi sur HTTPS. L'emplacement du fichier service worker détermine sa portée (il contrôle les pages dans son répertoire et sous-répertoires). L'enregistrement est asynchrone et se produit une seule fois par portée. Après la première visite, le SW s'active sur les chargements de page suivants. Utilisez l'événement load pour différer l'enregistrement jusqu'à après que la page soit interactive.

html
<!-- Register a service worker in main page -->
<script>
if ("serviceWorker" in navigator) {
  window.addEventListener("load", () => {
    navigator.serviceWorker
      .register("/sw.js")
      .then((reg) => {
        console.log("SW registered:", reg.scope);
      })
      .catch((err) => {
        console.log("SW registration failed:", err);
      });
  });
}
</script>

Service Worker : mise en cache

Le lifecycle du service worker a trois phases : install (mettre en cache les assets core), activate (nettoyer les anciens caches) et fetch (intercepter les requêtes réseau). La stratégie cache-first montrée ici sert les réponses en cache immédiatement, avec repli sur le réseau. D'autres stratégies incluent network-first (essayer le réseau, repli sur le cache) et stale-while-revalidate (servir le cache, mettre à jour en arrière-plan). Incrémentez CACHE_NAME pour déclencher les mises à jour de cache. L'API Cache stocke les paires Request/Response. Les service workers ne s'exécutent que quand nécessaire et peuvent être terminés par le navigateur pour économiser de la mémoire.

html
// sw.js - Cache assets for offline use
const CACHE_NAME = "my-app-v1";
const ASSETS = ["/", "/index.html", "/style.css", "/app.js"];

// Install: cache core assets
self.addEventListener("install", (e) => {
  e.waitUntil(
    caches.open(CACHE_NAME).then((cache) => cache.addAll(ASSETS))
  );
});

// Fetch: serve from cache, fall back to network
self.addEventListener("fetch", (e) => {
  e.respondWith(
    caches.match(e.request).then((cached) => {
      return cached || fetch(e.request);
    })
  );
});

// Activate: clean old caches
self.addEventListener("activate", (e) => {
  e.waitUntil(
    caches.keys().then((keys) =>
      Promise.all(
        keys.filter((k) => k !== CACHE_NAME)
            .map((k) => caches.delete(k))
      )
    )
  );
});

Manifeste d'application web

Le Web App Manifest est un fichier JSON qui rend une application web installable (Ajouter à l'écran d'accueil). name est le nom complet ; short_name apparaît sur l'icône de l'écran d'accueil. display:'standalone' cache l'UI du navigateur, la faisant ressembler à une app native. theme_color affecte la couleur du chrome du navigateur. icons doit inclure au moins les tailles 192px et 512px. 'purpose':'maskable' laisse Android adapter l'icône à différentes formes. Un manifeste valide plus un service worker enregistré sont les exigences minimales pour une PWA. Testez avec Lighthouse pour la conformité PWA.

html
<!-- Link the manifest in HTML -->
<link rel="manifest" href="manifest.json">

<!-- manifest.json -->
{
  "name": "My PWA App",
  "short_name": "MyApp",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#1976d2",
  "orientation": "portrait",
  "icons": [
    {
      "src": "/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icon-512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ]
}

Notifications push

Les notifications push vous permettent de réengager les utilisateurs même quand l'onglet est fermé. D'abord demandez l'autorisation avec Notification.requestPermission(). Puis abonnez-vous via PushManager — l'objet d'abonnement contient une URL endpoint et des clés. Envoyez cet abonnement à votre serveur, qui l'utilise pour envoyer des messages push via l'API Web Push (avec des clés VAPID pour l'authentification). Le gestionnaire d'événement push du service worker affiche la notification. userVisibleOnly:true signifie que chaque push doit afficher une notification (pas de push silencieux). Nécessite HTTPS et un service worker.

html
<!-- Request notification permission -->
<button onclick="subscribe()">Enable Notifications</button>

<script>
async function subscribe() {
  const permission = await Notification.requestPermission();
  if (permission !== "granted") return;

  const reg = await navigator.serviceWorker.ready;
  const subscription = await reg.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: urlBase64ToUint8Array(VAPID_KEY)
  });
  // Send subscription to your server
  await fetch("/api/subscribe", {
    method: "POST",
    body: JSON.stringify(subscription)
  });
}
</script>

<!-- In sw.js: handle push events -->
self.addEventListener("push", (e) => {
  const data = e.data.json();
  e.waitUntil(
    self.registration.showNotification(data.title, {
      body: data.body,
      icon: "/icon-192.png",
      badge: "/badge.png"
    })
  );
});

Synchronisation en arrière-plan

Background Sync vous permet de différer des actions jusqu'à ce que l'utilisateur ait une connectivité stable. Quand vous enregistrez un événement sync, le navigateur le déclenche quand la connectivité est restaurée — même si l'utilisateur a fermé l'onglet. Le gestionnaire d'événement sync (dans le service worker) effectue le travail différé. Si le travail lève une erreur, le navigateur réessaie automatiquement avec un backoff exponentiel. e.tag identifie le type de sync — une seule sync par tag est mise en file. Utilisez IndexedDB pour stocker les données en attente. C'est idéal pour les apps de messagerie, soumissions de formulaire et sync de données. Periodic Sync (pour des mises à jour régulières) est disponible dans Chrome mais pas tous les navigateurs.

html
// Register a sync event from the page
navigator.serviceWorker.ready.then((reg) => {
  return reg.sync.register("send-messages");
});

// Handle sync in sw.js
self.addEventListener("sync", (e) => {
  if (e.tag === "send-messages") {
    e.waitUntil(sendPendingMessages());
  }
});

async function sendPendingMessages() {
  const messages = await getMessagesFromIndexedDB();
  for (const msg of messages) {
    try {
      await fetch("/api/messages", {
        method: "POST",
        body: JSON.stringify(msg)
      });
      await deleteMessageFromIndexedDB(msg.id);
    } catch (err) {
      throw err; // triggers retry
    }
  }
}
17

Approfondissement des balises méta (Open Graph & Twitter)

Balises Open Graph (Facebook)

Les balises Open Graph (OG) contrôlent comment votre page apparaît quand partagée sur Facebook, LinkedIn et la plupart des plateformes sociales. og:title est le titre ; og:description est le résumé ; og:image est l'image de prévisualisation (recommandé 1200x630px). og:type (website, article, video.movie) affecte le rendu. Pour les articles, ajoutez article:published_time, article:author et article:section pour des aperçus plus riches. Spécifiez toujours les dimensions og:image pour un rendu plus rapide. Testez avec le Sharing Debugger de Facebook. Les balises OG sont essentielles pour le marketing sur les réseaux sociaux et les taux de clic.

html
<head>
  <meta property="og:title" content="My Awesome Article">
  <meta property="og:description" content="A deep dive into modern web development.">
  <meta property="og:type" content="article">
  <meta property="og:url" content="https://example.com/article">
  <meta property="og:image" content="https://example.com/img/og.jpg">
  <meta property="og:image:width" content="1200">
  <meta property="og:image:height" content="630">
  <meta property="og:site_name" content="My Website">
  <meta property="og:locale" content="en_US">
  <meta property="article:published_time" content="2025-01-15T08:00:00Z">
  <meta property="article:author" content="Jane Doe">
</head>

Balises Twitter Card

Les balises Twitter Card contrôlent comment les liens apparaissent sur X (Twitter). Le type twitter:card peut être 'summary' (petite image), 'summary_large_image' (grande image au-dessus du texte), 'player' (vidéo/audio) ou 'app'. twitter:site est le @handle du site ; twitter:creator est le @handle de l'auteur. L'image devrait faire au moins 300x157px (summary) ou 600x314px (grande image). twitter:image:alt améliore l'accessibilité. Testez avec le Card Validator de Twitter. Même si vous avez des balises OG, ajouter des balises Twitter spécifiques vous donne plus de contrôle sur les aperçus Twitter.

html
<head>
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:site" content="@mywebsite">
  <meta name="twitter:creator" content="@janedoe">
  <meta name="twitter:title" content="My Awesome Article">
  <meta name="twitter:description" content="A deep dive into modern web dev.">
  <meta name="twitter:image" content="https://example.com/img/twitter.jpg">
  <meta name="twitter:image:alt" content="Article cover image">
</head>

Viewport & méta mobile

La balise méta viewport est critique pour le design responsive — sans elle, les navigateurs mobiles rendent les pages à largeur desktop et zooment arrière. width=device-width correspond à la largeur de l'appareil ; initial-scale=1 définit le niveau de zoom. Évitez de désactiver le zoom utilisateur (user-scalable=no) car cela viole les directives d'accessibilité WCAG. apple-mobile-web-app-capable rend l'app plein écran quand ajoutée à l'écran d'accueil iOS. theme-color affecte la couleur de la barre d'adresse du navigateur sur Chrome mobile et Safari. Ces balises spécifiques mobile améliorent significativement l'expérience PWA et mobile.

html
<head>
  <!-- Responsive viewport -->
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0">

  <!-- Disable zoom (accessibility concern — avoid) -->
  <meta name="viewport"
        content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

  <!-- iOS Safari: full-screen web app -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style"
        content="black-translucent">
  <meta name="apple-mobile-web-app-title" content="MyApp">

  <!-- Android Chrome theme color -->
  <meta name="theme-color" content="#1976d2">
</head>

HTTP-Equiv & Charset

Les balises méta http-equiv simulent des en-têtes HTTP directement dans HTML. charset doit être le premier élément dans <head> et dans les 1024 premiers octets pour prévenir les attaques XSS basées sur l'encodage. http-equiv='refresh' redirige après un délai — préférez les redirections côté serveur pour le SEO. Content-Security-Policy via méta est limité (pas de report-uri, pas de frame-ancestors) — préférez les en-têtes HTTP. Cache-Control via méta n'est pas fiable — utilisez les en-têtes HTTP à la place. X-UA-Compatible force IE à utiliser son dernier moteur de rendu. Préférez toujours les vrais en-têtes HTTP à http-equiv quand possible.

html
<head>
  <!-- Character encoding (must be first in head) -->
  <meta charset="UTF-8">

  <!-- Refresh/redirect after 5 seconds -->
  <meta http-equiv="refresh" content="5; url=https://example.com">

  <!-- Set content security policy -->
  <meta http-equiv="Content-Security-Policy"
        content="default-src 'self'; script-src 'self'">

  <!-- X-UA-Compatible for IE -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge">

  <!-- Cache control -->
  <meta http-equiv="Cache-Control"
        content="no-cache, no-store, must-revalidate">
</head>

Données structurées (JSON-LD)

JSON-LD (JavaScript Object Notation for Linked Data) est le format recommandé par Google pour les données structurées. Il aide les moteurs de recherche à comprendre votre contenu, activant les extraits enrichis (étoiles de notation, dates d'événement, fils d'Ariane, accordéons FAQ) dans les résultats de recherche. Les types courants incluent Article, Product, Recipe, Event, LocalBusiness et FAQPage. Placez le script dans le <head> avec type='application/ld+json'. Validez avec le Rich Results Test de Google. Les données structurées ne garantissent pas les extraits enrichis mais vous rendent éligible. C'est un puissant outil SEO pour augmenter les taux de clic depuis les résultats de recherche.

html
<head>
  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": "My Awesome Article",
    "author": {
      "@type": "Person",
      "name": "Jane Doe"
    },
    "datePublished": "2025-01-15",
    "image": "https://example.com/img/article.jpg",
    "publisher": {
      "@type": "Organization",
      "name": "My Website",
      "logo": {
        "@type": "ImageObject",
        "url": "https://example.com/logo.png"
      }
    }
  }
  </script>
</head>
18

Approfondissement du HTML sémantique

Article vs Section vs Div

Choisir le bon élément conteneur compte pour l'accessibilité et le SEO. <article> est pour le contenu qui pourrait être distribué indépendamment (articles de blog, news, commentaires, cartes produit). <section> regroupe le contenu thématiquement lié — il devrait toujours avoir un titre. <div> est un dernier recours pour la mise en page/le style quand aucun élément sémantique ne convient. Les éléments <article> imbriqués (comme les commentaires dans un post) sont valides. La règle empirique : si le contenu pourrait être syndiqué via RSS, utilisez <article> ; si c'est un chapitre thématique, utilisez <section> ; si c'est purement pour la mise en page, utilisez <div>.

html
<!-- <article>: self-contained, syndicable content -->
<article>
  <h2>Blog Post Title</h2>
  <p>Content that makes sense on its own...</p>
  <article><h3>Comment 1</h3><p>...</p></article>
</article>

<!-- <section>: thematic grouping with a heading -->
<section>
  <h2>Chapter 1: Introduction</h2>
  <p>Related content...</p>
</section>

<!-- <div>: generic container, no semantic meaning -->
<div class="layout-wrapper">
  <div class="grid-item">Styling hook only</div>
</div>

Figure & Figcaption

<figure> représente le contenu autonome référencé depuis le texte principal — images, diagrammes, listes de code ou citations. <figcaption> fournit une légende/titre. Contrairement à un simple <img>, figure/figcaption lie sémantiquement le visuel à sa description. Les lecteurs d'écran annoncent les figures avec leurs légendes. Les figures peuvent être positionnées n'importe où par rapport au texte qui les référence. Utilisez <figure> pour tout contenu qui a une légende et est référencé par numéro (Figure 1, Listing 1). Pour les images purement décoratives, utilisez un simple <img> avec alt vide.

html
<figure>
  <img src="chart.png" alt="Sales growth chart showing 40% increase">
  <figcaption>
    Figure 1: Quarterly sales growth from Q1 to Q4 2025.
    Data source: Internal sales database.
  </figcaption>
</figure>

<!-- Figure can contain code blocks too -->
<figure>
  <pre><code>const x = 42;</code></pre>
  <figcaption>Listing 1: Variable declaration example</figcaption>
</figure>

Details & Summary (divulgation)

<details> et <summary> créent des sections repliables natives (accordéon) sans aucun JavaScript. Cliquer sur le <summary> bascule le contenu. L'attribut open le rend déplié par défaut. L'événement toggle se déclenche à l'expansion/repli. C'est excellent pour les FAQ, panneaux de paramètres et divulgation progressive. Les lecteurs d'écran l'annoncent comme un widget de divulgation. Vous pouvez styler le marqueur triangulaire par défaut avec CSS (summary::-webkit-details-marker ou list-style). Pour les interactions complexes, vous pouvez encore avoir besoin de JavaScript, mais pour les bascules simples, cette solution native est idéale.

html
<!-- Native collapsible without JavaScript -->
<details>
  <summary>Click to expand FAQ</summary>
  <p>Here is the hidden answer that appears when expanded.</p>
</details>

<!-- Open by default -->
<details open>
  <summary>Already expanded</summary>
  <p>This content is visible on page load.</p>
</details>

<!-- Nested disclosures -->
<details>
  <summary>Level 1</summary>
  <details>
    <summary>Level 2</summary>
    <p>Deeply nested content</p>
  </details>
</details>

Éléments Time & Mark

<time> enveloppe des dates/heures lisibles par l'humain avec un attribut datetime lisible par machine au format ISO 8601. Cela aide les moteurs de recherche, calendriers et technologies d'assistance à parser les dates correctement. datetime supporte les dates (YYYY-MM-DD), heures (HH:MM), datetimes avec fuseau horaire et durées (PT2H30M). <mark> représente le texte surligné pour pertinence, comme les correspondances de termes de recherche. Contrairement à <strong> ou <em> (qui indiquent importance/emphase), <mark> indique la pertinence contextuelle. Les deux éléments améliorent la signification sémantique et le SEO.

html
<!-- <time>: machine-readable dates/times -->
<p>Published on
  <time datetime="2025-01-15">January 15, 2025</time>
</p>
<p>Event at
  <time datetime="2025-03-20T14:30-05:00">2:30 PM EST</time>
</p>
<p>Duration:
  <time datetime="PT2H30M">2 hours 30 minutes</time>
</p>

<!-- <mark>: highlighted/relevant text -->
<p>Search results: the keyword
  <mark>HTML5</mark> appears in 3 documents.
</p>

Élément Dialog

L'élément <dialog> fournit des dialogues natifs modaux et non modaux sans bibliothèques. showModal() l'ouvre comme modal (avec backdrop, bloque l'interaction de page) ; show() l'ouvre non modalement. close() le ferme. form method='dialog' ferme le dialogue à la soumission, avec la valeur du bouton comme returnValue. Le pseudo-élément ::backdrop style l'overlay modal. La touche ESC ferme les dialogues modaux automatiquement. Le rendu top layer signifie que le dialogue apparaît au-dessus de tout autre contenu quel que soit le z-index. L'événement close se déclenche après la fermeture. C'est maintenant bien supporté et remplace beaucoup de bibliothèques de dialogues JavaScript.

html
<!-- Native modal dialog -->
<dialog id="myDialog">
  <h2>Confirm Action</h2>
  <p>Are you sure you want to proceed?</p>
  <form method="dialog">
    <button value="cancel">Cancel</button>
    <button value="confirm">Confirm</button>
  </form>
</dialog>

<button onclick="document.getElementById('myDialog').showModal()">
  Open Modal
</button>

<script>
const dialog = document.getElementById("myDialog");
dialog.addEventListener("close", () => {
  console.log("Dialog closed with:", dialog.returnValue);
});
// Close on backdrop click
dialog.addEventListener("click", (e) => {
  if (e.target === dialog) dialog.close();
});
</script>
19

Formulaires avancés & entrée

Fieldset & Legend

<fieldset> regroupe les contrôles de formulaire liés, et <legend> fournit une légende pour le groupe. C'est crucial pour l'accessibilité — les lecteurs d'écran annoncent la légende avant chaque contrôle du groupe, fournissant le contexte. L'attribut disabled sur un fieldset désactive tous les contrôles à l'intérieur. Les fieldsets améliorent aussi l'organisation visuelle avec une bordure par défaut. Pour les boutons radio, fieldset/legend est la manière recommandée d'étiqueter le groupe. Évitez d'imbriquer les fieldsets trop profondément, car cela peut confondre les utilisateurs de lecteur d'écran.

html
<form>
  <fieldset>
    <legend>Shipping Address</legend>
    <label>Street: <input type="text" name="street" required></label>
    <label>City: <input type="text" name="city" required></label>
    <label>ZIP: <input type="text" name="zip" pattern="[0-9]{5}"></label>
  </fieldset>

  <fieldset disabled>
    <legend>Billing (same as shipping)</legend>
    <label>Card: <input type="text" name="card"></label>
  </fieldset>

  <fieldset>
    <legend>Subscription Plan</legend>
    <label><input type="radio" name="plan" value="free"> Free</label>
    <label><input type="radio" name="plan" value="pro" checked> Pro</label>
  </fieldset>
</form>

Éléments Output & Progress

<output> affiche le résultat d'un calcul — il a une relation live avec les entrées de formulaire (via l'attribut for). C'est sémantiquement plus significatif qu'un span pour les valeurs calculées. <progress> représente l'achèvement d'une tâche (value/max) ; sans valeur, il montre un spinner indéterminé. <meter> représente une valeur scalaire dans une plage connue (comme l'espace disque ou les scores de test) — les attributs low, high et optimum définissent les seuils qui affectent la couleur (vert/jaune/rouge). Progress et meter ont tous deux un style intégré qui varie selon le navigateur mais peut être personnalisé avec CSS.

html
<form oninput="result.value = parseInt(a.value) + parseInt(b.value)">
  <input type="number" id="a" value="10"> +
  <input type="number" id="b" value="20"> =
  <output name="result" for="a b">30</output>
</form>

<!-- Progress bar -->
<label>Downloading: <progress id="prog" value="70" max="100">70%</progress></label>

<!-- Meter (gauge within a range) -->
<label>Disk usage: <meter value="0.6" min="0" max="1" low="0.5" high="0.8" optimum="0.2">60%</meter></label>
<label>Score: <meter value="85" min="0" max="100" low="40" high="70" optimum="90">85</meter></label>

Autocomplétion de formulaire

L'attribut autocomplete aide les navigateurs à remplir les formulaires en utilisant les données utilisateur stockées. Utilisez des tokens standardisés : 'name', 'email', 'tel', 'street-address', 'address-level2' (ville), 'postal-code', 'country'. Pour les cartes de crédit : 'cc-name', 'cc-number', 'cc-exp'. autocomplete='off' désactive l'autoremplissage (bien que les navigateurs puissent l'ignorer pour les champs non sensibles). autocomplete='one-time-code' déclenche l'autoremplissage de code SMS sur mobile. Des tokens autocomplete appropriés améliorent considérablement les taux de complétion de formulaire et l'expérience utilisateur. Ils aident aussi les gestionnaires de mots de passe à identifier les champs correctement.

html
<form autocomplete="on">
  <!-- Browser can autofill name -->
  <label>Name: <input type="text" name="name" autocomplete="name"></label>

  <!-- Email autofill -->
  <label>Email: <input type="email" name="email" autocomplete="email"></label>

  <!-- Address autofill tokens -->
  <fieldset>
    <legend>Address</legend>
    <input autocomplete="street-address">
    <input autocomplete="address-level2"> <!-- City -->
    <input autocomplete="postal-code">
    <input autocomplete="country">
  </fieldset>

  <!-- Disable autocomplete for sensitive field -->
  <label>SSN: <input type="text" autocomplete="off"></label>

  <!-- One-time code (SMS) -->
  <label>Code: <input type="text" autocomplete="one-time-code"></label>
</form>

Méthodes de soumission de formulaire

GET ajoute les données de formulaire à l'URL (visible, bookmarkable, longueur limitée) — utilisez pour les recherches et filtres. POST envoie les données dans le corps de la requête (non visible, pas de limite de longueur) — utilisez pour créer/mettre à jour des données. enctype='multipart/form-data' est requis pour les téléversements de fichiers. La paire nom/valeur du bouton est incluse dans la soumission — de multiples boutons submit peuvent déclencher différentes actions via le même nom avec différentes valeurs. Pour la soumission AJAX, utilisez l'objet FormData et fetch(). Utilisez toujours POST pour les données sensibles, car les données GET apparaissent dans l'historique du navigateur et les logs serveur.

html
<!-- GET: data in URL query string -->
<form method="GET" action="/search">
  <input name="q" value="html5">
  <!-- URL: /search?q=html5 -->
</form>

<!-- POST: data in request body -->
<form method="POST" action="/submit" enctype="application/x-www-form-urlencoded">
  <input name="name" value="Alice">
</form>

<!-- File upload: multipart -->
<form method="POST" action="/upload" enctype="multipart/form-data">
  <input type="file" name="document">
</form>

<!-- Form with custom submit button -->
<form method="POST" action="/save">
  <button type="submit" name="action" value="save">Save</button>
  <button type="submit" name="action" value="publish">Publish</button>
</form>

Contenteditable & Spellcheck

contenteditable='true' rend n'importe quel élément directement éditable dans le navigateur — la base des éditeurs de texte riche. spellcheck='true' active la vérification orthographique du navigateur (soulignement rouge pour les fautes). Pour les extraits de code, définissez spellcheck='false' pour éviter les faux positifs. L'attribut contenteditable peut être hérité — les éléments enfants sont éditables sauf si définis à 'false'. Sauvegarder le contenu éditable nécessite JavaScript (par exemple, stockage dans localStorage à l'entrée). Construire un éditeur de texte riche complet avec contenteditable est complexe (gestion du collage, formatage, position du curseur) — envisagez des bibliothèques comme Quill, TipTap ou ProseMirror pour la production.

html
<!-- Editable div -->
<div contenteditable="true">
  Click to edit this text directly in the browser.
</div>

<!-- Editable with spellcheck -->
<p contenteditable="true" spellcheck="true">
  Typoos will be underlined in red.
</p>

<!-- Turn off spellcheck for code -->
<pre contenteditable="true" spellcheck="false">
  const varible = "code"; // no spellcheck
</pre>

<!-- Entire document editable -->
<body contenteditable="true">

<!-- Save editable content -->
<div id="note" contenteditable="true"
     oninput="localStorage.setItem('note', this.innerHTML)">
  <script>document.getElementById('note').innerHTML =
    localStorage.getItem('note') || '';</script>
</div>
20

Balises méta SEO

Balises Open Graph

Les balises Open Graph (créées par Facebook) contrôlent comment votre page apparaît quand partagée sur les réseaux sociaux. og:image devrait faire 1200x630px. Sans ces balises, les plateformes inventent des aperçus à partir du contenu de la page, souvent mal.

html
<meta property="og:title" content="My Awesome Article">
<meta property="og:description" content="A deep dive into modern web design.">
<meta property="og:image" content="https://example.com/cover.jpg">
<meta property="og:url" content="https://example.com/article">
<meta property="og:type" content="article">
<meta property="og:site_name" content="Example Site">

Twitter Cards

Les balises Twitter Card contrôlent comment les liens s'affichent sur X/Twitter. summary_large_image montre une image proéminente au-dessus du titre ; summary montre une plus petite vignette carrée. La balise twitter:site lie la card à votre compte.

html
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@yoursite">
<meta name="twitter:title" content="My Article">
<meta name="twitter:description" content="A deep dive into web design.">
<meta name="twitter:image" content="https://example.com/cover.jpg">

Canonical & Robots

rel="canonical" prévient les pénalités de contenu dupliqué en pointant vers l'URL maître. La balise méta robots dirige les crawlers : noindex retire la page des résultats, nofollow bloque le suivi des liens.

html
<!-- Canonical: tells search engines the preferred URL -->
<link rel="canonical" href="https://example.com/article">

<!-- Robots: control indexing -->
<meta name="robots" content="index, follow">
<meta name="robots" content="noindex, nofollow">
<meta name="robots" content="noindex, follow">

Données structurées (JSON-LD)

Les données structurées JSON-LD aident les moteurs de recherche à comprendre le contenu et activent les résultats enrichis (étoiles de notation, fils d'Ariane, infos d'événement). Schema.org définit le vocabulaire. Placez la balise script dans head ou body.

html
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "Modern Web Design",
  "author": { "@type": "Person", "name": "Jane Doe" },
  "datePublished": "2025-01-15",
  "image": "https://example.com/cover.jpg"
}
</script>

Meta Description & Viewport

La balise méta description influence le taux de clic — gardez-la sous 160 caractères. La balise viewport est obligatoire pour le design responsive sur mobile. theme-color style la barre d'UI du navigateur. charset doit être le premier élément dans head.

html
<meta name="description" content="A concise 150-160 character summary that appears in search results.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#4285f4">
<meta charset="UTF-8">
21

Bases de SVG

Formes de base

SVG dessine avec des éléments XML. Les formes incluent rect, circle, ellipse, line, polyline et polygon. Contrairement aux images raster, les SVG scalent sans perte de qualité et peuvent être stylés avec CSS. fill définit la couleur intérieure, stroke définit le contour.

html
<svg width="200" height="150" xmlns="http://www.w3.org/2000/svg">
  <rect x="10" y="10" width="80" height="50" fill="steelblue"/>
  <circle cx="140" cy="40" r="30" fill="tomato"/>
  <line x1="10" y1="100" x2="180" y2="100" stroke="black" stroke-width="2"/>
  <ellipse cx="100" cy="120" rx="60" ry="20" fill="none" stroke="green"/>
</svg>

Chemins

L'élément path est la primitive SVG la plus puissante. Commandes : M (déplacer), L (ligne), H/V (horizontale/verticale), C (bezier cubique), Q (quadratique), A (arc), Z (fermer). Majuscule = coordonnées absolues, minuscule = relatives.

html
<svg width="200" height="200">
  <!-- M=move, L=line, C=cubic bezier, Z=close -->
  <path d="M 10 10 L 100 10 L 100 100 Z" fill="none" stroke="black"/>
  <path d="M 10 150 C 50 50, 150 50, 190 150" stroke="red" fill="none"/>
  <path d="M 10 180 Q 100 120 190 180" stroke="blue" fill="none"/>
</svg>

Groupes & réutilisation

Groupez des éléments avec g pour appliquer des attributs partagés ou les transformer ensemble. Définissez des formes réutilisables dans defs et référencez-les avec use href="#id". Cela garde les SVG DRY et plus petits.

html
<svg width="200" height="200">
  <defs>
    <g id="star">
      <polygon points="50,5 61,39 98,39 68,61 79,95 50,75 21,95 32,61 2,39 39,39"/>
    </g>
  </defs>
  <use href="#star" x="0" y="0" fill="gold"/>
  <use href="#star" x="100" y="100" fill="orange"/>
</svg>

Texte & style

Le texte SVG est du vrai texte — sélectionnable, recherchable et net à n'importe quelle échelle. font-family, font-size, font-weight reflètent CSS. text-anchor contrôle l'alignement horizontal (start/middle/end).

html
<svg width="300" height="100">
  <text x="10" y="50" font-family="Arial" font-size="24" fill="navy">
    Hello SVG
  </text>
  <text x="150" y="80" font-size="16" font-weight="bold" text-anchor="middle">
    Centered Bold Text
  </text>
</svg>

Dégradés & motifs

Les dégradés sont définis dans defs et référencés via fill="url(#id)". linearGradient transitionne le long d'une ligne ; radialGradient rayonne depuis un point central. Chaque stop définit une couleur à un offset de pourcentage.

html
<svg width="200" height="100">
  <defs>
    <linearGradient id="lg" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" stop-color="red"/>
      <stop offset="100%" stop-color="blue"/>
    </linearGradient>
    <radialGradient id="rg">
      <stop offset="0%" stop-color="yellow"/>
      <stop offset="100%" stop-color="green"/>
    </radialGradient>
  </defs>
  <rect width="100" height="100" fill="url(#lg)"/>
  <rect x="100" width="100" height="100" fill="url(#rg)"/>
</svg>
22

Canvas

Dessiner des formes

L'API Canvas dessine des pixels sur un élément canvas via un contexte de rendu 2D. fillRect/strokeRect dessinent des rectangles ; les chemins (beginPath, arc, lineTo) construisent des formes complexes avant fill() ou stroke(). Canvas est raster — la mise à l'échelle floute le dessin.

html
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');

ctx.fillStyle = 'tomato';
ctx.fillRect(10, 10, 100, 50);

ctx.strokeStyle = 'navy';
ctx.lineWidth = 3;
ctx.strokeRect(130, 10, 80, 80);

ctx.beginPath();
ctx.arc(200, 150, 40, 0, Math.PI * 2);
ctx.fill();

Chemins & lignes

Les chemins construisent des formes point par point. moveTo démarre un nouveau sous-chemin ; lineTo ajoute des segments droits ; closePath connecte au départ. bezierCurveTo et quadraticCurveTo dessinent des courbes avec des points de contrôle.

html
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(150, 50);
ctx.lineTo(100, 150);
ctx.closePath();
ctx.fillStyle = 'gold';
ctx.fill();
ctx.stroke();

// Bezier curves
ctx.beginPath();
ctx.moveTo(0, 200);
ctx.bezierCurveTo(100, 100, 200, 300, 300, 200);
ctx.stroke();

Dessiner des images

drawImage peint une image, vidéo ou un autre canvas. La forme à 9 arguments découpe un rectangle source et le peint dans un rectangle destination — utile pour les sprite sheets. Attendez onload avant de dessiner.

html
const img = new Image();
img.src = 'photo.jpg';
img.onload = () => {
  ctx.drawImage(img, 0, 0);                    // full image
  ctx.drawImage(img, 0, 0, 200, 150);          // scaled
  ctx.drawImage(img, 50, 50, 100, 100, 300, 0, 100, 100); // cropped
};

Boucle d'animation

requestAnimationFrame planifie draw() une fois par repeinte du navigateur (~60fps), se mettant en pause quand l'onglet est caché. clearRect efface le canvas à chaque frame pour prévenir les traînées. Pour la physique, multipliez le mouvement par le delta time pour une vitesse cohérente.

html
let x = 0;
function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = 'steelblue';
  ctx.fillRect(x, 50, 40, 40);
  x += 2;
  if (x > canvas.width) x = -40;
  requestAnimationFrame(draw);
}
requestAnimationFrame(draw);

Manipulation de pixels

getImageData renvoie un Uint8ClampedArray de valeurs de pixels RGBA bruts (0-255 par canal). L'accès direct aux pixels permet les filtres et effets. putImageData réécrit le tampon modifié. C'est lent pour les grands canvas.

html
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data; // RGBA bytes

for (let i = 0; i < data.length; i += 4) {
  const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
  data[i] = data[i + 1] = data[i + 2] = avg; // grayscale
}

ctx.putImageData(imageData, 0, 0);
23

Iframes & intégrations

Bases des iframes

Une iframe intègre un autre document dans la page courante. L'attribut title est requis pour l'accessibilité. loading="lazy" diffère le chargement jusqu'au voisinage du viewport. Définissez toujours width et height pour prévenir le décalage de mise en page.

html
<iframe
  src="https://example.com/widget"
  width="600"
  height="400"
  title="Example Widget"
  loading="lazy"
  referrerpolicy="no-referrer">
</iframe>

Attribut sandbox

L'attribut sandbox restreint les capacités d'une iframe. Une valeur vide bloque tout. Ajoutez des tokens pour réactiver des fonctionnalités : allow-scripts, allow-forms, allow-same-origin, allow-popups. Ne combinez jamais allow-scripts avec allow-same-origin pour du contenu non fiable.

html
<!-- Locks down the iframe completely -->
<iframe src="untrusted.html" sandbox></iframe>

<!-- Selectively re-enable features -->
<iframe
  src="widget.html"
  sandbox="allow-scripts allow-same-origin allow-forms">
</iframe>

Embed & Object

embed et object sont des éléments legacy. object supporte le contenu de repli affiché quand la ressource échoue. Les éléments HTML5 modernes (video, audio, picture) sont préférés. Utilisez iframe pour le contenu HTML, video pour la vidéo.

html
<!-- Embed for plugins/media -->
<embed src="video.mp4" type="video/mp4" width="400" height="300">

<!-- Object with fallback content -->
<object data="report.pdf" type="application/pdf" width="100%" height="600">
  <p>Your browser cannot display PDFs. <a href="report.pdf">Download</a></p>
</object>

<!-- Video with multiple sources -->
<video controls>
  <source src="movie.webm" type="video/webm">
  <source src="movie.mp4" type="video/mp4">
  Your browser does not support video.
</video>

Communication postMessage

postMessage est la seule manière de communiquer à travers les frontières d'iframe (origines différentes). Spécifiez toujours l'origine cible dans le troisième argument. Côté réception, vérifiez e.origin avant de faire confiance au message.

html
<!-- Parent page -->
<iframe id="f" src="child.html"></iframe>
<script>
  const frame = document.getElementById('f');
  frame.contentWindow.postMessage({ type: 'greet', text: 'Hi' }, 'https://example.com');

  window.addEventListener('message', (e) => {
    if (e.origin !== 'https://example.com') return;
    console.log('From child:', e.data);
  });
</script>

Iframes responsives

Pour rendre les iframes responsives (par exemple, vidéo 16:9), enveloppez-les dans un conteneur avec padding-bottom égal au pourcentage du ratio d'aspect (56,25% pour 16:9). Positionnez l'iframe absolument pour remplir le conteneur.

html
<div style="position:relative; padding-bottom:56.25%; height:0; overflow:hidden;">
  <iframe
    src="https://youtube.com/embed/abc"
    style="position:absolute; top:0; left:0; width:100%; height:100%; border:0;"
    title="Video"
    allowfullscreen>
  </iframe>
</div>
24

Optimisation de la performance

Resource hints

Les resource hints disent au navigateur de préparer des connexions ou récupérer des assets avant qu'ils ne soient nécessaires. preconnect réchauffe DNS/TCP/TLS. preload récupère les assets critiques de la page courante tôt. prefetch récupère les ressources de la page suivante pendant le temps d'inactivité.

html
<!-- Preconnect to a third-party origin -->
<link rel="preconnect" href="https://fonts.googleapis.com">

<!-- DNS prefetch for lower-priority origins -->
<link rel="dns-prefetch" href="https://analytics.example.com">

<!-- Preload critical assets -->
<link rel="preload" href="hero.webp" as="image">
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>

<!-- Prefetch next page -->
<link rel="prefetch" href="/next-page.html">

Chargement paresseux des images

loading="lazy" diffère le chargement des images hors écran jusqu'à ce que l'utilisateur défile près d'elles. Définissez toujours width et height pour prévenir le décalage de mise en page. L'élément picture sert les formats modernes (WebP/AVIF) avec un repli JPG.

html
<!-- Native lazy loading -->
<img src="photo.jpg" loading="lazy" width="800" height="600" alt="...">

<!-- Picture with responsive sources -->
<picture>
  <source srcset="small.webp" media="(max-width: 600px)" type="image/webp">
  <source srcset="large.webp" type="image/webp">
  <img src="large.jpg" loading="lazy" width="1200" height="800" alt="...">
</picture>

Stratégies de chargement de scripts

Sans attributs, un script bloque le parsing HTML. async télécharge en parallèle mais s'exécute immédiatement quand prêt — ordre non garanti. defer télécharge en parallèle et s'exécute dans l'ordre après que le DOM est parsé — meilleur pour les scripts principaux.

html
<!-- Normal: blocks HTML parsing -->
<script src="app.js"></script>

<!-- Async: downloads in parallel, runs ASAP -->
<script src="analytics.js" async></script>

<!-- Defer: downloads in parallel, runs after HTML parse -->
<script src="app.js" defer></script>

<!-- Module scripts defer by default -->
<script type="module" src="app.mjs"></script>

CSS critique

Inliner le CSS critique (styles nécessaires pour le contenu au-dessus de la ligne de flottaison) élimine les requêtes CSS bloquant le rendu, accélérant la première peinture. Le CSS restant se charge asynchronement via l'astuce preload. Des outils comme Critical extraient le CSS critique automatiquement.

html
<!-- Inline above-the-fold CSS in head -->
<head>
  <style>
    body { margin: 0; font-family: sans-serif; }
    .hero { height: 100vh; background: #f0f0f0; }
  </style>
  <!-- Load the rest asynchronously -->
  <link rel="preload" href="full.css" as="style" onload="this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="full.css"></noscript>
</head>

Mesurer la performance

L'API Performance mesure le timing réel de l'utilisateur. Métriques clés : FCP (First Contentful Paint), LCP (Largest Contentful Paint), CLS (Cumulative Layout Shift), INP (Interaction to Next Paint). Utilisez Lighthouse pour les données de lab.

html
// PerformanceObserver for Core Web Vitals
new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(entry.name, entry.startTime);
  }
}).observe({ entryTypes: ['paint', 'largest-contentful-paint'] });

// Navigation timing
const [nav] = performance.getEntriesByType('navigation');
console.log('DOM Content Loaded:', nav.domContentLoadedEventEnd);
console.log('Load:', nav.loadEventEnd);
25

Formulaires avancés

Types d'entrée

Les types d'entrée HTML5 fournissent une validation et UI intégrées. email/url valident le format. number/date fournissent des sélecteurs. color/range ont une UI spécialisée. accept filtre les types de fichiers. Les navigateurs gèrent la validation automatiquement.

html
<input type="email" required>
<input type="url" placeholder="https://">
<input type="number" min="0" max="100" step="5">
<input type="date" min="2024-01-01">
<input type="color" value="#ff0000">
<input type="range" min="0" max="10">
<input type="file" accept="image/*">

Validation de formulaire

required empêche la soumission si vide. minlength/maxlength limitent la longueur. pattern utilise la validation regex. Le navigateur empêche la soumission et montre les erreurs. Personnalisez avec setCustomValidity et l'événement invalid.

html
<form>
  <input type="text" required minlength="3" maxlength="20" pattern="[A-Za-z]+">
  <input type="email" required>
  <input type="submit" value="Submit">
</form>

Fieldset & Legend

fieldset regroupe les champs de formulaire liés. legend fournit une légende. disabled sur fieldset désactive tous les champs. Améliore l'accessibilité en regroupant les entrées liées. Les lecteurs d'écran annoncent la légende pour chaque champ.

html
<fieldset>
  <legend>Shipping Address</legend>
  <label>Street: <input type="text" name="street"></label>
  <label>City: <input type="text" name="city"></label>
</fieldset>
<fieldset disabled>
  <legend>Billing (disabled)</legend>
  <input type="text" name="billing">
</fieldset>

Datalist

datalist fournit des suggestions d'autocomplétion pour input. Les utilisateurs peuvent sélectionner ou taper librement. Contrairement à select, il permet des valeurs personnalisées. L'attribut list lie input à datalist par id. Utile pour la recherche et les tags.

html
<label>Choose browser:
  <input list="browsers" name="browser">
</label>
<datalist id="browsers">
  <option value="Chrome">
  <option value="Firefox">
  <option value="Safari">
</datalist>

Élément Output

output affiche les résultats calculés. L'attribut for lie aux IDs d'entrée. Se met à jour en live avec les changements de formulaire. Pas de JavaScript nécessaire pour les calculs simples. Accessible aux lecteurs d'écran comme une région live.

html
<form oninput="result.value = parseInt(a.value) + parseInt(b.value)">
  <input type="number" id="a" value="0"> +
  <input type="number" id="b" value="0"> =
  <output name="result" for="a b">0</output>
</form>
26

Accessibilité (a11y)

Labels ARIA

aria-label fournit des noms accessibles pour les éléments sans texte visible. aria-expanded indique l'état de bascule. aria-controls lie à l'élément contrôlé. Utilisez ARIA seulement quand la sémantique HTML est insuffisante.

html
<button aria-label="Close menu" onclick="closeMenu()">
  <svg>...</svg>
</button>
<nav aria-label="Main navigation">...</nav>
<button aria-expanded="false" aria-controls="menu">Menu</button>

Rôles de repère

Les rôles de repère aident les utilisateurs de lecteur d'écran à naviguer. La plupart des éléments sémantiques ont des rôles implicites. Ajoutez des rôles explicites seulement quand nécessaire. role="search" sur un formulaire crée un repère de recherche. Évitez la redondance de rôle avec les éléments sémantiques.

html
<header role="banner">...</header>
<nav role="navigation">...</nav>
<main role="main">...</main>
<aside role="complementary">...</aside>
<footer role="contentinfo">...</footer>
<form role="search">...</form>

Gestion du focus

Gérez le focus pour les utilisateurs clavier. À l'ouverture de modales, déplacez le focus à l'intérieur. À la fermeture, retournez le focus au déclencheur. Utilisez tabindex="-1" pour rendre les éléments focalisables par programme. Ne supprimez jamais les contours de focus sans remplacement.

html
<button id="open">Open</button>
<div id="modal" hidden>
  <button id="close">Close</button>
</div>
<script>
document.getElementById('open').onclick = () => {
  modal.hidden = false;
  document.getElementById('close').focus();
};
</script>

Liens de saut

Les liens de saut laisse les utilisateurs clavier contourner la navigation répétitive. Caché visuellement jusqu'au focus. Le href pointe vers l'ID du contenu principal. Essentiel pour la conformité d'accessibilité (WCAG). Améliore l'efficacité de navigation.

html
<body>
  <a href="#main" class="skip-link">Skip to main content</a>
  <nav>...long navigation...</nav>
  <main id="main">...</main>
</body>
<style>
.skip-link { position: absolute; left: -9999px; }
.skip-link:focus { left: 0; }
</style>

Texte alt

Le texte alt décrit les images pour les lecteurs d'écran. alt="" vide marque les images décoratives (ignorées). Décrivez le contenu et le but, pas l'apparence. Pour les images complexes, fournissez une description plus longue ailleurs. N'utilisez jamais alt pour les infobulles (utilisez title).

html
<!-- Informative image -->
<img src="chart.png" alt="Bar chart showing 30% increase in sales">
<!-- Decorative image -->
<img src="spacer.gif" alt="">
<!-- Complex image -->
<img src="diagram.png" alt="Network topology" longdesc="diagram-desc.html">
27

Pièges courants

Texte alt manquant

Le texte alt manquant casse l'accessibilité. Les lecteurs d'écran lisent le nom de fichier. « image » ou « photo » sont inutiles. Décrivez le contenu et le but. alt="" vide marque les images décoratives. Ne sautez jamais l'attribut alt entièrement.

html
<!-- BAD: no alt -->
<img src="photo.jpg">
<!-- BAD: unhelpful alt -->
<img src="photo.jpg" alt="image">
<!-- GOOD: descriptive alt -->
<img src="photo.jpg" alt="Team meeting in conference room">
<!-- Decorative: empty alt -->
<img src="border.png" alt="">

Soupe de div

Utiliser des divs pour tout supprime la signification sémantique. Les lecteurs d'écran ne peuvent pas naviguer. Le SEO ne peut pas comprendre la structure du contenu. Utilisez des éléments sémantiques : header, nav, main, article, section, aside, footer. Réservez div au regroupement sans intention sémantique.

html
<!-- BAD: div for everything -->
<div class="header">...</div>
<div class="nav">...</div>
<div class="article">...</div>
<!-- GOOD: semantic elements -->
<header>...</header>
<nav>...</nav>
<article>...</article>

Styles en ligne

Les styles en ligne mélangent contenu et présentation, rendant la maintenance difficile. Ils ont une haute spécificité, surchargeant les feuilles de style. Ne peuvent pas être mis en cache ou réutilisés. Utilisez des classes et des feuilles de style externes. Réservez les styles en ligne aux valeurs dynamiques.

html
<!-- BAD: inline styles -->
<div style="color: red; font-size: 16px;">Text</div>
<!-- GOOD: external CSS -->
<div class="error">Text</div>
<link rel="stylesheet" href="styles.css">

Bouton vs lien

Les boutons déclenchent des actions (sauvegarder, supprimer, basculer). Les liens naviguent vers des URLs. Utiliser des liens pour des actions casse la navigation clavier (Space vs Enter) et la sémantique. Les lecteurs d'écran les annoncent différemment. Utilisez type="button" pour empêcher la soumission de formulaire.

html
<!-- BAD: link for actions -->
<a href="#" onclick="save()">Save</a>
<!-- GOOD: button for actions -->
<button type="button" onclick="save()">Save</button>
<!-- Link for navigation -->
<a href="/about">About</a>

Hiérarchie des titres

Les titres créent un plan du document. Ne sautez pas de niveaux (h1 à h3). Utilisez un h1 par page (titre principal). Les utilisateurs de lecteur d'écran naviguent par titres. Maintenez une hiérarchie logique. Utilisez CSS pour le style visuel, pas les niveaux de titre.

html
<!-- BAD: skip levels -->
<h1>Title</h1>
<h3>Subtitle</h3>  <!-- Skipped h2 -->
<!-- BAD: multiple h1 -->
<h1>Title</h1>
<h1>Another</h1>
<!-- GOOD: hierarchical -->
<h1>Main Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>

Was this helpful?

Learning path

Learn from scratch

Learn this language from the ground up with structured lessons.