Focus trap
Шаблон, който задържа фокуса на клавиатурата в рамките на модален диалог, докато той е отворен — предотвратява излизането на Tab обратно в документа зад него и възстановява фокуса върху елемента, отворил диалога, при неговото затваряне.
Focus trap (капан за фокус) е съзнателно ограничение на навигацията с клавиатура: докато модален диалог е отворен, Tab циклично преминава само между фокусируемите елементи вътре в диалога. Shift+Tab действа в обратна посока. Потребителят не може чрез Tab да се върне в (визуално блокираната) страница зад модала, докато изрично не го затвори.
Задържането на фокуса е задължително за достъпните модални диалози. Без него потребителите с клавиатура и екранен четец попадат на невидимо съдържание на страницата, което не могат нито да видят, нито да напуснат.
Защо е необходимо
Модалният диалог е визуално представен като слой върху страницата. Намерението — недвусмислено — е потребителят да взаимодейства с модала, докато приключи, след което да се върне към страницата. За потребителите на мишка това е интуитивно: щракването извън модала не прави нищо (или го затваря); щракването вътре достига до контролите на модала.
Без focus trap потребителите на клавиатура получават непоследователно изживяване:
- Модалът се отваря. Фокусът се премества (или трябва да се премести) към първия фокусируем елемент вътре.
- Потребителят натиска Tab. Фокусът преминава към следващия фокусируем елемент вътре в модала.
- Потребителят продължава да натиска Tab. Фокусът накрая достига до последния фокусируем елемент в модала.
- Още едно натискане на Tab. Без капан фокусът прескача към следващия фокусируем елемент в документа — намиращ се зад модала, невидим за потребителя.
Единственият сигнал, че това се е случило, е изчезването на индикатора за фокус в модала. Потребителят няма представа къде е фокусът му.
Пълният шаблон за модален диалог
Пълноценният достъпен модал включва:
- Фокусът се премества в модала при отварянето му — обикновено към първия фокусируем елемент или към заглавието на модала (ако заглавието има
tabindex="-1"за програмно фокусиране). - Фокусът е задържан вътре в модала: Tab от последния елемент прескача към първия; Shift+Tab от първия прескача към последния.
- Escape затваря модала и връща фокуса към елемента-тригер, отворил го (не към тялото на документа).
- Щракване извън модала го затваря — незадължително поведение; не всички модали го прилагат, но ако вашият го прави, фокусът трябва да е задържан докато модалът е отворен.
role="dialog"заедно сaria-modal="true"върху елемента на модала, сaria-labelledby, сочещо към заглавието му.
Имплементации
Най-цитираната библиотека е focus-trap (npm: focus-trap, focus-trap-react, focus-trap-vue) — малка, без зависимости, обработва всички гранични случаи (прескача невидими елементи, интегрира се с inert, възстановява фокуса при затваряне).
Съвременният браузърен примитив е <dialog> с dialog.showModal(), който автоматично задържа фокуса и обработва Escape. Поддръжката от браузърите вече е достатъчно широка, за да се използва като изходна базова линия.
Антишаблон: „капанът, който не освобождава”
Focus trap трябва да освободи фокуса при затваряне на модала. Най-честата грешка в имплементацията е пропускането на възстановяването на фокуса към оригиналния тригер — фокусът тогава попада върху тялото на документа, което екранните четци обявяват като нищо. Потребителят е оставен в тишина и трябва да започне да натиска Tab от началото на страницата.