Fenêtre modale

Une fenêtre modale est une fenêtre qui apparaît par-dessus la fenêtre en cours du navigateur et qui prend le contrôle total du clavier et de l'écran.

Règles d’implémentation pour l’accessibilité

  • Une fenêtre modale porte le rôle aria role="dialog", l’attribut aria-modal="true" et un attribut aria-labelledby qui fait référence à l’id de l’élément contenant le titre de la boîte de dialogue.
  • Une fenêtre modale est considéré comme un changement de contexte. On veillera donc à commencer son contenu par un titre de niveau 1 (élément HTML h1).
  • Pour bien signifier l’ouverture d’un nouveau contexte, on veillera à opacifier le fond de la page pour bien faire apparaître la fenêtre modale.
  • À l’ouverture de la fenêtre modale, le focus sera positionné sur le premier élément pouvant recevoir le focus.
  • La fenêtre modale pourra être fermée en appuyant sur la touche [Echap] du clavier.
  • Après la fermeture de la fenêtre modale, le focus clavier se repositionne sur le bouton qui a provoqué l’ouverture de la fenêtre modale.
  • Pour relier le bouton qui ouvre la modale à la fenêtre modale, le bouton d’ouverture aura pour attribut aria-controls avec comme valeur l’id de la fenêtre modale.

Visuel

Voir la fenêtre modale accessible sur CodePen.

Extraits de code

Code HTML

<button id="btnActionModale" aria-controls="maModale">Modale</button>
<div id="maModale" role="dialog" aria-labelledby="titreModale" aria-describedby="descriptionModale">
  <h1 id="titreModale">Titre de la modale</h1>
  <p id="descriptionModale">Contenu de la modale</p>
  <button id="fermer" aria-label="Fermer la modale">&times;</button>
</div>

Code CSS

Pour adapter les couleurs, modifier les codes couleurs dans la déclaration :root.

:root {
    --BORDER-color: #b0aeae;
    --BUTTON-color: #215990;
    --BACKGROUND-color: #FFFFFF;
    --BODY-FADE-color: #000;
    --BOX-SHADOW: 0 19px 38px rgba(0, 0, 0, 0.12), 0 15px 12px rgba(0, 0, 0, 0.22);
    --FOCUS-color: #531AFF;
}
[role="dialog"] {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
  padding: 1em;
  max-height: 30vh;
  max-width: 50vw;
  background: var(--BACKGROUND-color);
  box-shadow: var(--BOX-SHADOW);
  display: none;
  border: 0;
}
[role="dialog"] * + * {
  margin-top: 0.5em;
}
[role="dialog"][open] {
  display: block;
}
button {
  cursor: pointer;
  background: var(--BUTTON-color);
  border: 0;
  color: #fff;
  padding: 0.25em 0.5em;
  font-size: 1em;
}
button:focus, 
button:hover  {
   outline: 3px solid var(--FOCUS-color);
}
#fermerModale {
  position: absolute;
  top: 0.5em;
  right: 0.5em;
  margin-top: 0;
  line-height: 1;
}
#opaque {
  background: var(--BODY-FADE-color);
  opacity: 0.75;
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  display: block;
}

Code javascript

var btnDeclencheur = document.getElementById('btnActionModale');
var fenetreModale = document.getElementById('maModale');
var fermerModale = document.getElementById('fermerModale');

function openDialog() {
  fenetreModale.setAttribute('open', '');
  fermerModale.focus();
  fermerModale.addEventListener('keydown', function(e) {
    if (e.keyCode == 9) {
      e.preventDefault();
    }
  });
  var opaque = document.createElement("div");
  opaque.id = 'opaque';
  document.body.insertBefore(opaque, fenetreModale);
  document.addEventListener('keydown', addESC);
}

function closeDialog() {
  fenetreModale.removeAttribute('open');
  btnDeclencheur.focus();      
  document.getElementById("opaque").remove();
  document.removeEventListener('keydown', addESC);
}

var addESC = function(e) {
  if (e.keyCode == 27) {
    closeDialog();
  } 
};

btnDeclencheur.addEventListener('click', function() {
  openDialog();
});

fermerModale.addEventListener('click', function() {
  closeDialog();
});