Files
stagiaire/PROCHAINE_ETAPE_contact.md
T

18 KiB
Raw Blame History

📬 Page Contact — relecture & prochaine étape

Salut Mélissa ! 👋

Ta page contact prend forme : le tableau de l'équipe est sympa, le formulaire est en place, et le bouton « contact » qui reste enfoncé pour montrer la page courante (.instyled) est une très bonne idée d'ergonomie. Bravo ! 🎉

Ce guide a trois objectifs :

  1. Corriger 4 bugs (avec l'explication, pas juste la solution).
  2. T'apprendre à définir et limiter une <textarea> proprement.
  3. Te lancer sur ta première mission JavaScript 🚀 (dans le thème FleetZen).

🚨 Bug 1 — L'accolade } oubliée (le bug le plus important)

Tu te souviens de la leçon « chaque { a son } » ? Elle te concerne en plein ! 😄 Regarde le tout début de contact.css :

body {
    width: 100%;
    height: 100%;
    background-color: lightblue;
    margin: 0;
    padding-bottom: 60px;
                              /* ❌ il manque le } ICI pour fermer body */
#nav_barre {                  /* du coup le navigateur croit que tout ça est ENCORE dans body */
    display: flex;
    ...

Tu as ouvert body { mais tu ne l'as jamais refermé. Résultat : le navigateur pense que #nav_barre, .styled, .table… sont tous imbriqués dans body, il se perd, et une grande partie de ton CSS est ignorée. C'est pour ça que ta page ne ressemble pas à ce que tu attends.

Correction : ferme body avec un }

body {
    width: 100%;
    height: 100%;
    background-color: lightblue;
    margin: 0;
    padding-bottom: 60px;
}                             /* ✅ on ferme body ici */

#nav_barre {
    display: flex;
    ...
}

💡 À retenir : à chaque { correspond un }. Une accolade oubliée et tout le reste de la feuille de style casse. Astuce : la plupart des éditeurs colorent ou « replient » les blocs — si la coloration paraît bizarre à partir d'un endroit, c'est souvent une accolade manquante juste avant.


🐛 Bug 2 — Un lien de navigation cassé

Ta page contact.html est déjà dans le dossier pages/. Or ton lien vers services pointe vers :

<a href="pages/services.html">   <!-- ❌ cherche pages/pages/services.html → n'existe pas -->

Comme tu es déjà dans pages/, tu redemandes d'entrer dans pages/ → le chemin n'existe pas.

Correction : le fichier est juste à côté, dans le même dossier

<a href="services.html">         <!-- ✅ même dossier, on met juste le nom du fichier -->

💡 À retenir : les chemins sont relatifs au fichier courant.

  • services.html → dans le même dossier
  • ../index.htmlremonter d'un dossier (le ..), puis prendre index.html Ton lien « retour » (../index.html) est d'ailleurs correct, bravo : c'est la même logique.

🐛 Bug 3 — Le champ e-mail n'est pas un vrai champ e-mail

<input type="text" name="e-mail" id="e-mail" ...>   <!-- ❌ type="text" -->

En type="text", le navigateur accepte n'importe quoi. Pour un e-mail, il existe un type dédié qui vérifie tout seul qu'il y a bien un @ :

<input type="email" name="email" id="email" ...>    <!-- ✅ -->

💡 À retenir : le bon type d'<input> fait travailler le navigateur à ta place : email, tel, number, date… Chacun ajoute sa petite vérification automatique.

⚠️ Petit détail : essaie d'éviter le tiret dans les id/name (e-mail). Préfère email ou e_mail — c'est plus simple à réutiliser ensuite, surtout en JavaScript.


🎯 Bug 4 — L'icône SVG n'est pas centrée dans le bouton « retour »

Ton bouton « retour » mélange une image (le SVG) et du texte côte à côte :

<button class="styled"><svg ...></svg>retour</button>

Le souci : par défaut, une icône SVG se pose sur la ligne du texte (sur la « ligne de base », comme une lettre). Du coup elle paraît trop haute ou trop basse, et ton line-height: 2.5 accentue le décalage. L'icône et le mot « retour » ne sont pas alignés sur leur milieu.

La solution : transformer le bouton en boîte flex

.styled {
    display: inline-flex;     /* le bouton range ses enfants (icône + texte) */
    align-items: center;      /* ↕ les centre verticalement, sur le même milieu */
    justify-content: center;  /* ↔ les centre horizontalement */
    gap: 6px;                 /* un petit espace entre l'icône et le mot */
    line-height: normal;      /* on enlève le 2.5 qui déréglait l'alignement */
    /* ...garde le reste de tes styles (couleur, border-radius, etc.) */
}

align-items: center, c'est exactement le flex que tu connais déjà (tu l'utilises sur #buttons). Ici on l'applique au bouton lui-même, parce que c'est lui le parent qui contient l'icône et le texte.

💡 À retenir : dès qu'un bouton (ou n'importe quelle boîte) contient une icône + du texte à aligner, passe-le en display: inline-flex; align-items: center;. C'est le réflexe pro pour centrer proprement une icône avec du texte.

