Centrer du texte dans un <hr />

Le problème

Non, <hr /> ne peut pas contenir de texte. Je veux plutôt parler de l'effet obtenu si cela était possible, qu'on retrouve un peu partout sur le web.

Ce problème n'étant pas nouveau, des implémentations ont déjà été trouvées, mais ces dernières sont rarement satisfaisantes. En effet, la solution idéale

  • ne dépend pas du fond présent sous le texte ;
  • ne suppose pas que la largeur prise par le texte est connue ;
  • tient en un seul élément HTML.

Et tout ceci est rendu possible par flexbox !

La solution…

Partons du HTML suivant :

<div class="hr">Chapitre 1</div>  

Il suffit de quelques lignes de CSS pour obtenir l'effet voulu :

.hr {
    display: flex;
    align-items: center;
    margin: 1em 0;
}
.hr::before, .hr::after {
    content: '';
    flex: 1;
    margin: 0 .25em;
    border-bottom: 1px solid #000;
}

Les lignes de part et d'autre du texte sont créées par la bordure des pseudo-éléments. Ces derniers prennent toute la largeur disponible en gardant le texte centré horizontalement grâce à flex: 1;, et l'alignement vertical est permis par align-items: center;.
On ajoute ensuite des marges pour « décoller » les lignes du texte.

…ou presque

Cette solution serait parfaite si elle ne posait pas un soucis de compatibilité lié à flexbox. En effet, même si son support est assez répandu, sa syntaxe a évolué avec le temps. Ainsi même en ajoutant toutes les règles possibles, certains navigateurs seraient laissés de côté.

Toutefois, nous pouvons faire en sorte que ces derniers n'affichent que le texte centré (sans les lignes). Après quelques modifications, nous avons donc une solution flexible, moderne et élégamment dégradable. Pourquoi s'en priver !?

.hr {
    display: -webkit-box;
    display: -moz-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;

    -webkit-box-align: center;
    -moz-box-align: center;
    -webkit-align-items: center;
    -ms-flex-align: center;
    align-items: center;

    margin: 1em 0;

    text-align: center;
}
.hr::before, .hr::after {
    content: '';

    -webkit-box-flex: 1;
    -moz-box-flex: 1;
    -webkit-flex: 1;
    -ms-flex: 1;
    flex: 1;

    margin: 0 .25em;

    border-bottom: 1px solid #000;
}