WCAG 2.1.2: Brak pułapki klawiaturowej

Kryterium Sukcesu 2.1.2 „Brak pułapki klawiaturowej” jest fundamentalnym wymogiem dostępności, który gwarantuje, że użytkownicy nawigujący stroną za pomocą samej klawiatury nigdy nie zostaną uwięzieni w konkretnym elemencie lub sekcji strony. Oznacza to, że po przeniesieniu fokusu do dowolnego komponentu za pomocą klawiatury, użytkownik musi mieć możliwość przeniesienia fokusu z tego komponentu również za pomocą wyłącznie klawiatury, bez konieczności użycia myszy czy innych urządzeń wskazujących.

To kryterium ma na celu zapewnienie płynnej i intuicyjnej nawigacji dla wszystkich użytkowników, którzy polegają na klawiaturze, umożliwiając im swobodne przemieszczanie się po całej zawartości strony.

Dlaczego to ma znaczenie?

Niezgodność z tym kryterium może całkowicie uniemożliwić lub znacząco utrudnić korzystanie ze strony internetowej dla wielu grup użytkowników. Pułapka klawiaturowa sprawia, że część lub całość treści staje się niedostępna. Kryterium to jest szczególnie ważne dla:

  • Użytkowników z niepełnosprawnościami ruchowymi: Osoby, które nie są w stanie używać myszy z powodu drżenia rąk, osłabienia mięśni, paraliżu lub innych ograniczeń, często polegają wyłącznie na klawiaturze do interakcji z interfejsem. Pułapka klawiaturowa może całkowicie zablokować im dalszą nawigację.
  • Użytkowników niewidomych lub słabowidzących: Osoby te często korzystają z czytników ekranu, które do nawigacji i interakcji z elementami strony wykorzystują klawiaturę. Jeśli fokus zostanie uwięziony, czytnik ekranu nie będzie w stanie odczytać pozostałej zawartości, a użytkownik nie będzie mógł opuścić uwięzionego elementu.
  • Użytkowników z niepełnosprawnościami poznawczymi: Nagłe zablokowanie fokusu bez wyraźnej metody wyjścia może być frustrujące i dezorientujące, prowadząc do rezygnacji z korzystania ze strony.
  • Użytkowników z tymczasowymi ograniczeniami: Osoby z urazem ręki, niedziałającą myszą lub korzystające z alternatywnych urządzeń wejściowych, które emulują klawiaturę, również zostaną dotknięte.
  • Użytkowników preferujących nawigację klawiaturą: Wielu zaawansowanych użytkowników i deweloperów preferuje klawiaturę ze względu na jej efektywność i szybkość.

Kryterium Sukcesu 2.1.2: Brak pułapki klawiaturowej (Poziom A)

Oficjalne sformułowanie kryterium sukcesu 2.1.2 z WCAG 2.1:

Jeżeli interfejs klawiatury jest używany do przeniesienia fokusu do komponentu strony, to fokus może zostać przeniesiony z tego komponentu za pomocą wyłącznie interfejsu klawiatury, a jeżeli wymaga to użycia czegoś więcej niż niemodyfikowanych klawiszy strzałek lub klawiszy tabulacji albo innych standardowych metod wyjścia, użytkownik jest informowany o metodzie przeniesienia fokusu.

Kluczowe aspekty tego sformułowania to:

  • „wyłącznie interfejsu klawiatury”: Oznacza to, że mysz lub inne urządzenia wskazujące nie mogą być wymagane do opuszczenia komponentu.
  • „niemodyfikowanych klawiszy strzałek lub klawiszy tabulacji albo innych standardowych metod wyjścia”: W większości przypadków klawisz Tab/Shift+Tab powinien wystarczyć do poruszania się po elementach, a klawisz Escape do zamykania nakładek.
  • „użytkownik jest informowany o metodzie przeniesienia fokusu”: Jeśli wymagane jest użycie niestandardowej kombinacji klawiszy (np. Ctrl+F6, aby wyjść z zagnieżdżonej aplikacji), informacja o tym powinna być wyraźnie podana użytkownikowi, zanim fokus zostanie przeniesiony do tego komponentu lub gdy jest on aktywny.