🔎 Comme tous tes boutons partagent la classe .styled, cette correction les rend tous propres d'un coup — même ceux sans icône (le texte y reste bien centré).


📐 La leçon du jour : définir et limiter une <textarea>

Ta zone de message est « brute » :

<textarea name="contacter" id="contacter"></textarea>

Par défaut elle est petite, et l'utilisateur peut écrire sans aucune limite. On va la cadrer.

1️⃣ Lui donner une taille de départ : rows et cols

<textarea id="contacter" name="contacter"
          rows="6" cols="40"></textarea>
  • rows = nombre de lignes visibles (la hauteur).
  • cols = largeur en caractères.

🔎 Ce ne sont pas des pixels : c'est « combien de lignes/caractères je vois » au départ.

2️⃣ Limiter le nombre de caractères : maxlength

<textarea id="contacter" name="contacter"
          rows="6" cols="40"
          maxlength="500"></textarea>

maxlength="500" = impossible de taper plus de 500 caractères. Le navigateur bloque tout seul, sans JavaScript. 👍

3️⃣ Cadrer le redimensionnement : resize en CSS

La petite poignée en bas à droite permet à l'utilisateur d'étirer la zone et de casser ta mise en page. On la contrôle en CSS :

#contacter {
    resize: vertical;   /* étirement en hauteur seulement (recommandé) */
    /* resize: none;    pour l'interdire complètement */
    width: 100%;
    min-height: 120px;
}

💡 À retenir :

  • rows / colstaille de départ.
  • maxlengthlimite le nombre de caractères (le navigateur bloque tout seul).
  • resize (CSS) → contrôle la poignée d'étirement (vertical, horizontal, none, both).

4️⃣ 👉 Votre question : laisser l'utilisateur redimensionner, mais entre un min et un max

Tu as écrit pour l'instant :

textarea {
    resize: initial;   /* "initial" = la valeur par défaut = "both" : étirable dans TOUS les sens, sans limite */
    width: 527px;
    height: 80px;
}

resize: initial remet la valeur par défaut, c'est-à-dire both : l'utilisateur peut tout étirer, dans toutes les directions et sans aucune borne. Il peut donc rendre la zone énorme et casser ta mise en page. Vous m'avez justement demandé comment autoriser l'agrandissement sans qu'il parte trop grand (ni trop petit). La recette tient en 2 idées qui se combinent :

  1. resize dit dans quelle direction on peut étirer.
  2. min-* / max-* disent jusqu'où on peut aller.
#contacter {
    resize: vertical;     /* on autorise l'étirement, mais en HAUTEUR seulement */

    min-height: 80px;     /* impossible de la réduire en dessous de 80px */
    max-height: 300px;    /* impossible de l'agrandir au-delà de 300px */

    width: 100%;          /* largeur pilotée en CSS, pas par l'utilisateur */
}

Avec ça : l'utilisateur attrape la poignée, tire vers le bas pour avoir plus de place… mais la zone refuse de dépasser 300px et de descendre sous 80px. Ta mise en page reste protégée. 🎉

Et si on veut autoriser les deux sens (vertical et horizontal) ?

Même principe, mais avec 4 bornes : 2 pour la hauteur, 2 pour la largeur. On passe resize à both (c'est d'ailleurs ce que faisait ton resize: initial, mais cette fois borné) :

#contacter {
    resize: both;         /* la poignée étire en hauteur ET en largeur */

    min-height: 80px;     /* bornes verticales */
    max-height: 300px;

    min-width: 200px;     /* bornes horizontales */
    max-width: 100%;      /* ne dépasse jamais la largeur du parent → pas de scroll */
}

Chaque direction a sa paire min/max :

  • hauteurmin-height / max-height
  • largeurmin-width / max-width

L'utilisateur peut alors étirer dans tous les sens, mais jamais au-delà de ces 4 limites.

