Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026

🚀 HTML5 Ultimate – SĂ©mantique, APIs & Performance

Guide complet : Structure sémantique, Formulaires 2.0, Multimédia, Accessibilité et nouvelles APIs.

1.1 Facile

Sémantique & Structure

header, nav, main, article vs section.

SEO A11y
1.2 Facile

SEO & Meta Tags

Viewport, Open Graph (OG), Twitter Cards, Favicons modernes.

<head> Social
1.3 Moyen

Accessibilité (ARIA)

Attributs aria-*, role et bonnes pratiques clavier.

WAI-ARIA Focus
2.1 Facile

Inputs Modernes

date, color, range, search, tel.

Input Types Mobile
2.2 Moyen

Validation Native

Constraint Validation API. pattern, required, setCustomValidity.

Regex JS Free
2.3 Moyen

Dialog & Popups

L'élément <dialog> natif. Plus besoin de libs JS lourdes.

<dialog> Modals
3.1 Facile

Audio & Vidéo

Codecs, sous-titres (track), contrĂŽles et fallback.

<video> VTT
3.2 Avancé

Images Responsives

MaĂźtriser srcset, sizes et la balise <picture>.

srcset Performance
3.3 Moyen

SVG vs Canvas

Vecteurs (DOM) vs Pixels (JS). Quand utiliser quoi ?

Vector 2D Context
4.1 Avancé

Web Components

Custom Elements, Shadow DOM et <template>. Intro.

Shadow DOM Vanilla JS
4.2 Avancé

Optimisation Chargement

defer vs async, preload, preconnect, Lazy loading.

Critical Path Core Vitals
5.1 Facile

Cheat-sheet & Boilerplate

Le template HTML5 parfait 2025.

Snippet Copy-Paste
1.1 Sémantique : Structurer le Web (Guide Avancé)
Le Squelette HTML5 Parfait

Oubliez la "Div Soup". Chaque zone a son rÎle précis.

<body>
                            <!-- 1. HEADER GLOBAL -->
                            <header>
                            <!-- Logo, Titre site -->
                            <nav>
                            <!-- Liens majeurs UNIQUEMENT -->
                            <ul><li><a href="/">Accueil</a></li></ul>
                            </nav>
                            </header>

                            <!-- 2. CONTENU PRINCIPAL (Unique par page) -->
                            <main>
                            <h1>Titre de la page</h1> <!-- Le H1 est souvent ici -->

                            <article>
                            <!-- Contenu autonome -->
                            </article>

                            <aside>
                            <!-- Sidebar : Lié au contenu mais non critique -->
                            <div class="ad">Pub</div>
                            </aside>
                            </main>

                            <!-- 3. FOOTER GLOBAL -->
                            <footer>
                            <small>© 2025</small>
                            </footer>
                            </body>
RĂšgles d'Or
  • <main> : Une seule fois par page. Ne doit pas contenir la navigation globale, le footer global ou la sidebar de site.
  • <nav> : RĂ©servĂ© aux blocs de navigation majeurs (Menu principal, Table des matiĂšres, Pagination). Ne pas utiliser pour une petite liste de liens en footer.
  • <aside> : Contenu "tangentiel". Si on le supprime, l'article principal doit rester comprĂ©hensible. (Ex: Bio auteur, Pubs, Articles similaires).
  • <header> & <footer> : Peuvent ĂȘtre utilisĂ©s plusieurs fois ! (Ex: Un header de site, et un header dans chaque <article>).

C'est la confusion n°1 des développeurs. Voici comment trancher.

BaliseDéfinitionLe test "RSS / Syndication"
<article>Contenu indépendant et autonome.OUI. Si je prends ce bloc et que je le colle dans un flux RSS ou sur un autre site, a-t-il du sens tout seul ? (Ex: Post de blog, Commentaire produit, Widget Météo).
<section>Regroupement thématique de contenu.NON. C'est juste un chapitre d'un ensemble plus grand. Doit généralement avoir un titre (h2-h6). (Ex: Chapitre "Intro", Bloc "Nos Tarifs").
<div>Conteneur stylistique générique.NON. Utilisé uniquement pour le CSS (Flexbox wrapper, Grid container, couleur de fond). Aucune valeur sémantique.
Exemple imbriqué complexe
<article> <!-- Le post de blog entier -->
                    <h1>L'histoire du Web</h1>

                    <section> <!-- Chapitre 1 -->
                    <h2>Les débuts</h2>
                    <p>...</p>
                    </section>

                    <section id="comments"> <!-- Zone des commentaires -->
                    <h2>Commentaires</h2>
                    <article> <!-- Commentaire individuel (Autonome !) -->
                    <h3>Jean a dit :</h3>
                    <p>Super article !</p>
                    </article>
                    </section>
                    </article>
