Понятия

Focus trap

Шаблон, който задържа фокуса на клавиатурата в рамките на модален диалог, докато той е отворен — предотвратява излизането на Tab обратно в документа зад него и възстановява фокуса върху елемента, отворил диалога, при неговото затваряне.

Focus trap (капан за фокус) е съзнателно ограничение на навигацията с клавиатура: докато модален диалог е отворен, Tab циклично преминава само между фокусируемите елементи вътре в диалога. Shift+Tab действа в обратна посока. Потребителят не може чрез Tab да се върне в (визуално блокираната) страница зад модала, докато изрично не го затвори.

Задържането на фокуса е задължително за достъпните модални диалози. Без него потребителите с клавиатура и екранен четец попадат на невидимо съдържание на страницата, което не могат нито да видят, нито да напуснат.

Защо е необходимо

Модалният диалог е визуално представен като слой върху страницата. Намерението — недвусмислено — е потребителят да взаимодейства с модала, докато приключи, след което да се върне към страницата. За потребителите на мишка това е интуитивно: щракването извън модала не прави нищо (или го затваря); щракването вътре достига до контролите на модала.

Без focus trap потребителите на клавиатура получават непоследователно изживяване:

  1. Модалът се отваря. Фокусът се премества (или трябва да се премести) към първия фокусируем елемент вътре.
  2. Потребителят натиска Tab. Фокусът преминава към следващия фокусируем елемент вътре в модала.
  3. Потребителят продължава да натиска Tab. Фокусът накрая достига до последния фокусируем елемент в модала.
  4. Още едно натискане на Tab. Без капан фокусът прескача към следващия фокусируем елемент в документа — намиращ се зад модала, невидим за потребителя.

Единственият сигнал, че това се е случило, е изчезването на индикатора за фокус в модала. Потребителят няма представа къде е фокусът му.

Пълният шаблон за модален диалог

Пълноценният достъпен модал включва:

  1. Фокусът се премества в модала при отварянето му — обикновено към първия фокусируем елемент или към заглавието на модала (ако заглавието има tabindex="-1" за програмно фокусиране).
  2. Фокусът е задържан вътре в модала: Tab от последния елемент прескача към първия; Shift+Tab от първия прескача към последния.
  3. Escape затваря модала и връща фокуса към елемента-тригер, отворил го (не към тялото на документа).
  4. Щракване извън модала го затваря — незадължително поведение; не всички модали го прилагат, но ако вашият го прави, фокусът трябва да е задържан докато модалът е отворен.
  5. 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 от началото на страницата.