⚠️ Le piège classique en horizontal : mets max-width: 100% (et pas un grand 527px fixe), sinon l'utilisateur peut élargir la zone plus que l'écran et faire apparaître une barre de défilement horizontale.

Récap des valeurs de resize :

resize Ce que l'utilisateur peut étirer
none rien (verrouillé)
vertical la hauteur seulement (le plus confortable pour un message)
horizontal la largeur seulement
both les deux — c'est ce que donne initial par défaut

🎯 Petit conseil de ciblage : vise plutôt #contacter (l'id de ta textarea) que textarea tout court. Le sélecteur textarea toucherait toutes les zones de texte du site, même celles que Guillaume ajoutera sur sa page.

💡 À retenir : resize = la direction autorisée. min-height/max-height (et min-width/max-width) = les bornes. Les deux ensemble = un redimensionnement libre mais encadré.


🧭 Petit plus — centrer un bloc sans le « pousser » avec margin-left

J'ai vu que tu centres ta table et ton nouveau .form avec margin-left: 600px / 620px. Ça « marche » sur ton écran… mais sur un écran plus petit, le bloc est poussé hors de la fenêtre → barre de défilement horizontale. Pour vraiment centrer un bloc de largeur fixe :

.form {
    width: 35%;
    margin-left: auto;    /* "auto" à gauche ET à droite = */
    margin-right: auto;   /* le navigateur répartit l'espace → bloc centré */
    /* on enlève le margin-left: 620px */
}

💡 À retenir : margin: auto à gauche et à droite centre un bloc qui a une largeur. C'est l'outil correct ; margin-left: 620px ne fait que le décaler et casse l'affichage sur petit écran.


🚀 Ta première mission JavaScript : le compteur de caractères

Jusqu'ici tu as fait du HTML (la structure) et du CSS (l'apparence). Le JavaScript, c'est la 3ᵉ couche : le comportement, ce qui réagit en direct. 🧠

On va le faire en mode tuto : tu construis petit bout par petit bout, et tu testes à chaque étape. Ne copie pas tout d'un coup — avance palier par palier, c'est comme ça qu'on comprend. 🙂

Objectif final : maxlength empêche de dépasser 500 caractères… mais l'utilisateur ne voit pas combien il lui en reste. On va afficher un compteur en direct : « Il vous reste 437 caractères ». C'est exactement ce que font Twitter/X, les SMS, etc.


🪜 Étape 0 — Découvrir la console (ton meilleur ami)

Ouvre ta page dans le navigateur, puis appuie sur F12 → onglet Console. C'est là que le JS « parle ».

Crée un fichier contact.js avec une seule ligne :

console.log("Mon fichier JS est bien chargé !");

Et branche-le en bas du <body>, juste avant </body> :

<script src="contact.js"></script>

🔎 Pourquoi à la fin du body ? Parce que le JS s'exécute de haut en bas. S'il se lance avant que le HTML existe, il ne trouve rien à manipuler. À la fin, tout le HTML est déjà là. 👍

Teste maintenant : recharge la page. Tu dois voir ton message dans la Console. Si oui, ton JS est branché. Sinon, vérifie le chemin du src.


🪜 Étape 1 — Ajouter l'affichage du compteur

Sous ta textarea, ajoute la ligne qui affichera le décompte :

<textarea id="contacter" name="contacter" rows="6" maxlength="500"></textarea>
<p>Il vous reste <span id="restant">500</span> caractères.</p>

Teste maintenant : tu dois lire « Il vous reste 500 caractères ». Pour l'instant ce 500 est figé, on va le rendre vivant.

🔎 Le <span id="restant"> est juste une petite « boîte » dans laquelle le JS viendra écrire le nombre. Son id est l'étiquette par laquelle on va l'attraper.


🪜 Étape 2 — Attraper les éléments depuis le JS

Dans contact.js, remplace ton console.log de test par :

const zoneMessage = document.getElementById("contacter"); // ta textarea
const compteur = document.getElementById("restant");      // le <span>

console.log(zoneMessage); // pour vérifier qu'on l'a bien trouvée

Teste maintenant : dans la Console tu dois voir s'afficher ta <textarea>. Si tu vois null, l'id ne correspond pas → vérifie l'orthographe (contacter).

🧩 Idée clé n°1 — SÉLECTIONNER. document.getElementById("contacter") veut dire : « va me chercher l'élément dont l'id est contacter ». On le range dans une variable pour s'en servir après.