Jak osiągnąć zgodność? Praktyczne wytyczne

Aby spełnić kryterium 2.1.2, należy zwrócić uwagę na zarządzanie fokusem w interaktywnych komponentach strony:

  • Zawsze zapewnij mechanizm wyjścia za pomocą klawiatury:

    Dla każdego elementu, który może przyjąć fokus, upewnij się, że klawisz Tab (lub Shift+Tab) przenosi fokus do następnego/poprzedniego elementu na stronie lub poza dany komponent. W przypadku nakładek (np. modali, okien dialogowych), zawsze zapewnij możliwość zamknięcia ich za pomocą klawisza Escape oraz dostępnego klawiaturowo przycisku zamknięcia.

  • Modale i okna dialogowe:

    Chociaż modale często celowo zatrzymują fokus wewnątrz, aby zapobiec nawigacji po tle, muszą również zapewnić jasny, klawiaturowo dostępny sposób na ich zamknięcie i przywrócenie fokusu do elementu, który je otworzył. Standardową praktyką jest umożliwienie zamknięcia modalu klawiszem Esc, a także zapewnienie widocznego przycisku "Zamknij" dostępnego tabulatorem.

  • Wbudowane widżety i aplikacje (np. mapy, odtwarzacze multimedialne, gry):

    Jeśli wbudowany komponent (często w <iframe>) przechwytuje fokus, musi istnieć sposób, aby użytkownik mógł opuścić ten komponent za pomocą klawiatury. Jeśli wymaga to niestandardowych kombinacji klawiszy, informacja o tym musi być wyraźnie widoczna i dostępna dla użytkownika.

  • Skomplikowane komponenty interfejsu:

    Dla komponentów takich jak rozwijane menu, akordeony czy zakładki, upewnij się, że fokus może swobodnie wchodzić do ich zawartości i wychodzić z niej, a także poruszać się między wewnętrznymi elementami (np. za pomocą klawiszy strzałek), bez blokowania.

  • Testowanie wyłącznie klawiaturą:

    Najlepszym sposobem na sprawdzenie zgodności jest odłożenie myszy i spróbowanie nawigacji po całej stronie za pomocą tylko klawiatury (klawiszy Tab, Shift+Tab, Enter, Escape, spacja i strzałki). Spróbuj otworzyć i zamknąć wszystkie interaktywne elementy, wypełnić formularze i aktywować przyciski.

Przykłady prawidłowych i nieprawidłowych implementacji

Przykład 1: Prawidłowe zarządzanie fokusem w modalu

Ten przykład pokazuje modal, który po otwarciu przenosi fokus do swojego pierwszego interaktywnego elementu, pozwala użytkownikowi nawigować wewnątrz klawiaturowo i zapewnia sposoby na jego zamknięcie (klawisz Escape oraz przycisk „Zamknij”).

<!-- HTML -->
<button id="openModalBtn">Otwórz Modal</button>

<div id="myModal" class="modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle" style="display: none;">
  <div class="modal-content" tabindex="-1">
    <h2 id="modalTitle">Tytuł Modalu</h2>
    <p>To jest treść modalu. Naciśnij Escape lub kliknij "Zamknij", aby wyjść.</p>
    <input type="text" placeholder="Pole tekstowe"><br>
    <button>Akcja 1</button>
    <button id="closeModalBtn">Zamknij</button>
  </div>
</div>

<!-- CSS -->
<style>
  .modal {
    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    background-color: rgba(0,0,0,0.5); display: flex;
    justify-content: center; align-items: center;
  }
  .modal-content {
    background-color: white; padding: 20px; border-radius: 5px;
    min-width: 300px; max-width: 500px;
  }
  .modal-content input, .modal-content button {
    margin: 5px 0;
  }
</style>

