Des listes simples aux designs avancés : compteurs, timelines, menus de navigation et composants interactifs.
HTML fournit trois éléments de liste principaux : <ul> (liste non ordonnée), <ol> (liste ordonnée) et <li> (élément de liste). Avec CSS, on peut transformer ces structures en timelines, FAQ, menus de navigation, étapes de processus et bien plus.
| Propriété | Description | Valeurs principales |
|---|---|---|
list-style-type |
Type de puce ou numérotation | disc, circle, square, decimal, none... |
list-style-image |
Image personnalisée comme puce | url('icon.png') |
list-style-position |
Position de la puce | inside, outside |
list-style |
Shorthand | type image position |
counter-reset |
Initialise un compteur | nom-compteur, nom-compteur valeur |
counter-increment |
Incrémente un compteur | nom-compteur, nom-compteur valeur |
content |
Insère du contenu avec compteur | counter(nom) |
<ul> crée une liste à puces, <ol> crée une liste numérotée, et <li> définit chaque élément de la liste.
<!-- Liste non ordonnée (puces) -->
<ul>
<li>Élément 1</li>
<li>Élément 2</li>
<li>Élément 3</li>
</ul>
<!-- Liste ordonnée (numéros) -->
<ol>
<li>Premier</li>
<li>Deuxième</li>
<li>Troisième</li>
</ol>
<!-- Liste ordonnée avec start -->
<ol start="5">
<li>Cinquième</li>
<li>Sixième</li>
</ol>
<!-- Listes imbriquées -->
<ul>
<li>Parent
<ul>
<li>Enfant 1</li>
<li>Enfant 2</li>
</ul>
</li>
</ul>
/* Types de puces */
ul { list-style-type: disc; } /* ● Plein (défaut) */
ul { list-style-type: circle; } /* ○ Cercle */
ul { list-style-type: square; } /* ■ Carré */
ul { list-style-type: none; } /* Pas de puce */
/* Numérotation arabe */
ol { list-style-type: decimal; } /* 1, 2, 3, 4... */
ol { list-style-type: decimal-leading-zero; } /* 01, 02, 03... */
/* Lettres */
ol { list-style-type: lower-alpha; } /* a, b, c, d... */
ol { list-style-type: upper-alpha; } /* A, B, C, D... */
ol { list-style-type: lower-roman; } /* i, ii, iii, iv... */
ol { list-style-type: upper-roman; } /* I, II, III, IV... */
/* Autres */
ol { list-style-type: lower-greek; } /* α, β, γ, δ... */
ol { list-style-type: lower-latin; } /* a, b, c, d... */
ol { list-style-type: upper-latin; } /* A, B, C, D... */
Démonstration : Types de listes
/* Image comme puce */
ul {
list-style-image: url('checkmark.svg');
}
/* Taille de l'image (en workaround avec padding-left) */
ul {
list-style-image: url('star.svg');
list-style-position: inside;
}
/* Fallback avec list-style-type */
ul {
list-style-type: disc;
list-style-image: url('custom-bullet.svg');
/* Si l'image ne charge pas, disc sera utilisé */
}
Liste avec icônes personnalisées
outside) ou à l'intérieur (inside) du bloc de texte.
/* outside (défaut) — la puce est hors du flux de texte */
ul { list-style-position: outside; }
/* inside — la puce est dans le flux de texte */
ul { list-style-position: inside; }
outside (défaut) :
● Premier élément de la liste
qui peut avoir plusieurs lignes
et le texte s'aligne après la puce
inside :
● Premier élément de la liste
● qui peut avoir plusieurs lignes
● et le texte s'aligne avec la puce
Différence entre outside et inside
Comparaison : outside vs inside
/* Shorthand */
ul {
list-style: disc url('icon.svg') inside;
}
/* Juste le type */
ul { list-style: none; }
/* Type + position */
ul { list-style: square inside; }
/* Réinitialiser */
ul { list-style: initial; }
<ol> ne peut pas faire seul.
/* Étape 1 : Initialiser le compteur */
.liste {
counter-reset: mon-compteur; /* Crée le compteur à 0 */
}
/* Étape 2 : Incrémenter à chaque élément */
.liste li {
counter-increment: mon-compteur; /* +1 à chaque li */
}
/* Étape 3 : Afficher le compteur */
.liste li::before {
content: counter(mon-compteur);
}
/* Compteur avec style */
.liste li::before {
content: counter(mon-compteur, upper-roman); /* I, II, III... */
content: counter(mon-compteur, lower-alpha); /* a, b, c... */
}
/* Compteur personnalisé (pas à partir de 1) */
.liste {
counter-reset: mon-compteur 0;
}
/* Compteur imbriqué */
.liste {
counter-reset: section;
}
.liste li {
counter-increment: section;
}
.liste li::before {
content: counter(section) ". ";
}
.liste li ul {
counter-reset: sous-section;
}
.liste li ul li {
counter-increment: sous-section;
}
.liste li ul li::before {
content: counter(section) "." counter(sous-section) " ";
}
Démonstration : Compteurs CSS
content et les sélecteurs :checked.
/* HTML */
<label class="check-item">
<input type="checkbox" checked>
<span class="check-custom"></span>
<span class="check-text">Tâche complétée</span>
</label>
/* CSS */
.check-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.5rem 0;
cursor: pointer;
}
.check-item input {
display: none;
}
.check-custom {
width: 20px;
height: 20px;
border: 2px solid #d1d5db;
border-radius: 6px;
display: grid;
place-items: center;
transition: all 0.2s;
}
.check-item input:checked + .check-custom {
background: #3b82f6;
border-color: #3b82f6;
}
.check-item input:checked + .check-custom::after {
content: '✓';
color: white;
font-size: 0.8rem;
font-weight: 700;
}
.check-item input:checked ~ .check-text {
text-decoration: line-through;
color: #9ca3af;
}
Démonstration : Checklist stylisée
/* HTML */
<nav>
<ul class="nav-menu">
<li class="nav-item active">
<a href="#">Accueil</a>
</li>
<li class="nav-item">
<a href="#">Cours</a>
</li>
<li class="nav-item">
<a href="#">Contact</a>
</li>
</ul>
</nav>
/* CSS */
.nav-menu {
display: flex;
gap: 0.25rem;
list-style: none;
padding: 0;
margin: 0;
}
.nav-item a {
display: block;
padding: 0.5rem 1rem;
color: #475569;
text-decoration: none;
border-radius: 6px;
font-weight: 500;
transition: all 0.2s;
}
.nav-item a:hover {
background: #f1f5f9;
color: #1e293b;
}
.nav-item.active a {
background: #3b82f6;
color: white;
}
Démonstration : Navigation en liste
Démonstration : Breadcrumb en liste
<ul> ← Conteneur de liste
│
├─ <li> Élément 1 </li> ← Élément de liste (bloc)
│ └─ ::marker ← Le puce (pseudo-élément)
│ └─ contenu ← Le texte de l'élément
│
├─ <li> Élément 2 </li>
│
└─ <li> Élément 3 </li>
└─ <ul> ← Liste imbriquée
├─ <li> Sous-élément 1 </li>
└─ <li> Sous-élément 2 </li>
Propriétés héritées :
list-style-type → de ul/ol vers li
list-style-image → de ul/ol vers li
list-style-position→ de ul/ol vers li
Propriétés non héritées :
display, padding, margin → à réinitialiser
Structure et héritage des propriétés de liste
counter-reset: mon-compteur → Initialisation (valeur = 0)
Élément 1 :
counter-increment: mon-compteur → Valeur = 1
::before { content: counter(mon-compteur) } → Affiche "1"
Élément 2 :
counter-increment: mon-compteur → Valeur = 2
::before { content: counter(mon-compteur) } → Affiche "2"
Élément 3 :
counter-increment: mon-compteur → Valeur = 3
::before { content: counter(mon-compteur) } → Affiche "3"
Compteur imbriqué :
═══════════════════
counter-reset: section
├─ Section 1 → counter(section) = 1
│ counter-reset: sous-section
│ ├─ 1.1 → counter(sous-section) = 1
│ ├─ 1.2 → counter(sous-section) = 2
├─ Section 2 → counter(section) = 2
│ counter-reset: sous-section
│ ├─ 2.1 → counter(sous-section) = 1
Flux d'exécution des compteurs CSS
list-style-position: outside (défaut)
────────────────────────────────────
┌─ padding-left ─┐
│ │
● │ Premier élém...│
● │ Deuxième élém..│
● │ Troisième élém.│
│ │
└────────────────┘
La puce est EN DEHORS du bloc de texte
Le texte est indenté
list-style-position: inside
──────────────────────────
┌─ padding-left ─┐
│ │
│ ● Premier élém.│
│ ● Deuxième élém│
│ ● Troisième él.│
│ │
└────────────────┘
La puce est DANS le bloc de texte
Le texte s'aligne sur la puce
Comparaison des positions de puce
Composant Timeline
/* HTML */
<ol class="timeline">
<li class="timeline-item">
<div class="timeline-marker"></div>
<div class="timeline-content">
<h3>Janvier 2024</h3>
<p>Lancement du projet</p>
</div>
</li>
<li class="timeline-item">
<div class="timeline-marker"></div>
<div class="timeline-content">
<h3>Mars 2024</h3>
<p>Première version beta</p>
</div>
</li>
</ol>
/* CSS */
.timeline {
list-style: none;
padding: 0;
position: relative;
}
.timeline::before {
content: '';
position: absolute;
left: 16px;
top: 0;
bottom: 0;
width: 2px;
background: #e2e8f0;
}
.timeline-item {
position: relative;
padding-left: 48px;
padding-bottom: 2rem;
}
.timeline-marker {
position: absolute;
left: 8px;
top: 4px;
width: 18px;
height: 18px;
border-radius: 50%;
background: #3b82f6;
border: 3px solid white;
box-shadow: 0 0 0 2px #3b82f6;
}
.timeline-content h3 {
font-size: 1rem;
margin-bottom: 0.25rem;
}
.timeline-content p {
color: #64748b;
font-size: 0.9rem;
}
Lancement du projet et définition du scope
Première version beta avec les fonctionnalités core
Ouverture aux bêta-testeurs
Lancement officiel v1.0
Liste de fonctionnalités avec icônes custom
/* CSS */
.feature-list {
list-style: none;
padding: 0;
}
.feature-item {
display: flex;
align-items: flex-start;
gap: 1rem;
padding: 0.75rem 0;
}
.feature-icon {
flex-shrink: 0;
width: 32px;
height: 32px;
border-radius: 8px;
display: grid;
place-items: center;
font-size: 1rem;
}
.feature-icon.blue { background: #dbeafe; }
.feature-icon.green { background: #dcfce7; }
.feature-icon.purple { background: #f3e8ff; }
.feature-text strong {
display: block;
margin-bottom: 0.125rem;
}
.feature-text span {
font-size: 0.85rem;
color: #64748b;
}
Structure FAQ avec details/summary
/* HTML */
<dl class="faq">
<div class="faq-item">
<dt>
<button class="faq-question">
Qu'est-ce que CSS ?
<span class="faq-icon">+</span>
</button>
</dt>
<dd class="faq-answer">
<p>CSS (Cascading Style Sheets) est un langage de
styles utilisé pour décrire la présentation des
documents HTML.</p>
</dd>
</div>
</dl>
/* Utiliser details/summary (natif) */
<details class="faq-item">
<summary class="faq-question">
Qu'est-ce que CSS ?
</summary>
<div class="faq-answer">
<p>CSS est un langage de styles...</p>
</div>
</details>
/* CSS */
.faq-item {
border: 1px solid #e2e8f0;
border-radius: 8px;
margin-bottom: 0.5rem;
overflow: hidden;
}
.faq-question {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 1.25rem;
background: white;
border: none;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
text-align: left;
}
.faq-answer {
padding: 0 1.25rem 1rem;
color: #64748b;
line-height: 1.6;
}
details[open] .faq-icon {
transform: rotate(45deg);
}
CSS (Cascading Style Sheets) est un langage de styles utilisé pour décrire la présentation des documents HTML. Il contrôle les couleurs, la mise en page, la typographie et bien plus.
Une classe (.classe) peut être utilisée sur plusieurs éléments, tandis qu'un id (#id) doit être unique dans la page. Les id ont une priorité plus élevée dans la cascade CSS.
La cascade détermine quel style s'applique quand plusieurs règles correspondent. Elle prend en compte l'ordre de déclaration, la spécificité et l'héritage.
Indicateur d'étapes horizontales
/* HTML */
<ol class="steps">
<li class="step-item completed">
<span class="step-num">1</span>
<span class="step-label">Inscription</span>
</li>
<li class="step-item active">
<span class="step-num">2</span>
<span class="step-label">Vérification</span>
</li>
<li class="step-item">
<span class="step-num">3</span>
<span class="step-label">Paiement</span>
</li>
</ol>
/* CSS */
.steps {
display: flex;
justify-content: space-between;
list-style: none;
padding: 0;
position: relative;
}
.steps::before {
content: '';
position: absolute;
top: 18px;
left: 10%;
right: 10%;
height: 2px;
background: #e2e8f0;
}
.step-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
position: relative;
z-index: 1;
}
.step-num {
width: 36px;
height: 36px;
border-radius: 50%;
background: #e2e8f0;
color: #94a3b8;
display: grid;
place-items: center;
font-weight: 700;
font-size: 0.9rem;
transition: all 0.3s;
}
.step-item.completed .step-num {
background: #22c55e;
color: white;
}
.step-item.active .step-num {
background: #3b82f6;
color: white;
box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.2);
}
.step-label {
font-size: 0.8rem;
color: #64748b;
font-weight: 500;
}
.step-item.active .step-label {
color: #1e293b;
font-weight: 600;
}
/* FAUX — les marges et padding par défaut créent un décalage */
ul {
list-style: none;
/* Les marges et padding par défaut subsistent ! */
}
/* CORRECT — tout réinitialiser */
ul {
list-style: none;
padding: 0;
margin: 0;
}
/* FAUX — pas sémantique */
<div class="liste">
<div class="item">Élément 1</div>
<div class="item">Élément 2</div>
</div>
/* CORRECT — structure sémantique */
<ul class="liste">
<li class="item">Élément 1</li>
<li class="item">Élément 2</li>
</ul>
/* FAUX — si l'image ne charge pas, pas de puce */
ul {
list-style-image: url('icon.svg');
}
/* CORRECT — toujours un fallback */
ul {
list-style-type: disc;
list-style-image: url('icon.svg');
}
/* FAUX — le compteur se réinitialise à chaque élément */
li {
counter-reset: mon-compteur;
counter-increment: mon-compteur;
}
/* CORRECT — counter-reset sur le conteneur */
ol {
counter-reset: mon-compteur;
}
ol li {
counter-increment: mon-compteur;
}
/* ATTENTION — list-style: none peut casser la sémantics */
ul {
list-style: none;
/* Les lecteurs d'écran ne détectent plus la liste ! */
}
/* CORRECT — ajouter le role ARIA si nécessaire */
<ul role="list" style="list-style: none;">
...
</ul>
/* FAUX — les listes imbriquées ont le même style */
ul ul {
list-style-type: disc; /* Même puce que le parent ! */
}
/* CORRECT — varier les styles selon la profondeur */
ul { list-style-type: disc; }
ul ul { list-style-type: circle; }
ul ul ul { list-style-type: square; }
<ul> pour les éléments non ordonnés, <ol> pour les ordonnés.<ol>.<ul> avec list-style: none pour l'accessibilité.| Situation | Approche recommandée |
|---|---|
| Liste de caractéristiques | <ul> avec icônes personnalisées via ::before |
| Étapes d'un processus | <ol> avec compteurs CSS ou design personnalisé |
| Menu de navigation | <ul> + display: flex + list-style: none |
| FAQ / Accordéon | <details>/<summary> natif |
| Checklist / Todo | <ul> avec checkboxes stylisées |
| Breadcrumb | <ol> avec séparateurs via ::after |
| Timeline | <ol> avec pseudo-éléments pour la ligne |
| Numérotation personnalisée | counter-reset + counter-increment + content: counter() |
Exercice 1 : Liste sans puces
Crée une liste horizontale de liens de navigation en retirant toutes les puces et en utilisant Flexbox :
Solution :
.nav {
display: flex;
gap: 1rem;
list-style: none;
padding: 0;
margin: 0;
}
.nav a {
color: #334155;
text-decoration: none;
padding: 0.5rem 1rem;
border-radius: 6px;
}
.nav a:hover {
background: #f1f5f9;
}
Exercice 2 : Compteur personnalisé
Crée une liste numérotée avec des compteurs qui commencent à 5 et utilisent des chiffres romains :
Solution :
.liste-romaine {
list-style: none;
counter-reset: romain 4;
}
.liste-romaine li {
counter-increment: romain;
}
.liste-romaine li::before {
content: counter(romain, upper-roman) ". ";
font-weight: 700;
color: #3b82f6;
}
Exercice 3 : Liste avec bordure gauche
Crée une liste où chaque élément a une bordure colorée à gauche qui change selon l'élément :
Solution :
.liste-borduree {
list-style: none;
padding: 0;
}
.liste-borduree li {
padding: 0.75rem 1rem;
margin-bottom: 0.5rem;
border-left: 4px solid #3b82f6;
background: #f8fafc;
border-radius: 0 6px 6px 0;
}
.liste-borduree li:nth-child(2) { border-color: #8b5cf6; }
.liste-borduree li:nth-child(3) { border-color: #ec4899; }
.liste-borduree li:nth-child(4) { border-color: #f59e0b; }
Exercice 4 : Menu vertical
Crée un menu vertical avec icônes, texte et un indicateur de sélection actif :
Solution :
.menu {
list-style: none;
padding: 0;
width: 200px;
background: #1e293b;
border-radius: 8px;
}
.menu-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 1rem;
color: #94a3b8;
cursor: pointer;
border-radius: 6px;
margin: 0.25rem;
transition: all 0.2s;
}
.menu-item:hover {
background: rgba(255,255,255,0.1);
color: white;
}
.menu-item.active {
background: #3b82f6;
color: white;
}
Exercice 5 : Checklist avec animation
Crée une checklist où les éléments cochés ont une animation de barré et de coloration :
Solution :
.checklist {
list-style: none;
padding: 0;
}
.checklist li {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.5rem 0;
cursor: pointer;
transition: all 0.3s;
}
.checklist li::before {
content: '☐';
font-size: 1.2rem;
color: #94a3b8;
}
.checklist li.done::before {
content: '☑';
color: #22c55e;
}
.checklist li.done {
color: #94a3b8;
text-decoration: line-through;
}
Exercice 6 : Breadcrumb avec séparateurs
Crée un breadcrumb avec des séparateurs / entre les étapes :
Solution :
.breadcrumb {
display: flex;
list-style: none;
padding: 0;
gap: 0.5rem;
font-size: 0.9rem;
}
.breadcrumb li:not(:last-child)::after {
content: '/';
margin-left: 0.5rem;
color: #94a3b8;
}
.breadcrumb a {
color: #3b82f6;
text-decoration: none;
}
.breadcrumb a:hover {
text-decoration: underline;
}
.breadcrumb li:last-child {
color: #64748b;
}
Projet : Page de cours avec listes avancées
Crée un fichier index.html et listes.css qui implémentent une page de cours utilisant différentes structures de listes :
HTML requis :
<nav> avec un <ul> comme menu de navigation horizontal<main> contenant :<section class="sommaire"> — sommaire avec compteurs CSS<section class="features"> — liste de fonctionnalités avec icônes<section class="timeline"> — frise chronologique<section class="faq"> — 3 questions avec <details>/<summary><footer> avec breadcrumbCSS requis :
display: flex, list-style: none, gap, hover statescounter() et ::before::before avec icônes ou compteurs::before pour la ligne verticale, markers ronds<details>/<summary> stylisés::afterObjectif : Démontrer la maîtrise des listes, compteurs CSS et sémantique HTML dans la création de composants UI variés.
Quiz rapide
<ul> et <ol> ?list-style-position: inside et outside ?role="list" quand on utilise list-style: none ?counter() et counters() ?<ul> est une liste non ordonnée (puces), <ol> est une liste ordonnée (numéros).list-style-type: noneinside place la puce dans le flux de texte (le texte s'aligne sur la puce). outside (défaut) place la puce à l'extérieur du bloc de texte.counter-reset: nom sur le conteneur, 2) counter-increment: nom sur les éléments, 3) content: counter(nom) dans le pseudo-élément.counter-reset: nom valeur — ex: counter-reset: compteur 4 commence à 5.display: flex sur le <ul> et en retirant les styles de liste par défaut.role="list" restaure la sémantique.<details> avec <summary> à l'intérieur.<ol> avec ::before pour les markers, une ligne verticale via ::before sur le conteneur, et des markers ronds avec position: absolute.counter() gère un seul compteur. counters() gère des compteurs imbriqués avec un séparateur — ex: counters(section, ".") produit "1.1", "1.2", "2.1".