🪜 Étape 3 — Réagir quand on tape

Ajoute en dessous :

zoneMessage.addEventListener("input", function () {
    console.log("Tu viens de taper quelque chose !");
});

Teste maintenant : clique dans la zone et tape quelques lettres. À chaque touche, un message apparaît dans la Console. 🎉

🧩 Idée clé n°2 — RÉAGIR. addEventListener("input", … ) se lit : « écoute les saisies dans cette zone, et à chaque frappe, exécute cette fonction ». ("input" = « le contenu a changé », parfait pour une textarea.)


🪜 Étape 4 — Calculer et afficher ce qu'il reste

Maintenant on remplace le console.log par le vrai calcul. Voici le fichier complet :

// 1. On attrape la textarea et la "boîte" où afficher le compteur
const zoneMessage = document.getElementById("contacter");
const compteur = document.getElementById("restant");
const MAX = 500;

// 2. À chaque frappe, on recalcule ce qu'il reste
zoneMessage.addEventListener("input", function () {
    const dejaTape = zoneMessage.value.length; // .value = le texte tapé, .length = sa longueur
    compteur.textContent = MAX - dejaTape;     // on écrit le résultat dans le <span>
});

🧩 Idée clé n°3 — MODIFIER. compteur.textContent = … réécrit le texte affiché en direct, sans recharger la page. C'est ça, la magie du JS.

🔎 zoneMessage.value, c'est le contenu tapé par l'utilisateur ; .length en donne le nombre de caractères. 500 ce nombre = ce qu'il reste.

Teste maintenant : tape du texte → le nombre doit descendre à chaque lettre (499, 498, …) et s'arrêter à 0 quand tu atteins la limite. Si oui : bravo, tu viens d'écrire ta première vraie logique en JavaScript ! 🎉

🎯 Défis bonus (dans l'ordre de difficulté) :

  1. Passe le compteur en rouge quand il reste moins de 50 caractères :
    compteur.style.color = (MAX - dejaTape) < 50 ? "red" : "black";
    
  2. Affiche le texte « caractères » au singulier quand il reste 1 ou 0.
  3. Désactive le bouton « Envoyer » tant que le message est vide.

♻️ Bonus — La notion de composant réutilisable (la navbar)

Regarde : la barre du haut (#nav_barre) est recopiée à l'identique dans index.html, services.html et contact.html. Le jour où on change un lien, il faut le modifier dans 3 fichiers → source d'erreurs (c'est d'ailleurs comme ça que le Bug 2 se glisse 😉).

C'est le problème que résolvent les composants : on écrit la navbar une seule fois, et on la réutilise partout.

Première approche très simple en JavaScript : une fonction qui génère la navbar.

function creerNavbar() {
    return `
        <div id="nav_barre" class="shadow">
            <h1>FleetZen</h1>
            <div id="buttons">
                <button class="instyled">contact</button>
                <a href="services.html"><button class="styled">services</button></a>
                <a href="../index.html"><button class="styled">retour</button></a>
            </div>
        </div>`;
}

// On l'injecte tout en haut du body :
document.body.insertAdjacentHTML("afterbegin", creerNavbar());

Teste : enlève la navbar écrite « en dur » dans le HTML, garde ce JS, recharge → la navbar réapparaît, générée par la fonction. Maintenant le jour où tu changes un lien, tu le changes à un seul endroit pour toutes les pages (fini les liens cassés du Bug 2 😉).

💡 À retenir : un composant = un bout d'interface écrit une fois et réutilisé partout. C'est l'idée centrale derrière React, Vue, etc. — mais ça commence par une simple fonction comme celle-ci.


Ta checklist

  • Fermer body avec un } dans le CSS (Bug 1 — le plus urgent)
  • Réparer le lien vers services.html (Bug 2)
  • Passer le champ e-mail en type="email" (Bug 3)
  • Centrer l'icône SVG du bouton « retour » avec inline-flex (Bug 4)
  • Ajouter rows, maxlength + redimensionnement borné (resize: vertical + min/max-height)
  • Centrer table et .form avec margin: auto (au lieu de margin-left: 600px)
  • Faire marcher le compteur de caractères en JavaScript
  • (Bonus) Transformer la navbar en composant réutilisable
  • Penser à fermer la balise </html> en fin de fichier + ajouter un <footer>
  • Commits petits et clairs, puis git push

Pose-moi toutes tes questions. Tu gères ! 📬