Développement web : HTML, CSS et JavaScript
Quitter

Leçon 2 sur 17 · HTML et CSS

HTML : structure d'une page, balises sémantiques, liens et images

45 min Node.js 22 (Debian, git, npm, python3)

Objectif

Écrire à la main une page HTML valide et bien structurée : le squelette obligatoire, les titres et paragraphes, les listes, les grandes zones sémantiques (header, nav, main, footer), les liens et les images. À la fin, vous aurez la page d'accueil et la page « Nos chambres » du Riad Yasmine à Marrakech.

L'essentiel

  • HTML décrit le contenu et son sens (« ceci est un titre », « ceci est un menu »), pas son apparence : l'apparence, c'est le CSS.
  • Un élément = balise ouvrante + contenu + balise fermante : <p>Bonjour</p>. Les attributs précisent l'élément : <a href="chambres.html">.
  • Toute page commence par <!doctype html>, puis <html lang="fr">, un <head> (informations sur la page) et un <body> (ce qui s'affiche).
  • Les balises sémantiques (header, nav, main, article, section, aside, footer) aident les lecteurs d'écran et les moteurs de recherche.
  • Un seul h1 par page, puis des h2, h3… dans l'ordre, sans sauter de niveau.
  • Toute image porte un attribut alt qui décrit ce qu'elle montre.

1. Anatomie d'un élément

<a href="chambres.html" title="Voir les chambres">Nos chambres</a>
<!-- └ balise ouvrante avec deux attributs ┘└ contenu ┘└ fermante ┘ -->
  • Les attributs s'écrivent nom="valeur" dans la balise ouvrante, séparés par des espaces.
  • Les éléments s'imbriquent comme des poupées russes, et se ferment dans l'ordre inverse : <p>Un <strong>prix</strong> imbattable</p> est correct, <p>Un <strong>prix</p></strong> ne l'est pas.
  • Certains éléments sont vides (pas de contenu, pas de balise fermante) : <img>, <br>, <meta>, <link>, <input>, <hr>.
  • <!-- ... --> est un commentaire : visible dans le code source, jamais à l'écran.
  • HTML ignore les espaces et retours à la ligne multiples : indentez votre code pour vous, pas pour le navigateur.

2. Le squelette d'une page

<!doctype html>
<html lang="fr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="Riad de charme dans la médina de Marrakech, six chambres, patio et terrasse.">
  <title>Riad Yasmine — Maison d'hôtes à Marrakech</title>
  <link rel="stylesheet" href="style.css">
  <link rel="icon" href="favicon.png">
</head>
<body>
  <!-- tout ce qui s'affiche -->
</body>
</html>
Ligne Rôle
<!doctype html> « ceci est du HTML moderne » ; sans lui, le navigateur passe en mode de compatibilité
lang="fr" langue de la page : prononciation des lecteurs d'écran, traduction, référencement. Pour une page en arabe : lang="ar" dir="rtl"
<meta charset="utf-8"> l'encodage : sans lui, « Fès » et « مرحبا » s'affichent en caractères bizarres
viewport indispensable pour un affichage correct sur téléphone (leçon 1.6)
description le résumé affiché sous le titre dans les résultats de recherche
<title> le texte de l'onglet et du lien dans Google : précis et unique pour chaque page
<link rel="stylesheet"> relie la feuille de style CSS

Le <head> ne s'affiche pas : il contient des métadonnées, des informations sur la page.

3. Titres, paragraphes, mise en valeur

<h1>Riad Yasmine</h1>
<p>Une maison d'hôtes de six chambres, à cinq minutes de la place Jemaa el-Fna.</p>

<h2>Le riad</h2>
<p>Construit au <strong>XVIIIᵉ siècle</strong>, entièrement restauré en 2023.</p>

<h2>Les services</h2>
<h3>Petit-déjeuner</h3>
<p>Msemen, baghrir, amlou et jus d'orange pressé, <em>servis sur la terrasse</em>.</p>
<h3>Hammam</h3>
<p>Sur réservation, la veille.</p>
  • h1 à h6 forment le plan de la page. Un lecteur d'écran permet de sauter de titre en titre : c'est leur vraie raison d'être. Ne choisissez jamais un titre pour sa taille (la taille se règle en CSS).
  • <p> : un paragraphe. Pour un simple retour à la ligne dans une adresse, <br> ; pour séparer des idées, un nouveau <p>.
  • <strong> : importance (affiché en gras par défaut) ; <em> : emphase (italique). Ce sont des balises de sens ; <b> et <i> ne portent qu'un style.

4. Les listes

<ul>                         <!-- liste à puces : l'ordre n'a pas d'importance -->
  <li>Wi-Fi gratuit</li>
  <li>Terrasse avec vue sur l'Atlas</li>
  <li>Navette depuis l'aéroport Marrakech-Ménara</li>
</ul>

<ol>                         <!-- liste numérotée : l'ordre compte -->
  <li>Choisissez vos dates</li>
  <li>Choisissez votre chambre</li>
  <li>Confirmez par e-mail</li>
</ol>

<dl>                         <!-- liste de définitions : terme / description -->
  <dt>Arrivée</dt><dd>à partir de 14 h</dd>
  <dt>Départ</dt><dd>avant 11 h</dd>
</dl>

Un menu de navigation est, au fond, une liste de liens : beaucoup de sites l'écrivent <nav><ul><li><a …></a></li>…</ul></nav>.

5. Les balises sémantiques de structure

Avant HTML5, tout était fait de <div> anonymes. Aujourd'hui, on nomme les zones :

<body>
  <header>                       <!-- en-tête du site : logo, nom, menu -->
    <h1>Riad Yasmine</h1>
    <nav>                        <!-- menu de navigation principal -->
      <a href="index.html">Accueil</a>
      <a href="chambres.html">Chambres</a>
      <a href="#contact">Contact</a>
    </nav>
  </header>

  <main>                         <!-- LE contenu principal (un seul par page) -->
    <section>                    <!-- une partie thématique, avec son titre -->
      <h2>Le riad</h2> …
    </section>
    <article>                    <!-- un contenu autonome : avis, article de blog -->
      <h2>« Un séjour inoubliable »</h2>
      <p>Accueil chaleureux, chambre impeccable. — Sophie, Lyon</p>
    </article>
    <aside>                      <!-- contenu annexe : encadré, liens connexes -->
      <p>Offre : -15 % pour 5 nuits et plus.</p>
    </aside>
  </main>

  <footer>                       <!-- pied de page : adresse, mentions -->
    <p>Derb Sidi Bouloukat, Marrakech</p>
  </footer>
</body>
Balise Quand l'utiliser
header introduction d'une page ou d'une section
nav un bloc de liens de navigation important (pas chaque lien)
main le contenu propre à la page, une seule fois
section une partie thématique qui a un titre
article un contenu qui aurait du sens seul (un avis, une fiche produit)
aside un contenu secondaire
footer pied de page ou de section
div un conteneur sans sens, uniquement pour la mise en forme

Pourquoi c'est important : un lecteur d'écran annonce « navigation », « contenu principal » et permet d'y aller directement ; Google comprend mieux votre page ; et votre CSS est plus lisible.

6. Les liens

<!-- Lien absolu : vers un autre site -->
<a href="https://www.visitmorocco.com/fr">Office national marocain du tourisme</a>

<!-- Liens relatifs : vers une page du même site -->
<a href="chambres.html">Nos chambres</a>          <!-- même dossier -->
<a href="chambres/suite-atlas.html">Suite Atlas</a> <!-- sous-dossier -->
<a href="../index.html">Accueil</a>               <!-- dossier parent -->
<a href="/tarifs.html">Tarifs</a>                 <!-- depuis la racine du site -->

<!-- Ancre : vers un endroit de la page -->
<a href="#contact">Nous contacter</a>
<section id="contact"> … </section>

<!-- Courriel -->
<a href="mailto:contact@riad-yasmine.ma">contact@riad-yasmine.ma</a>

<!-- Ouvrir dans un nouvel onglet : à réserver aux liens externes -->
<a href="https://maps.example.com/riad" target="_blank" rel="noopener">Plan d'accès</a>

Règles de qualité :

  • le texte du lien doit dire où il mène : « Voir nos chambres » plutôt que « cliquez ici » (les lecteurs d'écran listent les liens hors contexte) ;
  • préférez les liens relatifs à l'intérieur de votre site : il continuera de fonctionner en local, en test et en production ;
  • un id doit être unique dans la page.

7. Les images

<img src="images/patio.jpg"
     alt="Le patio du riad et sa fontaine en zellige vert"
     width="800" height="533">
  • src : le chemin de l'image (mêmes règles que les liens) ;
  • alt : le texte alternatif, lu par les lecteurs d'écran et affiché si l'image ne charge pas. Décrivez ce que l'image apporte. Pour une image purement décorative : alt="" (vide, mais présent) ;
  • width et height : les dimensions réelles en pixels. Le navigateur réserve la place avant le chargement, la page ne « saute » pas (leçon 4.2).

Image avec légende :

<figure>
  <img src="images/terrasse.webp" alt="Terrasse au coucher du soleil, vue sur la Koutoubia" width="1200" height="800">
  <figcaption>La terrasse, où le thé est servi à 17 h.</figcaption>
</figure>

Formats à connaître : JPEG (photos), PNG (logos, transparence), WebP / AVIF (photos plus légères, à privilégier), SVG (dessins vectoriels, icônes : nets à toutes les tailles).

8. Caractères spéciaux et validation

Quelques caractères ont un sens en HTML ; pour les afficher, on utilise des entités :

Caractère Entité
< &lt;
> &gt;
& &amp;
" &quot;
espace insécable (1 200 DH sur une seule ligne) &nbsp;

Grâce à utf-8, les accents et l'arabe s'écrivent directement, sans entité.

Pour vérifier une page, le validateur du W3C (validator.w3.org) signale balises mal fermées, attributs inconnus ou id en double. Le navigateur, lui, « répare » silencieusement les erreurs… à sa façon, différente d'un navigateur à l'autre.

9. Organiser les fichiers d'un site

riad/
├── index.html          ← la page d'accueil (nom attendu par les serveurs web)
├── chambres.html
├── style.css
├── app.js
└── images/
    ├── patio.jpg
    └── terrasse.webp

Conseils : noms de fichiers en minuscules, sans espaces ni accents (suite-atlas.html, pas Suite Atlas.html) ; un serveur Linux distingue Patio.jpg de patio.jpg, alors que Windows ne le fait pas : c'est la première cause d'images cassées après une mise en ligne.

Pièges fréquents

  • Oublier <meta charset="utf-8"> : les accents s'affichent mal dès la mise en ligne.
  • Choisir un titre pour sa taille (h4 parce qu'il est « plus petit ») : le plan de la page devient incohérent. Gardez l'ordre logique et réglez la taille en CSS.
  • Images sans alt ou avec alt="image" : inutile pour un aveugle et mauvais pour le référencement.
  • Tout faire en <div> : la page fonctionne, mais elle est muette pour les lecteurs d'écran et les moteurs de recherche.

Lab

Vous allez construire, pas à pas, deux pages du Riad Yasmine dans /root/riad :

  1. le squelette de index.html ;
  2. sa structure sémantique, avec un seul h1 ;
  3. le menu (liens relatifs et ancre) et la section contact ;
  4. une image avec texte alternatif et dimensions ;
  5. la page chambres.html avec une liste et un lien de retour.

Pour écrire un fichier, le plus simple est cat > /root/riad/index.html <<'EOF', puis le contenu, puis une ligne EOF. Relisez votre fichier avec cat.

Quiz

  1. Quelles sont les trois lignes qui doivent figurer dans le <head> de toute page ?
  2. Quelle différence entre <section> et <div> ?
  3. Écrivez un lien vers la page tarifs.html située dans le dossier parent.
  4. Que mettre dans l'attribut alt d'une image purement décorative ?
  5. Pourquoi faut-il indiquer width et height sur une image ?
Réponses
  1. <meta charset="utf-8">, <meta name="viewport" content="width=device-width, initial-scale=1"> et <title>…</title>.
  2. <section> a un sens (une partie thématique, avec un titre) ; <div> n'en a aucun et ne sert qu'à regrouper pour la mise en forme.
  3. <a href="../tarifs.html">Nos tarifs</a>.
  4. Un texte vide, alt="" : l'attribut est présent, et le lecteur d'écran ignore l'image.
  5. Pour que le navigateur réserve la place de l'image avant son chargement : la page ne se décale pas pendant l'affichage.

Sources de référence : MDN Web Docs en français (licence CC BY-SA 2.5). Texte original MasterLinux.

Exercices pratiques

À réaliser sur Node.js 22 (Debian, git, npm, python3)

Le terminal en ligne ouvre bientôt. En attendant, réalisez ces tâches sur votre machine Linux, une machine virtuelle ou WSL.

  1. Créez /root/riad/index.html avec le squelette complet d'une page : doctype HTML5, élément html en français (lang="fr"), un head contenant le jeu de caractères utf-8 et un titre qui contient « Riad Yasmine », puis un body.
    Afficher un indiceUtilisez cat > /root/riad/index.html <<'EOF' … EOF, ou printf avec une ligne par argument.
    Voir la solution
    printf '%s\n' '<!doctype html>' '<html lang="fr">' '<head>' '  <meta charset="utf-8">' '  <title>Riad Yasmine — Marrakech</title>' '</head>' '<body>' '  <p>Site en construction</p>' '</body>' '</html>' > /root/riad/index.html

    Vérification : grep -qi '<!doctype html>' /root/riad/index.html && grep -q '<html lang="fr"' /root/riad/index.html && grep -qi '<meta charset="utf-8"' /root/riad/index.html && grep -q '<title>[^<]*Riad Yasmine[^<]*</title>' /root/riad/index.html && grep -q '<body' /root/riad/index.html

  2. Structurez le body de /root/riad/index.html avec les balises sémantiques header, nav, main et footer. La page doit contenir UN SEUL titre h1 (le nom du riad).
    Afficher un indiceheader contient le h1 ; nav viendra accueillir le menu ; main le contenu principal ; footer l'adresse.
    Voir la solution
    printf '%s\n' '<!doctype html>' '<html lang="fr">' '<head>' '  <meta charset="utf-8">' '  <title>Riad Yasmine — Marrakech</title>' '</head>' '<body>' '  <header>' '    <h1>Riad Yasmine</h1>' '    <nav></nav>' '  </header>' '  <main>' '    <p>Un riad de six chambres au cœur de la médina.</p>' '  </main>' '  <footer>' '    <p>Derb Sidi Bouloukat, Marrakech</p>' '  </footer>' '</body>' '</html>' > /root/riad/index.html

    Vérification : f=/root/riad/index.html; for b in header nav main footer; do grep -q "<$b" $f || exit 1; done; test "$(grep -o "<h1" $f | wc -l)" -eq 1

  3. Dans le nav, ajoutez un lien relatif vers chambres.html et un lien vers l'ancre #contact. Dans main, ajoutez une section dont l'identifiant est contact (id="contact") avec un titre h2.
    Afficher un indice<a href="chambres.html">Chambres</a> et <section id="contact"><h2>Contact</h2>…</section>
    Voir la solution
    printf '%s\n' '<!doctype html>' '<html lang="fr">' '<head>' '  <meta charset="utf-8">' '  <title>Riad Yasmine — Marrakech</title>' '</head>' '<body>' '  <header>' '    <h1>Riad Yasmine</h1>' '    <nav>' '      <a href="index.html">Accueil</a>' '      <a href="chambres.html">Chambres</a>' '      <a href="#contact">Contact</a>' '    </nav>' '  </header>' '  <main>' '    <p>Un riad de six chambres au cœur de la médina.</p>' '    <section id="contact">' '      <h2>Contact</h2>' '      <p>Écrivez-nous : <a href="mailto:contact@riad-yasmine.ma">contact@riad-yasmine.ma</a></p>' '    </section>' '  </main>' '  <footer>' '    <p>Derb Sidi Bouloukat, Marrakech</p>' '  </footer>' '</body>' '</html>' > /root/riad/index.html

    Vérification : f=/root/riad/index.html; grep -q 'href="chambres.html"' $f && grep -q 'href="#contact"' $f && grep -q 'id="contact"' $f && grep -q '<h2' $f

  4. Dans main, ajoutez l'image images/patio.jpg avec un texte alternatif (alt) qui décrit vraiment l'image, ainsi que ses dimensions (width et height).
    Afficher un indice<img src="images/patio.jpg" alt="Le patio et sa fontaine en zellige" width="800" height="533">
    Voir la solution
    sed -i 's#<p>Un riad de six chambres au cœur de la médina.</p>#&\n    <img src="images/patio.jpg" alt="Le patio du riad et sa fontaine en zellige vert" width="800" height="533">#' /root/riad/index.html

    Vérification : grep -o '<img[^>]*>' /root/riad/index.html | grep 'images/patio.jpg' | grep 'width=' | grep 'height=' | grep -Eq 'alt="[^"]+"'

  5. Créez /root/riad/chambres.html (même squelette, lang="fr") : un h1 « Nos chambres », une liste à puces d'au moins trois chambres et un lien de retour vers index.html.
    Afficher un indice<ul> <li>Suite Atlas</li> <li>Chambre Majorelle</li> <li>Chambre Ourika</li> </ul>
    Voir la solution
    printf '%s\n' '<!doctype html>' '<html lang="fr">' '<head>' '  <meta charset="utf-8">' '  <title>Nos chambres — Riad Yasmine</title>' '</head>' '<body>' '  <h1>Nos chambres</h1>' '  <ul>' '    <li>Suite Atlas — 1 200 DH la nuit</li>' '    <li>Chambre Majorelle — 900 DH la nuit</li>' '    <li>Chambre Ourika — 750 DH la nuit</li>' '  </ul>' '  <p><a href="index.html">Retour à l’accueil</a></p>' '</body>' '</html>' > /root/riad/chambres.html

    Vérification : f=/root/riad/chambres.html; grep -q '<html lang="fr"' $f && grep -q '<h1>Nos chambres</h1>' $f && grep -q '<ul' $f && test "$(grep -o '<li' $f | wc -l)" -ge 3 && grep -q 'href="index.html"' $f

Références officielles consultées : Syntaxe de base du HTML — https://developer.mozilla.org/fr/docs/Learn_web_development/Core/Structuring_content/Basic_HTML_syntax ; Qu'y a-t-il dans l'en-tête ? Métadonnées d'une page Web — https://developer.mozilla.org/fr/docs/Learn_web_development/Core/Structuring_content/Webpage_metadata ; Structurer des documents — https://developer.mozilla.org/fr/docs/Learn_web_development/Core/Structuring_content/Structuring_documents ; Création d'hyperliens — https://developer.mozilla.org/fr/docs/Learn_web_development/Core/Structuring_content/Creating_links ; Les images en HTML — https://developer.mozilla.org/fr/docs/Learn_web_development/Core/Structuring_content/HTML_images. Texte original MasterLinux.