462 lines
14 KiB
CSS
462 lines
14 KiB
CSS
/* =====================================================================
|
|
style.css — la "peau" de la page
|
|
---------------------------------------------------------------------
|
|
Le CSS (Cascading Style Sheets) décrit l'APPARENCE des éléments HTML.
|
|
Une règle CSS se lit ainsi :
|
|
|
|
sélecteur { ← QUI on cible (balise, .classe, #id…)
|
|
propriété: valeur; ← CE QU'ON change
|
|
}
|
|
|
|
"Cascading" (en cascade) : si plusieurs règles ciblent le même
|
|
élément, la plus SPÉCIFIQUE gagne (un #id bat une .classe qui bat
|
|
une balise), et à égalité, la DERNIÈRE écrite gagne.
|
|
===================================================================== */
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
1. VARIABLES CSS (on dit aussi "custom properties")
|
|
---------------------------------------------------------------------
|
|
:root = l'élément racine du document (<html>).
|
|
On y déclare des variables qui commencent par deux tirets "--".
|
|
On les réutilise ensuite partout avec var(--nom).
|
|
Avantage : changer une couleur à UN endroit la change PARTOUT.
|
|
--------------------------------------------------------------------- */
|
|
:root {
|
|
--fond: #f7f5f0; /* couleur de fond de la page */
|
|
--surface: #ffffff; /* fond des "cartes" et blocs */
|
|
--texte: #1d1b18; /* couleur du texte principal */
|
|
--texte-doux: #6b665e; /* texte secondaire, plus discret */
|
|
--bordure: #e2ddd3; /* traits de séparation */
|
|
--accent: #d4a017; /* jaune "JavaScript" */
|
|
--accent-fort: #8a6500; /* version plus foncée pour le texte */
|
|
--code-fond: #1e1e24; /* fond des éditeurs de code */
|
|
--code-texte: #e8e6e3; /* texte dans les éditeurs */
|
|
--ok: #2f9e5b; /* vert : succès */
|
|
--erreur: #d64545; /* rouge : erreur */
|
|
--info: #3b7dd8; /* bleu : information */
|
|
|
|
--rayon: 10px; /* arrondi des coins */
|
|
--police: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
--police-code: "JetBrains Mono", "Fira Code", Consolas, monospace;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
MODE SOMBRE AUTOMATIQUE
|
|
---------------------------------------------------------------------
|
|
@media permet d'appliquer des règles SOUS CONDITION.
|
|
Ici : "si le système de l'utilisateur est réglé en thème sombre".
|
|
On ne fait que redéfinir les variables : tout le reste suit tout seul.
|
|
:not([data-theme="light"]) → sauf si l'utilisateur a forcé le clair
|
|
avec le bouton (voir script.js).
|
|
--------------------------------------------------------------------- */
|
|
@media (prefers-color-scheme: dark) {
|
|
:root:not([data-theme="light"]) {
|
|
--fond: #141416;
|
|
--surface: #1c1c20;
|
|
--texte: #ecebe8;
|
|
--texte-doux: #9d988f;
|
|
--bordure: #2e2e34;
|
|
--accent-fort: #f0c040;
|
|
--code-fond: #0f0f12;
|
|
}
|
|
}
|
|
/* Même chose quand l'utilisateur force le thème sombre avec le bouton */
|
|
:root[data-theme="dark"] {
|
|
--fond: #141416;
|
|
--surface: #1c1c20;
|
|
--texte: #ecebe8;
|
|
--texte-doux: #9d988f;
|
|
--bordure: #2e2e34;
|
|
--accent-fort: #f0c040;
|
|
--code-fond: #0f0f12;
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
2. RÉINITIALISATION DE BASE
|
|
---------------------------------------------------------------------
|
|
"*" = sélecteur universel : TOUS les éléments.
|
|
box-sizing: border-box → la largeur d'un élément INCLUT ses marges
|
|
intérieures (padding) et sa bordure. Beaucoup plus intuitif.
|
|
--------------------------------------------------------------------- */
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
html {
|
|
scroll-behavior: smooth; /* défilement doux quand on clique un lien #ancre */
|
|
scroll-padding-top: 20px; /* laisse un peu d'air au-dessus du titre ciblé */
|
|
}
|
|
|
|
body {
|
|
margin: 0; /* le navigateur met 8px par défaut : on enlève */
|
|
background: var(--fond);
|
|
color: var(--texte);
|
|
font-family: var(--police);
|
|
font-size: 17px;
|
|
line-height: 1.65; /* interligne confortable pour la lecture */
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
3. MISE EN PAGE : grille à deux colonnes (menu + contenu)
|
|
---------------------------------------------------------------------
|
|
display: grid transforme un conteneur en GRILLE.
|
|
grid-template-columns définit la largeur des colonnes :
|
|
- 260px : le menu a une largeur fixe
|
|
- 1fr : le contenu prend "1 fraction" de l'espace restant
|
|
--------------------------------------------------------------------- */
|
|
.mise-en-page {
|
|
display: grid;
|
|
grid-template-columns: 260px 1fr;
|
|
min-height: 100vh; /* vh = % de la hauteur de la fenêtre */
|
|
}
|
|
|
|
/* Le menu latéral */
|
|
.sommaire {
|
|
position: sticky; /* "colle" en haut quand on défile */
|
|
top: 0;
|
|
height: 100vh;
|
|
overflow-y: auto; /* barre de défilement si le menu est long */
|
|
padding: 24px 18px;
|
|
border-right: 1px solid var(--bordure);
|
|
background: var(--surface);
|
|
}
|
|
|
|
.sommaire .logo {
|
|
display: flex; /* flexbox : aligne les enfants en ligne */
|
|
align-items: center; /* centrés verticalement */
|
|
gap: 10px; /* espace entre eux */
|
|
font-weight: 700;
|
|
font-size: 1.1rem; /* rem = relatif à la taille de police racine */
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.sommaire .logo span {
|
|
background: var(--accent);
|
|
color: #000;
|
|
font-family: var(--police-code);
|
|
padding: 2px 8px;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.sommaire ol {
|
|
list-style: none; /* enlève les numéros automatiques */
|
|
padding: 0;
|
|
margin: 0;
|
|
counter-reset: chap -1; /* compteur CSS maison, démarre à -1 → premier = 0 */
|
|
}
|
|
|
|
.sommaire li {
|
|
counter-increment: chap; /* +1 à chaque <li> */
|
|
}
|
|
|
|
.sommaire a {
|
|
display: block;
|
|
padding: 6px 10px;
|
|
border-radius: 6px;
|
|
color: var(--texte-doux);
|
|
text-decoration: none; /* enlève le soulignement des liens */
|
|
font-size: 0.93rem;
|
|
transition: background .15s, color .15s; /* animation douce au survol */
|
|
}
|
|
|
|
/* ::before = pseudo-élément : du contenu "virtuel" inséré AVANT le texte */
|
|
.sommaire a::before {
|
|
content: counter(chap, decimal-leading-zero) " ";
|
|
font-family: var(--police-code);
|
|
opacity: .5;
|
|
}
|
|
|
|
/* :hover = quand la souris passe dessus */
|
|
.sommaire a:hover {
|
|
background: var(--fond);
|
|
color: var(--texte);
|
|
}
|
|
|
|
/* .actif est ajoutée par JavaScript sur le chapitre en cours de lecture */
|
|
.sommaire a.actif {
|
|
background: var(--accent);
|
|
color: #000;
|
|
}
|
|
|
|
#bouton-theme {
|
|
margin-top: 20px;
|
|
width: 100%;
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
4. LE CONTENU
|
|
--------------------------------------------------------------------- */
|
|
main {
|
|
max-width: 860px; /* lignes pas trop longues = lecture facile */
|
|
padding: 40px 48px 120px;
|
|
min-width: 0; /* évite qu'un long bloc de code élargisse la grille */
|
|
}
|
|
|
|
header.intro h1 {
|
|
font-size: 2.6rem;
|
|
line-height: 1.15;
|
|
margin: 0 0 12px;
|
|
}
|
|
|
|
header.intro h1 mark {
|
|
background: var(--accent);
|
|
color: #000;
|
|
padding: 0 8px;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
header.intro p.chapeau {
|
|
font-size: 1.2rem;
|
|
color: var(--texte-doux);
|
|
}
|
|
|
|
section.chapitre {
|
|
padding-top: 40px;
|
|
margin-top: 40px;
|
|
border-top: 1px solid var(--bordure);
|
|
}
|
|
|
|
section.chapitre h2 {
|
|
font-size: 1.8rem;
|
|
margin: 0 0 16px;
|
|
}
|
|
|
|
section.chapitre h2 .num {
|
|
font-family: var(--police-code);
|
|
color: var(--accent-fort);
|
|
margin-right: 10px;
|
|
}
|
|
|
|
h3 {
|
|
margin-top: 32px;
|
|
font-size: 1.2rem;
|
|
}
|
|
|
|
/* Le code "en ligne" dans le texte, ex : <code>let</code> */
|
|
p code, li code, td code, summary code {
|
|
font-family: var(--police-code);
|
|
font-size: .88em;
|
|
background: var(--surface);
|
|
border: 1px solid var(--bordure);
|
|
padding: 1px 6px;
|
|
border-radius: 5px;
|
|
}
|
|
|
|
/* Encadrés pédagogiques */
|
|
.encadre {
|
|
border-left: 4px solid var(--info);
|
|
background: var(--surface);
|
|
padding: 12px 18px;
|
|
border-radius: 0 var(--rayon) var(--rayon) 0;
|
|
margin: 20px 0;
|
|
}
|
|
.encadre.astuce { border-color: var(--ok); }
|
|
.encadre.attention { border-color: var(--erreur); }
|
|
.encadre strong:first-child { display: block; margin-bottom: 4px; }
|
|
|
|
/* Tableaux */
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse; /* fusionne les bordures des cellules */
|
|
margin: 16px 0;
|
|
font-size: .95rem;
|
|
}
|
|
th, td {
|
|
text-align: left;
|
|
padding: 8px 12px;
|
|
border-bottom: 1px solid var(--bordure);
|
|
}
|
|
th { color: var(--texte-doux); font-weight: 600; }
|
|
|
|
/* Images de schéma faites en texte */
|
|
pre.schema {
|
|
font-family: var(--police-code);
|
|
font-size: .85rem;
|
|
background: var(--surface);
|
|
border: 1px solid var(--bordure);
|
|
border-radius: var(--rayon);
|
|
padding: 16px;
|
|
overflow-x: auto;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
5. LE "BAC À SABLE" : éditeur de code + sortie
|
|
---------------------------------------------------------------------
|
|
Chaque .bac contient :
|
|
- une barre (titre + boutons)
|
|
- un <textarea> où l'on écrit le code
|
|
- une zone .sortie où s'affichent les console.log
|
|
--------------------------------------------------------------------- */
|
|
.bac {
|
|
margin: 20px 0;
|
|
border-radius: var(--rayon);
|
|
overflow: hidden; /* coupe ce qui dépasse des coins arrondis */
|
|
border: 1px solid var(--bordure);
|
|
background: var(--code-fond);
|
|
}
|
|
|
|
.bac .barre {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between; /* titre à gauche, boutons à droite */
|
|
gap: 8px;
|
|
flex-wrap: wrap; /* les boutons passent à la ligne si besoin */
|
|
padding: 8px 12px;
|
|
background: rgba(255,255,255,.04);
|
|
color: #9d988f;
|
|
font-size: .82rem;
|
|
font-family: var(--police-code);
|
|
}
|
|
|
|
.bac .boutons { display: flex; gap: 6px; }
|
|
|
|
.bac textarea {
|
|
display: block;
|
|
width: 100%;
|
|
min-height: 120px;
|
|
padding: 14px 16px;
|
|
border: none;
|
|
outline: none;
|
|
resize: vertical; /* on peut agrandir verticalement */
|
|
background: transparent;
|
|
color: var(--code-texte);
|
|
font-family: var(--police-code);
|
|
font-size: 14.5px;
|
|
line-height: 1.6;
|
|
tab-size: 2; /* une tabulation = 2 espaces */
|
|
white-space: pre; /* garde les espaces et retours à la ligne */
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.bac .sortie {
|
|
border-top: 1px solid rgba(255,255,255,.08);
|
|
padding: 10px 16px;
|
|
font-family: var(--police-code);
|
|
font-size: 13.5px;
|
|
color: #cfcac2;
|
|
min-height: 38px;
|
|
max-height: 320px;
|
|
overflow: auto;
|
|
background: rgba(0,0,0,.25);
|
|
}
|
|
|
|
/* :empty = élément sans contenu → on affiche un texte d'aide via ::before */
|
|
.bac .sortie:empty::before {
|
|
content: "▸ La sortie s'affichera ici. Clique sur « Exécuter » (ou Ctrl+Entrée).";
|
|
color: #6b665e;
|
|
}
|
|
|
|
/* Chaque ligne de sortie */
|
|
.ligne { white-space: pre-wrap; padding: 2px 0; border-bottom: 1px dashed rgba(255,255,255,.05); }
|
|
.ligne.err { color: #ff8a8a; }
|
|
.ligne.warn { color: #f0c040; }
|
|
.ligne.info { color: #8ab4f8; }
|
|
.ligne .t-nombre { color: #b5cea8; }
|
|
.ligne .t-texte { color: #ce9178; }
|
|
.ligne .t-booleen { color: #569cd6; }
|
|
.ligne .t-vide { color: #808080; font-style: italic; }
|
|
|
|
/* Zone visuelle pour les démos DOM */
|
|
.scene {
|
|
background: var(--surface);
|
|
border-top: 1px solid rgba(255,255,255,.08);
|
|
padding: 16px;
|
|
min-height: 60px;
|
|
color: var(--texte);
|
|
font-family: var(--police);
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
6. BOUTONS
|
|
--------------------------------------------------------------------- */
|
|
button {
|
|
font: inherit; /* hérite de la police du parent */
|
|
cursor: pointer; /* curseur "main" */
|
|
border: 1px solid var(--bordure);
|
|
background: var(--surface);
|
|
color: var(--texte);
|
|
padding: 6px 14px;
|
|
border-radius: 7px;
|
|
font-size: .9rem;
|
|
}
|
|
button:hover { border-color: var(--accent); }
|
|
|
|
/* Boutons dans la barre des éditeurs */
|
|
.bac button {
|
|
font-family: var(--police-code);
|
|
font-size: .8rem;
|
|
padding: 4px 10px;
|
|
background: transparent;
|
|
color: #cfcac2;
|
|
border-color: rgba(255,255,255,.15);
|
|
}
|
|
.bac button.executer {
|
|
background: var(--accent);
|
|
color: #000;
|
|
border-color: var(--accent);
|
|
font-weight: 700;
|
|
}
|
|
|
|
/* :focus-visible = focus au CLAVIER : important pour l'accessibilité */
|
|
button:focus-visible, textarea:focus-visible, a:focus-visible, input:focus-visible {
|
|
outline: 2px solid var(--accent);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
7. EXERCICES (balise <details> : un bloc qu'on ouvre / ferme)
|
|
--------------------------------------------------------------------- */
|
|
.exercice {
|
|
background: var(--surface);
|
|
border: 1px solid var(--bordure);
|
|
border-radius: var(--rayon);
|
|
padding: 16px 20px;
|
|
margin: 24px 0;
|
|
}
|
|
.exercice > strong { color: var(--accent-fort); }
|
|
|
|
details {
|
|
margin-top: 10px;
|
|
}
|
|
details summary {
|
|
cursor: pointer;
|
|
color: var(--texte-doux);
|
|
font-size: .92rem;
|
|
}
|
|
details[open] summary { margin-bottom: 8px; }
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
8. RESPONSIVE : adaptation aux petits écrans (téléphone)
|
|
---------------------------------------------------------------------
|
|
max-width: 860px → "si l'écran fait 860px de large OU MOINS".
|
|
On passe alors en une seule colonne et le menu devient un bandeau.
|
|
--------------------------------------------------------------------- */
|
|
@media (max-width: 860px) {
|
|
.mise-en-page { grid-template-columns: 1fr; }
|
|
|
|
.sommaire {
|
|
position: static;
|
|
height: auto;
|
|
border-right: none;
|
|
border-bottom: 1px solid var(--bordure);
|
|
}
|
|
.sommaire ol {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 4px;
|
|
}
|
|
.sommaire a { font-size: .8rem; padding: 4px 8px; }
|
|
|
|
main { padding: 24px 16px 80px; }
|
|
header.intro h1 { font-size: 2rem; }
|
|
}
|