Résoudre le problème d’ancre masquée par une barre de navigation sticky avec quelques lignes de CSS inline
Dans un document (blog, wiki, guide), cliquer sur un lien de note de bas de page ou sur le sommaire (TOC) fait défiler la page vers #some-id, alignant l’élément ciblé sur le haut de la fenêtre.
Mais lorsqu’une barre de navigation est fixée en haut avec position: sticky (ou fixed), le défilement place l’élément au sommet, tandis que le contenu se retrouve caché derrière la barre.
C’est un problème fréquent côté front‑end, mais il peut être déroutant pour les développeurs back‑end ou full‑stack qui se demandent pourquoi le lien fonctionne alors que le contenu reste invisible.
Dans cet article, je partage ma méthode préférée : ajouter quelques lignes de CSS inline sur la page concernée – la solution la plus simple et la plus immédiate.
Pourquoi cela se produit-il ?
Le comportement par défaut du navigateur est le suivant :
- Quand l’URL devient
…/page#target, - Le navigateur cherche l’élément `id="target``,
- Il fait défiler la page de façon à ce que le début de cet élément soit aligné sur le haut du conteneur de défilement (habituellement le haut de la fenêtre).
Avec une barre sticky, l’élément est rendu au-dessus de la fenêtre, donc il se retrouve caché sous la barre.

La solution la plus simple : scroll-margin-top (ajouter un espace au-dessus de l’élément)
En appliquant scroll-margin-top à l’élément ciblé, le navigateur essaie de placer l’élément en dessous de l’espace plutôt qu’au tout‑en‑haut.
Appliquer en CSS inline (recommandé)
Il suffit d’ajouter le bloc suivant dans le <head> ou le template de la page concernée.
<style>
:root { --sticky-nav-h: 64px; } /* ajuster à la hauteur réelle de la barre */
[id] { scroll-margin-top: calc(var(--sticky-nav-h) + 12px); }
</style>
--sticky-nav-h: hauteur de la barre sticky.+ 12px: marge supplémentaire pour éviter que l’élément ne soit trop proche de la barre (au choix).
Appliquer à
[id]globalement corrige automatiquement tous les liens d’ancre de la page. Si vous préférez limiter l’effet, vous pouvez restreindre la portée comme ci‑dessous.
Restreindre la portée pour plus de sécurité
Par exemple, appliquer uniquement dans la zone principale du contenu :
<style>
:root { --sticky-nav-h: 64px; }
.article [id] { scroll-margin-top: calc(var(--sticky-nav-h) + 12px); }
</style>
Ou, si le TOC cible surtout les h2/h3 :
<style>
:root { --sticky-nav-h: 64px; }
.article h2[id], .article h3[id] {
scroll-margin-top: calc(var(--sticky-nav-h) + 12px);
}
</style>
Option complémentaire : scroll-padding-top (espacement de sécurité du conteneur)
scroll-padding-top indique au conteneur de défilement qu’il doit disposer d’une zone de sécurité en haut pour les actions de défilement « snap » ou de fragments.
En pratique, scroll-margin-top est plus intuitif, mais combiner les deux peut renforcer la stabilité selon la mise en page.
<style>
:root { --sticky-nav-h: 64px; }
html { scroll-padding-top: calc(var(--sticky-nav-h) + 12px); }
</style>
- Utile pour corriger rapidement tous les liens d’ancre d’une page.
- Si vous avez besoin d’un contrôle précis sur un élément particulier, préférez
scroll-margin-top.
Astuce rétro pour la compatibilité : créer un faux offset avec ::before
Cette technique est vieille mais toujours valable. On insère un bloc invisible avant l’élément cible pour pousser son positionnement sous la barre.
<style>
:root { --sticky-nav-h: 64px; }
.anchor-target::before {
content: "";
display: block;
height: calc(var(--sticky-nav-h) + 12px);
margin-top: calc(-1 * (var(--sticky-nav-h) + 12px));
visibility: hidden;
pointer-events: none;
}
</style>
Exemple d’utilisation :
<h2 id="install" class="anchor-target">Installation</h2>
- Avantage : fonctionne de façon fiable, même dans les navigateurs plus anciens.
- Inconvénient : nécessite d’ajouter une classe et de gérer la sélection des éléments.
En général, commencez par scroll-margin-top. Si vous rencontrez des cas particuliers, utilisez la technique ::before.
JavaScript ? Pourquoi le CSS inline reste souvent préférable
Il est possible d’utiliser scrollIntoView() puis d’ajuster la position avec window.scrollBy(0, -navHeight). Cependant, le CSS est généralement plus simple.
- Pages de contenu statique (notes, TOC, etc.)
- Besoin d’une solution rapide sans toucher aux routes ou aux composants du framework
- Mainteneur non spécialiste du front‑end
Quelques lignes de <style> sont sans dépendances, faciles à déboguer et à annuler, ce qui les rend idéales pour les pages de documentation.
Checklist de production
- Déterminez la hauteur exacte de la barre sticky.
- Si la hauteur change en fonction du breakpoint, modifiez simplement
--sticky-nav-hà chaque breakpoint. - Ne pas trop étendre la portée.
- L’application globale
[id]est pratique, mais limiter à.article [id]est souvent préférable. - Ajoutez un peu de marge supplémentaire (+8 – 16 px) pour une meilleure perception.
- Donner exactement la hauteur de la barre peut parfois donner l’impression que l’élément est collé.
Conclusion : ma solution préférée
Ajoutez simplement le bloc suivant en CSS inline sur la page problématique.
<style>
:root { --sticky-nav-h: 64px; }
.article [id] { scroll-margin-top: calc(var(--sticky-nav-h) + 12px); }
</style>
Cette approche résout la plupart des cas de TOC, de notes de bas de page et de liens profonds. J’espère qu’elle sera utile aux développeurs qui souhaitent éliminer le problème d’ancre masquée par la barre sticky.
Articles connexes
- Pourquoi spécifier la largeur et la hauteur dans la balise <img> ?
- Même les ingénieurs back‑end doivent connaître ces 5 méthodes JS front‑end