Numérotation automatique en CSS

CSS est un langage de description, pas de programmation. Ça, c’est clair : pas de variables, pas de boucles, pas de fonctions… C’est bien pour ça que les préprocesseurs comme Sass et Less existent. Attendez : pas de variables ? Hmm en fait si, d’une certaine manière : notamment pour la numérotation.

Imaginez un article long, séparé en chapitres titrés par des h2, et en sous-parties titrées par des h3. Ce serait pratique de numéroter tout ça, n’est-ce pas ? Mais si on le fait à la main, au moindre ajout de chapitre entre deux il faudra tout refaire. C’est là que CSS entre dans la danse. Oui, CSS, ce brave CSS, qui va nous permettre d’ajouter des chiffres (ou des lettres) à nos titres, automatiquement.

Le balisage html

<h1>La vie sur Terre</h1>    
<h2>Les animaux</h2>
<h3>Les mammifères</h3>
<p>Nous allons vous parler des mammifères, de la famille des "Ils ont des poils".</p>
<h3>Les reptiles</h3>
<p>Nous allons vous parler des reptiles, de la famille des "Ils n'ont pas toujours de pattes".</p>
<h2>Les végétaux</h2>
<h3>Les cormophytes</h3>
<p>Nous allons vous parler des cormophytes, de la famille des "Ils ont des tiges".</p>
<h3>Les thallophytes</h3>
<p>Nous allons vous parler des thallophytes, de la famille des "Ils sont gluants".</p>

(oui, la classification a évolué depuis, et il en manque de gros bouts, mais zut, c’est mon exemple)

(et si vous trouvez ma référence, je vous aime)

Le style

On définit que le compteur des chapitres s’appellera « chapter », et celui des sous-parties « subpart ». Oui, je sais, je donne à mes variables des noms incroyablement originaux.

Première chose : mettre à zéro le compteur des chapitres, sur body.

body {
   counter-reset: chapter;
}

Sur les h2 (titres de chapitre), on incrémente la variable chapter, tout en remettant à zéro subpart.

h2 {
  counter-increment: chapter;
  counter-reset: subpart;
}

Sur les h3, on incrémente juste la variable subpart.

h3 {
  counter-increment: subpart;  
}

Jusqu’ici, rien que du très logique, n’est-ce pas ?

Mais nous n’avons fait que définir, il faut maintenant afficher. Et pour cela, on va utiliser la valeur counter(). En argument, le nom du compteur, tout simplement. Comme il s’agit d’un contenu, la propriété à qui on donne cette valeur, c’est content – je ne crois pas qu’elle puisse s’appliquer à une autre.

Et comme pour l’instant, content n’est utilisable que sur les pseudo-éléments, on va partir sur :before pour l’exemple.

Ici, on affiche le numéro du chapitre suivi immédiatement d’un point puis un espace (eh oui, on peut concaténer en CSS, et l’opérateur de concaténation est l’espace).

h2:before {
   content: counter(chapter) ". ";
}

Les sous-parties se voient affublées du numéro de chapitre, suivi d’un point, puis du numéro de sous-partie, et encore un point et un espace.

h3:before {
  content: counter(chapter) "." counter(subpart) ". ";
}

Voir la démo.

À noter que j’ai défini les resets et increments sur les éléments et l’affichage sur les pseudo-éléments, mais les increments peuvent se mettre sur les pseudo-éléments, pour raccourcir un peu l’écriture. En revanche, les resets doivent être sur les éléments – j’ai testé, ça marche pas, sinon.

Autre chose : la numérotation ne prend pas en compte un élément en display: none, attention.

Un peu plus de style

Si on ne précise rien, la numérotation se fait en chiffres arabes. Mais on peut utiliser les chiffres romains, géorgiens, l’alphabet grec, latin, exactement comme pour la numérotation des listes ordonnées.

Pour cela, il suffit d’indiquer le type dans l’affichage, en second paramètre de counter :

h2:before {
  content: counter(chapter, upper-latin) ". ";
}

h3:before {
  content: counter(chapter, upper-latin) "." counter(subpart) ". ";
}

(là, comme ça, j’ai l’impression de revivre mes cours de bio de la fac. Woohoo.)

Voir la démo.

Numérotation imbriquée

Justement, parlons-en, des listes. Les listes ordonnées ont par défaut un chiffre arabe suivi d’un point. Mais on peut tout à fait redéfinir ceci.

Déjà, on annule le style par défaut de la liste.

ol {
  list-style-type: none;              
}

Ensuite, on met à zéro le compteur « section », sur le ol.

ol {
  list-style-type: none;
  counter-reset: section;                
} 

Enfin, on incrémente et on affiche :

li:before {
  counter-increment: section;            
  content: counters(section, ".") " ";
}

Ici, la fonction est différente : c’est counters, avec un s. Cette fonction accepte en paramètre le nom du compteur et le séparateur, tous deux obligatoires, et en troisième paramètre optionnel, le type de numérotation (les valeurs de list-type). Ce troisième paramètre semble ne pas pouvoir être redéfini suivant la profondeur de la liste, c’est-à-dire qu’on ne peut pas avoir une liste dont les li du premier ol seraient préfixées par I, II, III, et les li du ol-fils par i, ii, iii…

Voir la démo.

Conclusion

Outre son côté pratique, cela permet de faire de très jolies choses, puisqu’on peut parfaitement styler les pseudo-éléments.

Compteurs CSS chez Lea Verou

C’est chez Lea Verou que j’ai découvert pour la première fois cette propriété. Cela m’avait mystifiée pendant un bout de temps, car Firebug n’affichait pas encore les pseudo-éléments.

Compteurs CSS sur Alsacréations

Sur Alsacrétions, dans un article sur les listes.

Et CanIUse nous indique que tous les navigateurs, hormis IE 5, 6 et 7, gèrent les compteurs (accessoirement, ces derniers ne gèrent pas les pseudo-éléments, donc de toute façon on n’aurait rien pu faire avec). Donc ne vous privez pas !

Bibliographie

  1. est-il possible de numéroter automatiquement les titres dans un fichier markdown natif