Pourquoi Google aime la sémantique ?

Les robots d'indexation ne "voient" pas votre site, ils lisent le code.

  • PondĂ©ration : Les mots-clĂ©s dans un <main> ou un <h1> ont plus de poids que dans un <div> ou un footer.
  • Structure : Google comprend mieux la hiĂ©rarchie de l'information (Titre > Intro > Chapitre).
  • Rich Snippets : Une structure claire aide Ă  gĂ©nĂ©rer des "Sitelinks" ou des extraits enrichis dans les rĂ©sultats de recherche.
Accessibilité (A11y) & Landmarks

Pour les utilisateurs aveugles utilisant des lecteurs d'écran (NVDA, VoiceOver) :

  • Navigation rapide : L'utilisateur peut appuyer sur une touche pour sauter directement au <main> (raccourci "D" ou "M"), ignorant ainsi le menu rĂ©pĂ©titif.
  • Div Soup = Enfer : Si tout est une <div>, l'utilisateur doit Ă©couter tout le code sĂ©quentiellement sans pouvoir "scanner" la page.
<!-- MAUVAIS (Div Soup) --> <div id="header">...</div> <div id="nav">...</div> <!-- BON (Roles implicites) --> <header>...</header> <!-- Role banner --> <nav>...</nav> <!-- Role navigation -->
1.2 SEO Technique & Meta Tags (Guide 2025)
Les Indispensables
<head>
                            <meta charset="UTF-8">
                            <meta name="viewport" content="width=device-width, initial-scale=1.0">

                            <!-- Titre : 50-60 caractÚres max (mot-clé au début) -->
                            <title>Formation HTML5 Avancée | Ideo-Lab</title>

                            <!-- Description : 150-160 chars. C'est votre "Pub" dans Google -->
                            <meta name="description" content="Maßtrisez le HTML5 moderne : Sémantique, SEO technique et APIs...">

                            <!-- Canonical : Évite le 'Duplicate Content' -->
                            <link rel="canonical" href="https://site.com/url-propre">
                            </head>
ContrĂŽle des Robots

Dites Ă  Google quoi faire de cette page.

<!-- Standard (Indexable + Suivre les liens) -->
                            <meta name="robots" content="index, follow">

                            <!-- Page Privée / Admin (Ne pas indexer) -->
                            <meta name="robots" content="noindex, nofollow">

                            <!-- Indexer mais ne pas afficher le cache -->
                            <meta name="robots" content="noarchive">

Astuce : La balise canonical est cruciale si votre site est accessible via plusieurs URLs (ex: avec ou sans paramĂštres `?ref=...`).

Transformez vos liens partagés sur WhatsApp, Slack, LinkedIn et Twitter en cartes riches.

Open Graph (Facebook, LinkedIn, Discord)
<!-- Type de contenu -->
                            <meta property="og:type" content="website">

                            <!-- URL Canonique du partage -->
                            <meta property="og:url" content="https://monsite.com/">

                            <!-- Titre (Peut ĂȘtre diffĂ©rent du <title>) -->
                            <meta property="og:title" content="Guide Ultime HTML5">

                            <!-- Description -->
                            <meta property="og:description" content="Découvrez...">

                            <!-- IMAGE : Le plus important (1200x630 px recommandé) -->
                            <meta property="og:image" content="https://monsite.com/og.jpg">
                            <meta property="og:image:width" content="1200">
                            <meta property="og:image:height" content="630">
Twitter Cards (X)
<!-- Grande image (impact visuel max) -->
                            <meta name="twitter:card" content="summary_large_image">

                            <!-- Compte du site -->
                            <meta name="twitter:site" content="@ideo_lab">

                            <!-- Compte de l'auteur -->
                            <meta name="twitter:creator" content="@dev_name">

                            <!-- Titre (Fallback sur OG si absent) -->
                            <meta name="twitter:title" content="Guide HTML5">

Testez vos cartes :
Usez du Twitter Card Validator ou du LinkedIn Post Inspector.

Favicons 2025 & UI Mobile

