Hvor mange drop-down-menyer, dialoger og modaler har du laget for en web-app? Og hvor mange av dem hadde riktige ARIA-attributter, fungerte godt for de som ikke ser, kunne lukkes med “klikk utenfor” eller escape, OG var fri for rar scrolle-oppførsel, glitchy gjennomsiktig bakgrunn og andre finurligheter? Vel, det er kanskje lettere enn du tror.

En eksempel-modal

La oss lage en liten modal for å illustrere poenget. I tillegg til markupen er det bittelitt JavaScript som bytter display.modal og .backdrop-elementene mellom "none" og "block".

<div id="modal1" class="ex">
  <button>Vis meg en modal!</button>
  <div class="backdrop" style="display: none"></div>
  <div class="modal" style="display: none">
    <h2>Hei der!</h2>
    <p>
      Kan vi interessere deg i noen spennende valg om hvilke tredjeparter vi
      skal lekke dataene dine til med en hjertevarmende tekst om hvor dypt og
      inderlig vi bryr oss om personvernet ditt?
    </p>
    <p>
      <button>Nei takk</button>
    </p>
  </div>
</div>

CSS:

.backdrop {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.3);
}

.modal {
  background: #fff;
  padding: 40px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  max-width: 500px;
  width: 90vw;
  max-height: 500px;
}

Vakkert. Hva mer kan man ønske seg? Vel, flere ting.

Prøv å åpne modalen og deretter trykk tab for å navigere deg rundt. Heldigvis for meg er kodemaker.no bygget fornuftig nok til at den øvelsen starter lovende: Du tabber deg gjennom klikkbare elementer i modalen. Men så går det utforbakke: tab fortsetter å navigere i lenker bak modalen. Ikke særlig modalt, spør du meg.

Når du er forsynt med modalen og vil lukke den viser neste problem seg: museklikk på backdropet har ingen effekt, ei heller escape-tasten. Det er mye jobb å lage gode modaler. Ditt eneste valg er dessverre å trykke “Nei takk”.

Skulle du være så uheldig å lese denne artikkelen på en skjermleser så trenger jeg ikke å forklare deg hvilke andre problemer denne løsningen byr på.

En bedre modal

Det viser seg at nettleseren allerede har løst de fleste av disse problemene for oss. La oss nå gjøre det jeg liker aller best med jobben min: løse problemer ved å fjerne kode.

HTML-en er nesten helt lik, bortsett fra at selve modalen nå er en dialog, ikke en div, og div-en som laget backdropet er helt borte:

<div id="modal2" class="ex">
  <button>Vis meg en modal!</button>
  <dialog>
    <h2>Hei der!</h2>
    <p>
      Kan vi interessere deg i noen spennende valg om hvilke tredjeparter vi
      skal lekke dataene dine til med en hjertevarmende tekst om hvor dypt og
      inderlig vi bryr oss om personvernet ditt?
    </p>
    <p>
      <button>Nei takk</button>
    </p>
  </dialog>
</div>

Uten at vi legger til noe CSS ser det sånn ut:

Hei der!

Kan vi interessere deg i noen spennende valg om hvilke tredjeparter vi skal lekke dataene dine til med en hjertevarmende tekst om hvor dypt og inderlig vi bryr oss om personvernet ditt?

Det blir ikke rålekkert, men det ser ut som en modal, og ikke minst oppfører den seg akkurat slik en modal skal: Den ligger over det øvrige innholdet, bakgrunnen er grået ut, tastatur-fokus er begrenset til modalen, escape-tasten lukker den, og skjermlesere får riktig informasjon om at dette er en modal dialog. Ikke verst!

Alt dette med et dialog-element og følgende JavaScript:

var el = document.getElementById("modal2");
var modal = el.querySelector("dialog");

function toggle() {
  if (modal.open) {
    modal.close();
  } else {
    modal.showModal();
  }
}

el.querySelectorAll("button")
  .forEach(b => b.addEventListener("click", toggle));

For å stramme opp det visuelle kan vi legge til litt CSS for selve boksen. Backdropet er et pseudo-element, og kan styles etter alle kunstens regler:

.modal2 {
  background: #fff;
  padding: 40px;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  max-width: 500px;
  width: 90vw;
  max-height: 500px;
}

.modal2::backdrop {
  background: #591e1e66;
}

Hei der!

Kan vi interessere deg i noen spennende valg om hvilke tredjeparter vi skal lekke dataene dine til med en hjertevarmende tekst om hvor dypt og inderlig vi bryr oss om personvernet ditt?

Snasent! Legg merke til det helraffe rød-tinta backdropet.

Flere lukkemuskler

Jeg fristet tidligere med muligheten for å klikke på backdropet for å lukke modalen, men sånn er det enn så lenge ikke. Dette er funksjonalitet vi ikke får ut av boksen, men i klassisk W3C-API-stil så kan vi få det til, om enn på noe krøkkete vis.

Siden backdropet er et pseudo-element er det dessverre usynlig for DOM-en. I DOM-ens øyne dekker modalen hele skjermen når den er åpen. Dersom vi flytter all padding fra selve modalen til en div inne i den vil alle klikk rett på selve dialog-elementet være klikk på backdroppet.

Oppdatert HTML:

<div id="modal4" class="ex">
  <button>Vis meg en modal!</button>
  <dialog class="modal3">
    <div class="modal3-content">
      <h2>Hei der!</h2>
      <p>
        Kan vi interessere deg i noen spennende valg om hvilke tredjeparter vi
        skal lekke dataene dine til med en hjertevarmende tekst om hvor dypt og
        inderlig vi bryr oss om personvernet ditt?
      </p>
      <p>
        <button>Nei takk</button>
      </p>
    </div>
  </dialog>
</div>

Og CSS:

.modal3 {
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  max-width: 500px;
  width: 90vw;
  max-height: 500px;
}

.modal3-content {
  background: #fff;
  padding: 40px;
}

Og JavaScript:

document
  .querySelector("#modal4 dialog")
  .addEventListener("click", function (e) {
    if (e.target.tagName == "DIALOG") {
      e.target.close();
    }
  });

Et voila!

Hei der!

Kan vi interessere deg i noen spennende valg om hvilke tredjeparter vi skal lekke dataene dine til med en hjertevarmende tekst om hvor dypt og inderlig vi bryr oss om personvernet ditt?

Dette er bare noen av tingene dialog kan gjøre for deg. Den kan også brukes til ikke-modale dialoger, sjekk MDN sin referanse for flere detaljer.