<!-- JavaScript -->
<script>
  const openModalBtn = document.getElementById('openModalBtn');
  const closeModalBtn = document.getElementById('closeModalBtn');
  const myModal = document.getElementById('myModal');
  const modalContent = myModal.querySelector('.modal-content');
  let previouslyFocusedElement;

  function trapFocus(element) {
    const focusableElements = element.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
    const firstFocusableElement = focusableElements[0];
    const lastFocusableElement = focusableElements[focusableElements.length - 1];

    firstFocusableElement.focus();

    element.addEventListener('keydown', function(e) {
      if (e.key === 'Tab') {
        if (e.shiftKey) { // shift + tab
          if (document.activeElement === firstFocusableElement) {
            lastFocusableElement.focus();
            e.preventDefault();
          }
        } else { // tab
          if (document.activeElement === lastFocusableElement) {
            firstFocusableElement.focus();
            e.preventDefault();
          }
        }
      }
    });
  }

  openModalBtn.addEventListener('click', () => {
    previouslyFocusedElement = document.activeElement;
    myModal.style.display = 'flex';
    trapFocus(modalContent);
  });

  function closeMyModal() {
    myModal.style.display = 'none';
    if (previouslyFocusedElement) {
      previouslyFocusedElement.focus();
    }
  }

  closeModalBtn.addEventListener('click', closeMyModal);

  document.addEventListener('keydown', (e) => {
    if (e.key === 'Escape' && myModal.style.display === 'flex') {
      closeMyModal();
    }
  });
</script>

Przykład 2: Nieprawidłowa pułapka klawiaturowa w modalu

Ten modal otwierany jest poprawnie, ale użytkownik klawiatury nie ma możliwości jego zamknięcia. Klawisz Escape nie działa, a przycisk "Zamknij" nie jest dostępny poprzez nawigację klawiszem Tab (np. jest ukryty lub ma tabindex="-1" bez logiki zarządzania fokusem).

<!-- HTML -->
<button id="openBadModalBtn">Otwórz Zły Modal</button>

<div id="badModal" class="modal" style="display: none;">
  <div class="modal-content">
    <h2>Zablokowany Modal</h2>
    <p>Ta treść jest tylko dla Ciebie! Nie możesz mnie opuścić.</p>
    <input type="text" placeholder="Pole tekstowe"><br>
    <!-- Brak dostępnego klawiaturowo przycisku zamknięcia -->
    <button style="display: none;">Niewidoczny Zamknij (niedostępny klawiaturowo)</button>
  </div>
</div>

<!-- CSS -->
<style>
  /* Używa tych samych stylów modalnych co powyżej */
</style>

<!-- JavaScript -->
<script>
  const openBadModalBtn = document.getElementById('openBadModalBtn');
  const badModal = document.getElementById('badModal');

  openBadModalBtn.addEventListener('click', () => {
    badModal.style.display = 'flex';
    // Brak logiki zarządzania fokusem, brak obsługi Escape
    // Fokus może krążyć w kółko w modalu, bez możliwości wyjścia
    const firstInput = badModal.querySelector('input');
    if (firstInput) firstInput.focus();
  });
  // Brak listenera dla Escape, brak dostępnego przycisku zamknięcia
</script>

Przykład 3: Prawidłowe zarządzanie fokusem w osadzonym komponencie

Ten przykład pokazuje, jak osadzony komponent (np. gra lub niestandardowa aplikacja webowa w iframe) może informować użytkownika o specjalnej metodzie wyjścia, jeśli klawisz Tab nie jest wystarczający.

<!-- HTML -->
<div role="region" aria-label="Interaktywna gra">
  <p>Aby opuścić grę, naciśnij <kbd>Ctrl</kbd> + <kbd>G</kbd>.</p>
  <iframe srcdoc="<!DOCTYPE html><html><head><title>Gra</title></head><body style='margin:0;display:flex;flex-direction:column;justify-content:center;align-items:center;height:100vh;background:#eee;'><h3>Witaj w grze!</h3><button>Start</button><p>Nawiguj klawiszami strzałek.</p></body></html>" 
          title="Przykładowa gra" width="400" height="300"></iframe>
  <button>Kolejny element na stronie</button>
</div>

