Comment empêcher le défilement d'une page lorsqu'une boîte de dialogue est ouverte
L’ouverture d’une boîte de dialogue modale devrait concentrer l’attention de l’utilisateur sur cette boîte de dialogue, et non lui permettre de faire défiler la page en arrière-plan. Pourtant, empêcher le défilement en arrière-plan reste étonnamment difficile, en particulier lorsque vous avez besoin d’un comportement de verrouillage du défilement fiable sur iOS Safari.
L’élément <dialog> avec showModal() gère automatiquement le blocage des interactions. Le navigateur marque tout ce qui se trouve en dehors de la boîte de dialogue comme inert, empêchant les clics et la navigation au clavier. Mais la prévention du défilement ? C’est un problème distinct que la plateforme ne résout pas complètement.
Cet article couvre les principales approches pour les implémentations de boîtes de dialogue modales avec verrouillage du défilement, leurs compromis, et pourquoi aucune solution unique ne fonctionne parfaitement partout.
Points clés à retenir
- La méthode
showModal()bloque les interactions mais n’empêche pas le défilement en arrière-plan - La propriété CSS
overflow: hiddenfonctionne sur ordinateur mais échoue sur iOS Safari - La technique du body fixe avec restauration de la position de défilement offre la solution multi-navigateurs la plus fiable
- Utilisez
overscroll-behavior: containen complément d’autres méthodes pour empêcher le chaînage du défilement - Gardez toujours votre boîte de dialogue défilable avec
max-heightetoverflow-y: autopour l’accessibilité
Ce que showModal() fait et ne fait pas
Lorsque vous appelez dialog.showModal(), le navigateur :
- Affiche la boîte de dialogue dans la couche supérieure
- Crée un pseudo-élément
::backdrop - Rend le contenu en arrière-plan inerte (bloque les interactions par pointeur et clavier)
- Piège le focus dans la boîte de dialogue
Ce qu’il ne fait pas : empêcher de manière fiable le défilement en arrière-plan sur tous les navigateurs et appareils. Sur certaines plateformes, notamment mobiles, les utilisateurs peuvent toujours faire défiler la page à l’aide de gestes tactiles ou de la molette de défilement.
L’approche CSS simple : overflow: hidden
La solution la plus courante utilise le sélecteur :has() pour détecter une boîte de dialogue ouverte :
body:has(dialog[open]) {
overflow: hidden;
}
Cela fonctionne sur la plupart des navigateurs de bureau. La page devient non défilable tant que la boîte de dialogue est ouverte.
Le piège : Cette approche n’est pas fiable sur iOS Safari. Le défilement tactile contourne souvent overflow: hidden sur le body, permettant aux utilisateurs de faire défiler l’arrière-plan malgré tout. Si votre audience inclut des utilisateurs de Safari mobile, vous aurez besoin de quelque chose de plus robuste.
La technique du body fixe pour une fiabilité multi-navigateurs
La solution multi-navigateurs la plus fiable, y compris pour le verrouillage du défilement sur iOS Safari, utilise JavaScript pour fixer le body en place :
let scrollPosition = 0;
function lockScroll() {
scrollPosition = window.scrollY;
document.body.style.position = 'fixed';
document.body.style.top = `-${scrollPosition}px`;
document.body.style.width = '100%';
}
function unlockScroll() {
document.body.style.position = '';
document.body.style.top = '';
document.body.style.width = '';
window.scrollTo(0, scrollPosition);
}
Appelez lockScroll() lors de l’ouverture de la boîte de dialogue et unlockScroll() lors de sa fermeture.
Cette technique stocke la position de défilement, fixe le body pour qu’il ne puisse pas défiler, puis restaure tout à la fermeture. Elle gère le défilement tactile sur iOS car le body ne peut littéralement pas bouger.
Compromis : Vous pouvez observer un décalage de mise en page si la barre de défilement disparaît. Compensez en ajoutant un padding-right égal à la largeur de la barre de défilement lors du verrouillage.
CSS overscroll-behavior pour le chaînage du défilement
La propriété overscroll-behavior empêche le chaînage du défilement, c’est-à-dire lorsque le défilement à l’intérieur d’un élément provoque le défilement d’un parent après avoir atteint la limite.
dialog {
overscroll-behavior: contain;
}
dialog::backdrop {
overscroll-behavior: contain;
}
Les versions récentes de Chromium (fin 2025+) ont amélioré ce comportement, le faisant fonctionner même sur des conteneurs non défilables. Cela aide au verrouillage du défilement des boîtes de dialogue HTML dans Chrome, mais les autres navigateurs ne sont pas encore tous à jour.
Important : Les solutions modales CSS overscroll-behavior empêchent le chaînage du défilement, pas le défilement lui-même. Si l’utilisateur fait défiler directement sur le backdrop ou le body, overscroll-behavior ne l’arrêtera pas. Utilisez ceci en complément d’autres techniques, pas en remplacement.
Discover how at OpenReplay.com.
Les particularités d’iOS Safari à connaître
iOS Safari présente des défis uniques pour empêcher le défilement en arrière-plan dans les implémentations modales :
overflow: hiddensur le body ne bloque pas de manière fiable le défilement tactile- L’effet de rebond élastique peut déclencher un mouvement en arrière-plan
- L’apparition du clavier virtuel peut provoquer un comportement de défilement inattendu
La technique du body fixe reste la solution la plus fiable. Certains développeurs ajoutent également touch-action: none à l’élément backdrop (pas à la boîte de dialogue elle-même), bien que cela puisse interférer avec le défilement à l’intérieur de la boîte de dialogue si appliqué trop largement.
Gardez votre boîte de dialogue défilable
Un détail crucial : si le contenu de votre boîte de dialogue dépasse la hauteur de la fenêtre d’affichage, la boîte de dialogue elle-même doit défiler. Définissez des valeurs appropriées pour max-height et overflow-y: auto sur la boîte de dialogue :
dialog {
max-height: 90vh;
overflow-y: auto;
}
Bloquer tout défilement crée des problèmes d’accessibilité. Les utilisateurs doivent pouvoir accéder à tout le contenu de la boîte de dialogue.
Une remarque sur l’API Popover
L’API Popover existe pour les superpositions légères mais n’est pas un remplacement direct pour les boîtes de dialogue modales. Les popovers ne bloquent pas les interactions en arrière-plan de la même manière, et le comportement de verrouillage du défilement diffère. Pour de véritables expériences modales nécessitant un verrouillage du défilement, restez avec <dialog> et showModal().
Choisir votre approche
Pour les applications destinées uniquement aux ordinateurs de bureau, l’approche CSS :has() avec overflow: hidden suffit souvent. Pour une fiabilité multi-navigateurs, en particulier sur iOS Safari, utilisez la technique du body fixe avec restauration de la position de défilement. Superposez overscroll-behavior: contain pour empêcher le chaînage du défilement dans les navigateurs compatibles.
Conclusion
Aucune solution ne fonctionne parfaitement partout. La technique du body fixe offre le verrouillage du défilement multi-navigateurs le plus fiable, en particulier pour iOS Safari. Combinez-la avec overscroll-behavior: contain pour une protection supplémentaire contre le chaînage du défilement dans les navigateurs Chromium. Testez sur de vrais appareils, en particulier iOS Safari, et acceptez que certains cas limites puissent nécessiter des compromis.
FAQ
iOS Safari gère le défilement tactile différemment des navigateurs de bureau. Le système d'événements tactiles du navigateur peut contourner overflow hidden sur l'élément body, permettant le défilement en arrière-plan même lorsque la propriété est définie. La technique du body fixe fonctionne car elle positionne physiquement le body hors écran, rendant le défilement impossible plutôt que simplement masqué.
Oui, c'est possible. Lorsque la barre de défilement disparaît, le contenu peut se décaler pour remplir cet espace. Pour éviter cela, calculez la largeur de la barre de défilement et ajoutez un padding-right équivalent au body lors du verrouillage du défilement. Supprimez le padding lors du déverrouillage. Cela maintient une mise en page cohérente tout au long de l'interaction modale.
L'API Popover sert un objectif différent. Elle crée des superpositions légères sans bloquer les interactions en arrière-plan ni fournir les mêmes capacités de verrouillage du défilement. Pour de véritables expériences modales où les utilisateurs doivent interagir avec la boîte de dialogue avant de continuer, utilisez l'élément dialog avec showModal pour un piégeage de focus approprié et un comportement inerte.
Définissez overscroll-behavior contain sur la boîte de dialogue pour empêcher le chaînage du défilement vers l'arrière-plan. Assurez-vous que votre boîte de dialogue a max-height et overflow-y auto pour que le contenu interne défile correctement. Évitez d'appliquer touch-action none à toute la boîte de dialogue, car cela bloque le défilement légitime dans la zone de contenu modale.
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.