Rot-Dialog: Rollbarkeit bei vielen Stapeln und echte Modalität

Beanstandung 1: .overlay bekommt overflow-y:auto, overscroll-behavior:
contain und justify-content:safe center, damit bei vielen Kandidaten-
Stapeln (Rot-Fall bietet alle Stapel der Sitzung an) keine Schaltfläche
mehr unerreichbar aus dem Bildschirm waechst, ohne dass die Seite
dahinter mitrollt oder sich die Optik bei wenigen Stapeln aendert.

Beanstandung 2: askForStack setzt inert auf die Geschwisterelemente von
root, solange der Dialog offen ist, und hebt es beim Schliessen (ueber
jeden der drei Wege) nur fuer selbst gesetzte Elemente wieder auf.
Fokus kehrt nach dem Schliessen zum vorherigen Element zurueck statt auf
dem entfernten Dialog haengen zu bleiben.
This commit is contained in:
vchuser
2026-07-28 17:20:19 +02:00
parent e5f8952b95
commit 0c96743211
2 changed files with 32 additions and 1 deletions
+3 -1
View File
@@ -88,11 +88,13 @@ body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: safe center;
gap: 18px; gap: 18px;
padding: 24px; padding: 24px;
text-align: center; text-align: center;
z-index: 10; z-index: 10;
overflow-y: auto;
overscroll-behavior: contain;
} }
.overlay.green { background: var(--green); } .overlay.green { background: var(--green); }
+29
View File
@@ -38,6 +38,21 @@ export function askForStack(root, { spec, candidates }) {
overlay.querySelector('#read').textContent = describeReading(spec); overlay.querySelector('#read').textContent = describeReading(spec);
const choices = overlay.querySelector('#choices'); const choices = overlay.querySelector('#choices');
// Waehrend der Dialog offen ist, muss die Modalitaet, die per aria-modal
// behauptet wird, auch durchgesetzt werden: die Geschwisterelemente im
// Wurzelelement werden per inert unerreichbar (Tastatur, Zeigegeraet,
// Hilfsmittel). Elemente, die schon vorher inert waren, bleiben es -
// nur die selbst gesetzten inert-Markierungen werden spaeter entfernt.
const previouslyFocused = document.activeElement;
const madeInert = [];
for (const sibling of root.children) {
if (!sibling.hasAttribute('inert')) {
sibling.setAttribute('inert', '');
madeInert.push(sibling);
}
}
root.appendChild(overlay); root.appendChild(overlay);
return new Promise((resolve) => { return new Promise((resolve) => {
@@ -48,6 +63,20 @@ export function askForStack(root, { spec, candidates }) {
if (settled) return; if (settled) return;
settled = true; settled = true;
overlay.remove(); overlay.remove();
for (const sibling of madeInert) {
sibling.removeAttribute('inert');
}
// Fokus darf nicht auf dem entfernten Dialog-Element haengen bleiben -
// zurueck zu dem, was vorher den Fokus hatte, sofern das noch moeglich ist.
if (
previouslyFocused &&
typeof previouslyFocused.focus === 'function' &&
document.contains(previouslyFocused)
) {
previouslyFocused.focus();
} else {
root.focus?.();
}
resolve(result); resolve(result);
}; };