<!-- JavaScript (przykładowa implementacja dla ramki - często zarządzana wewnątrz ramki) -->
<script>
  // Ta logika musiałaby być zaimplementowana wewnątrz iframe LUB na stronie głównej,
  // aby przechwytywać klawisze, gdy fokus jest w iframie (co jest skomplikowane ze względów bezpieczeństwa).
  // Zazwyczaj to komponent w iframie jest odpowiedzialny za własne zarządzanie focusem
  // i dostarczanie informacji o wyjściu.
  // Dla uproszczenia, informacja tekstowa jest kluczowa dla SC 2.1.2.
  document.addEventListener('keydown', function(event) {
    if (event.ctrlKey && event.key === 'g' && document.activeElement.tagName === 'IFRAME') {
      alert('Opuszczono grę za pomocą Ctrl+G!');
      document.getElementById('nextElementBtn').focus(); // Przenieś fokus poza iframe
      event.preventDefault();
    }
  });
  // Zakładając, że iframem można nawigować tabulatorem, a po ostatnim elemencie w iframie
  // fokus przenosi się do następnego elementu na stronie głównej, chyba że aplikacja
  // wewnętrzna celowo blokuje to i wymaga specjalnej kombinacji klawiszy, która musi być opisana.
  // Powyższy przykład ilustruje, jak poinformować użytkownika, gdy specjalna kombinacja jest wymagana.
</script>

Najlepsze praktyki i typowe pułapki

Najlepsze praktyki:

  • Używaj standardowych elementów HTML i wzorców ARIA: Wiele wbudowanych elementów HTML (np. <dialog>) domyślnie zapewnia prawidłowe zachowanie fokusu. Używając wzorców ARIA (np. role="dialog", aria-modal="true"), możesz wzmocnić ich dostępność i zapewnić poprawne działanie czytników ekranu.
  • Testuj z samą klawiaturą od wczesnych etapów rozwoju: Regularne testowanie nawigacji klawiaturowej pozwoli wykryć pułapki na wczesnym etapie, zanim staną się trudniejsze do naprawienia.
  • Pamiętaj o zarządzaniu fokusem przy dynamicznej zawartości: Jeśli treść jest dodawana, usuwana lub ukrywana/pokazywana (np. w przypadku wiadomości o błędach, powiadomień, rozwijanych sekcji), upewnij się, że fokus jest przenoszony w logiczne miejsce i nie zostaje uwięziony lub zagubiony.
  • Zapewnij wizualny wskaźnik fokusu: Chociaż nie jest to bezpośrednio wymagane przez 2.1.2, widoczny wskaźnik fokusu (:focus stylizacja) jest kluczowy dla wszystkich użytkowników klawiatury, aby wiedzieli, gdzie aktualnie znajduje się ich fokus.

Typowe pułapki:

  • Niestandardowe widżety bez odpowiedniej obsługi zdarzeń klawiatury: Tworzenie niestandardowych elementów interaktywnych (np. suwaków, selektorów dat) bez implementacji odpowiedniej obsługi klawiszy Tab, Shift+Tab, Escape i strzałek często prowadzi do pułapek.
  • Zapominanie o klawiszu Escape dla modalnych okien: Użytkownicy klawiatury oczekują, że klawisz Escape zamknie większość nakładek i okien dialogowych. Brak tej funkcjonalności jest częstą pułapką.
  • Zagnieżdżone elementy lub iframes, które przechwytują fokus: Wbudowane treści lub zagnieżdżone aplikacje mogą niezamierzenie pułapkować fokus, jeśli nie ma mechanizmu do jego opuszczenia.
  • Przeładowywanie stron lub zmiany zawartości bez resetowania fokusu: Jeśli nowa zawartość ładuje się dynamicznie, a fokus nie jest prawidłowo zarządzany, może on zostać uwięziony w nieistniejącym już elemencie lub w miejscu, z którego nie ma wyjścia.

Zasoby dodatkowe

Przegląd prywatności

Ta strona korzysta z ciasteczek, aby zapewnić Ci najlepszą możliwą obsługę. Informacje o ciasteczkach są przechowywane w przeglądarce i wykonują funkcje takie jak rozpoznawanie Cię po powrocie na naszą stronę internetową i pomaganie naszemu zespołowi w zrozumieniu, które sekcje witryny są dla Ciebie najbardziej interesujące i przydatne.