Ne chargez plus 15 fichiers `.png`. Le format SVG est supporté et permet le Dark Mode.

BaliseUsage
icon (svg)Navigateurs modernes. Léger, vectoriel.
apple-touch-iconIcÎne sur l'écran d'accueil iOS (iPhone/iPad). 180x180px.
theme-colorColore la barre d'adresse du navigateur mobile (Chrome/Safari).
<!-- 1. Favicon SVG (Moderne) -->
                    <link rel="icon" type="image/svg+xml" href="/favicon.svg">

                    <!-- 2. Favicon ICO (Fallback Legacy) -->
                    <link rel="alternate icon" href="/favicon.ico">

                    <!-- 3. iOS Home Screen (Pas de transparence !) -->
                    <link rel="apple-touch-icon" href="/apple-touch-icon.png">

                    <!-- 4. Couleur du navigateur (Barre d'adresse) -->
                    <meta name="theme-color" content="#234A26">
                    <!-- On peut mĂȘme changer la couleur selon le Dark Mode -->
                    <meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
                    <meta name="theme-color" content="#0f172a" media="(prefers-color-scheme: dark)">

                    <!-- 5. Web App Manifest (PWA) -->
                    <link rel="manifest" href="/site.webmanifest">
1.3 Accessibilité (A11y) & WAI-ARIA
Gestion du Focus (Tabindex)

Tout Ă©lĂ©ment interactif DOIT ĂȘtre atteignable via la touche Tab.

ValeurComportementUsage
0IntÚgre l'élément dans le flux naturel de tabulation.Rendre une div ou un span focusable.
-1Focusable via JS (el.focus()) mais pas via Tab.Modales, messages d'erreur, widgets complexes.
1+Anti-pattern. Force un ordre illogique.A bannir. Suivez l'ordre du DOM.
Styles de Focus (Outline)

Ne supprimez jamais l'outline sans le remplacer. C'est le seul repĂšre pour la navigation clavier.

/* ❌ A NE JAMAIS FAIRE SEUL */
                            *:focus { outline: none; }

                            /* ✅ La bonne mĂ©thode : :focus-visible */
                            /* S'active seulement au clavier, pas au clic souris */
                            button:focus-visible {
                            outline: 2px solid #38bdf8;
                            outline-offset: 2px;
                            }
L'ordre logique (DOM)

L'ordre visuel (CSS Flex/Grid order) doit correspondre à l'ordre du DOM HTML, sinon le focus saute de maniÚre imprévisible.

Nommer les éléments (Labels)

Indispensable pour les boutons icĂŽnes (sans texte) ou les inputs sans label visible.

<!-- Label invisible (Lu par le Screen Reader) -->
                            <button aria-label="Fermer le menu">
                            <i class="fa fa-times"></i>
                            </button>

                            <!-- Référence un autre élément (TrÚs puissant) -->
                            <h2 id="modal-title">Supprimer ?</h2>
                            <div role="dialog" aria-labelledby="modal-title">
                            ...
                            </div>
États Dynamiques (Pour le JS)

HTML5 ne suffit pas pour les widgets JS (Accordéons, Modales, Menus).

  • aria-expanded="true/false" : Pour les menus dĂ©roulants ou accordĂ©ons. Indique si la zone est ouverte.
  • aria-hidden="true" : Cache un Ă©lĂ©ment aux lecteurs d'Ă©cran (ex: icĂŽne dĂ©corative) tout en le laissant visible.
  • aria-live="polite" : Pour les notifications (Toasts). Le lecteur d'Ă©cran lira le message dĂšs qu'il apparaĂźt, sans couper l'utilisateur.
RÚgle N°1 de l'ARIA
"Si vous pouvez utiliser un élément HTML natif (button, a, input) qui possÚde déjà la sémantique et le comportement clavier, N'UTILISEZ PAS ARIA."
Mauvais Pattern (Div Button)
<!-- ❌ Mauvais -->
                            <!-- Pas de focus, pas d'activation "Entrée/Espace" -->
                            <div onclick="save()">Sauver</div>

                            <!-- ⚠ "RĂ©parĂ©" avec ARIA (Trop lourd) -->
                            <div role="button" tabindex="0" 
                            onkeydown="if(event.key==='Enter') save()" 
                            onclick="save()">
                            Sauver
                            </div>
Bon Pattern (Natif)
<!-- ✅ Parfait -->
                            <!-- Focus, Click, Entrée et Espace gérés nativement -->
                            <button onclick="save()">Sauver</button>
Quand utiliser role="..." ?
  • role="alert" : Message d'erreur critique.
  • role="dialog" : FenĂȘtre modale (empĂȘche de sortir).
  • role="tablist" / "tab" : SystĂšme d'onglets complexe.
2.1 Formulaires : La Bible des Input Types
Types & Claviers Virtuels (iOS/Android)

Choisir le bon type ne sert pas qu'Ă  la validation, cela adapte le clavier du smartphone.

TypeClavier AffichéUsage
emailTouche @ et . accessibles.Emails.
telPavé numérique (0-9, *, #).Téléphones, codes PIN.
urlTouche .com ou /.Sites web.
searchTouche "Rechercher" (Go) + Croix "Clear".Barres de recherche.
L'attribut inputmode (Le Secret)

Parfois, type="number" est mauvais (flÚches de scroll, validation stricte). Utilisez inputmode pour forcer le pavé numérique tout en gardant un champ texte libre.

<!-- Code Carte Bleue (Pas de flĂšches up/down) -->
                            <input type="text" inputmode="numeric" pattern="[0-9]*" placeholder="0000 0000...">

                            <!-- Montant avec décimales -->
                            <input type="text" inputmode="decimal" placeholder="10.50">

                            <!-- Code 2FA (One Time Password) -->
                            <input type="text" autocomplete="one-time-code" inputmode="numeric">
UX Clavier (EnterKeyHint)
<!-- Change le label de la touche "Entrée" sur mobile -->
                            <input type="text" enterkeyhint="send"> <!-- "Envoyer" -->
                            <input type="search" enterkeyhint="search"> <!-- "Rechercher" -->
Date & Heure (Natif)

Plus besoin de lourdes bibliothÚques JS (Datepicker). L'interface dépend du navigateur/OS.

<!-- Date seule (JJ/MM/AAAA) -->
                            <input type="date" min="2025-01-01" max="2025-12-31">

                            <!-- Date et Heure -->
                            <input type="datetime-local">

                            <!-- Mois seulement -->
                            <input type="month">

                            <!-- Heure -->
                            <input type="time">
Couleurs
<label>Couleur du produit</label>
                            <input type="color" value="#ff0000">
Fichiers & Caméra (Mobile)

Astuce pour ouvrir la caméra directement sur mobile.

<!-- Classique (Multiples) -->
                            <input type="file" multiple accept=".pdf,.docx">

                            <!-- Images uniquement -->
                            <input type="file" accept="image/*">

                            <!-- Ouvrir Caméra (Selfie) -->
                            <input type="file" accept="image/*" capture="user">

                            <!-- Ouvrir Caméra (ArriÚre / Environnement) -->
                            <input type="file" accept="image/*" capture="environment">
Sliders (Range)
<input type="range" min="0" max="10" step="0.5" 
                            oninput="this.nextElementSibling.value = this.value">
                            <output>5</output>
Autocomplete (Vital pour l'UX)

Aide le navigateur (Chrome/Safari) à pré-remplir les champs correctement.

<!-- Login -->
                            <input type="text" autocomplete="username">
                            <input type="password" autocomplete="current-password">

                            <!-- Inscription / Change Password -->
                            <input type="password" autocomplete="new-password">

                            <!-- Carte Bancaire -->
                            <input type="text" autocomplete="cc-number">
                            <input type="text" autocomplete="cc-exp">
                            <input type="text" autocomplete="cc-csc">
Datalist (L'auto-complétion native)

Un hybride entre un <select> et un <input>. Permet de choisir une valeur prédéfinie OU d'en écrire une nouvelle.

<label>Votre navigateur préféré ?</label>
                            <input list="browsers" name="browser">

                            <datalist id="browsers">
                            <option value="Chrome">
                            <option value="Firefox">
                            <option value="Safari">
                            <option value="Opera">
                            <option value="Edge">
                            </datalist>
Hidden (Sécurité)
<!-- Souvent utilisé pour les tokens CSRF ou ID -->
                            <input type="hidden" name="user_id" value="42">
2.2 Validation Native (Constraint Validation API)
Attributs de base

Le navigateur bloque la soumission et affiche une bulle d'erreur native si ces conditions ne sont pas remplies.

<form>
                            <!-- Présence & Longueur -->
                            <input type="text" required minlength="3" maxlength="20">

                            <!-- Plage numérique -->
                            <input type="number" min="18" max="99" step="1">

                            <!-- Format Email ou URL (Validation auto) -->
                            <input type="email" required>

                            <button>Envoyer</button>
                            </form>
Puissance du Regex (pattern)

L'attribut title est affiché dans la bulle d'erreur si le pattern échoue.

<!-- Code Postal (5 chiffres exacts) -->
                            <input type="text" pattern="[0-9]{5}" 
                            title="Veuillez entrer 5 chiffres">

                            <!-- Username (Lettres, chiffres, tiret, 3-15 chars) -->
                            <input type="text" pattern="[a-zA-Z0-9-]{3,15}">

                            <!-- Mot de passe complexe -->
                            <!-- (?=.*\d) = au moins un chiffre -->
                            <!-- (?=.*[a-z]) = au moins une minuscule -->
                            <input type="password" 
                            pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}" 
                            title="8 chars, 1 maj, 1 min, 1 chiffre">
Le ProblĂšme de l'UX

Si vous utilisez juste :invalid, le champ sera rouge dÚs le chargement de la page (car il est vide et requis). C'est une mauvaise expérience utilisateur.

Solution Moderne : :user-invalid

Ne cible l'erreur que si l'utilisateur a déjà interagi avec le champ.

/* 1. État par dĂ©faut (Pas d'erreur visible) */
                            input { border: 1px solid #ccc; }

                            /* 2. SuccĂšs (Optionnel) */
                            input:valid { border-color: green; }

                            /* 3. Erreur (Seulement aprĂšs interaction) */
                            /* Support: Firefox, Chrome/Edge 119+ */
                            input:user-invalid {
                            border-color: red;
                            background-color: #fff0f0;
                            animation: shake 0.3s;
                            }
Solution Compatibilité (Le "Hack" Placeholder)

Si vous devez supporter de vieux navigateurs.

/* Cible les inputs invalides qui ne montrent PAS 
                            leur placeholder (donc l'user a tapé qqchose) */
                            input:not(:placeholder-shown):invalid {
                            border-color: red;
                            }

                            /* Requis : il faut mettre un placeholder, 
                            mĂȘme vide (espace) */
                            <input required placeholder=" " ...>
Quand le HTML ne suffit plus (Custom Logic)

Exemple classique : "Confirmer le mot de passe". HTML ne peut pas comparer deux champs. Il faut utiliser l'API JS.

<input type="password" id="pwd">
                    <input type="password" id="confirm">

                    <script>
                    const pwd = document.getElementById("pwd");
                    const confirm = document.getElementById("confirm");

                    function validatePassword() {
                    if (pwd.value !== confirm.value) {
                    // 1. Marque le champ comme invalide
                    // 2. Définit le message de la bulle native
                    confirm.setCustomValidity("Les mots de passe ne correspondent pas !");
                    } else {
                    // IMPORTANT : Remettre Ă  vide pour valider le champ
                    confirm.setCustomValidity("");
                    }
                    }

                    pwd.onchange = validatePassword;
                    confirm.onkeyup = validatePassword;
                    </script>
Méthodes Clés
  • checkValidity() : Retourne true/false et dĂ©clenche l'Ă©vĂ©nement `invalid` si faux.
  • reportValidity() : Affiche la bulle d'erreur native (utile si vous faites un formulaire AJAX).
  • setCustomValidity('msg') : Bloque l'envoi du form tant que le message n'est pas vide.
2.3 L'élément <dialog>

ArrĂȘtez d'utiliser des div avec z-index: 9999. HTML5 a maintenant une balise native pour les modales, qui gĂšre le focus trap et la touche Echap nativement.

HTML
<dialog id="myModal">
                        <h2>Confirmation</h2>
                        <p>Voulez-vous supprimer cet élément ?</p>

                        <form method="dialog">
                        <!-- Ce bouton ferme la modal auto sans JS -->
                        <button value="cancel">Annuler</button>
                        <button value="confirm">Oui</button>
                        </form>
                        </dialog>
JavaScript & CSS
const modal = document.getElementById('myModal');

                        // Ouvre en mode "Modal" (bloque le reste de la page)
                        modal.showModal(); 

                        // Ouvre en mode "Non-modal" (popup flottante)
                        // modal.show(); 

                        modal.close(); // Fermeture manuelle
/* Fond sombre derriĂšre la modal */
                        ::backdrop {
                        background: rgba(0, 0, 0, 0.8);
                        }
3.2 Images Responsives (Avancé)
Attribut srcset (Résolution)

Laisse le navigateur choisir la meilleure image selon la largeur d'écran (w) ou la densité de pixels (1x, 2x).

<img src="small.jpg"
                        srcset="small.jpg 500w,
                        medium.jpg 1000w,
                        large.jpg 2000w"
                        sizes="(max-width: 600px) 100vw,
                        50vw"
                        alt="Description">

Traduction : "Si l'écran fait moins de 600px, l'image occupe 100% de largeur. Sinon 50%. Choisis dans `srcset` le fichier le plus léger pour cette taille."

Balise <picture> (Direction Artistique)

Force le changement d'image (ex: recadrage différent sur mobile) ou de format (WebP).

<picture>
                        <!-- Format AVIF (Le plus léger) -->
                        <source srcset="img.avif" type="image/avif">

                        <!-- Format WebP (Standard moderne) -->
                        <source srcset="img.webp" type="image/webp">

                        <!-- Fallback JPG -->
                        <img src="img.jpg" alt="..." loading="lazy">
                        </picture>
4.1 Web Components (Custom Elements)

Créer vos propres balises HTML encapsulées (comme React/Vue, mais natif navigateur).

Définition (JS)
class UserCard extends HTMLElement {
                        constructor() {
                        super();
                        // Shadow DOM (CSS isolé)
                        this.attachShadow({ mode: 'open' }); 
                        }

                        connectedCallback() {
                        this.shadowRoot.innerHTML = `
                        <style>h3 { color: blue; }</style>
                        <div class="card">
                        <h3><slot name="username">Inconnu</slot></h3>
                        <p>Role: Admin</p>
                        </div>
                        `;
                        }
                        }
                        customElements.define('user-card', UserCard);
Utilisation (HTML)
<user-card>
                        <span slot="username">Alice</span>
                        </user-card>

                        <user-card>
                        <span slot="username">Bob</span>
                        </user-card>

Le CSS défini dans le Shadow DOM n'affecte pas le reste de la page, et le CSS de la page n'affecte pas le composant.

4.2 Performance : Critical Rendering Path
MéthodeComportementUsage
<script src="...">Bloque le rendu HTML pendant le tĂ©lĂ©chargement ET l'exĂ©cution.👎 À Ă©viter (sauf bas de page).
asyncTĂ©lĂ©charge en parallĂšle, exĂ©cute dĂšs que prĂȘt (pause le HTML). Ordre non garanti.Analytics, Pubs (scripts indĂ©pendants).
deferTĂ©lĂ©charge en parallĂšle, exĂ©cute aprĂšs le chargement du HTML (DOMContentLoaded).👍 Standard moderne pour vos JS app.
Resource Hints
<!-- Charger une ressource critique (ex: police) en priorité -->
                    <link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

                    <!-- Pré-résoudre un DNS (ex: CDN externe) -->
                    <link rel="preconnect" href="https://api.monsite.com">
Lazy Loading Natif

Ne charge l'image/iframe que quand l'utilisateur scrolle dessus.

<img src="lourd.jpg" loading="lazy" alt="..." width="800" height="600">
                    <iframe src="..." loading="lazy"></iframe>

Attention : Ne jamais mettre loading="lazy" sur l'image tout en haut de la page (LCP), sinon le site paraĂźt lent.

5.1 HTML5 Ultimate Boilerplate
<!DOCTYPE html>
                <html lang="fr">
                <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <title>Titre Page</title>
                <meta name="description" content="Description SEO">

                <!-- Favicons -->
                <link rel="icon" type="image/svg+xml" href="/favicon.svg">

                <!-- Styles -->
                <link rel="stylesheet" href="style.css">

                <!-- Scripts (Non-bloquant) -->
                <script src="app.js" defer></script>
                </head>
                <body>
                <header>
                <nav>
                <ul><li><a href="/">Accueil</a></li></ul>
                </nav>
                </header>

                <main>
                <h1>Titre Principal (H1)</h1>

                <section>
                <h2>Section Thématique</h2>
                <p>Contenu...</p>
                <img src="img.jpg" alt="Description" loading="lazy">
                </section>
                </main>

                <footer>
                <p>© 2025 Mon Site</p>
                </footer>
                </body>
                </html>