WCAG 2.5.6: Równoczesne mechanizmy wprowadzania

WCAG 2.5.6: Równoczesne mechanizmy wprowadzania

Kryterium sukcesu WCAG 2.5.6, zatytułowane „Równoczesne mechanizmy wprowadzania” (Concurrent Input Mechanisms), należy do poziomu dostępności AAA. Jego głównym celem jest zapewnienie, że treści cyfrowe nie ograniczają użytkowników do korzystania tylko z jednego typu urządzenia wejściowego ani nie blokują możliwości jednoczesnego używania różnych metod interakcji. Oznacza to, że użytkownik powinien mieć swobodę wyboru preferowanego sposobu interakcji z interfejsem – czy to za pomocą myszy, klawiatury, ekranu dotykowego, rysika, poleceń głosowych czy innych technologii wspomagających.

Zasada ta ma kluczowe znaczenie dla stworzenia elastycznego i inkluzywnego środowiska cyfrowego, które dostosowuje się do różnorodnych potrzeb i możliwości użytkowników, zamiast narzucać im konkretne sposoby interakcji.

Dlaczego to jest ważne? (Wpływ na dostępność)

Zapewnienie obsługi równoczesnych mechanizmów wprowadzania ma fundamentalne znaczenie dla szerokiego grona użytkowników, którzy mogą napotykać bariery, gdy treść cyfrowa jest zaprojektowana pod kątem tylko jednego typu interakcji.

Użytkownicy dotknięci problemem:

  • Osoby z niepełnosprawnościami ruchowymi: Mogą mieć trudności z precyzyjnym posługiwaniem się myszą lub używać alternatywnych urządzeń wskazujących (np. joystick, sterowanie głową, śledzenie wzroku), które często emulują klawiaturę lub mysz w sposób niepełny. Wymagają one elastyczności w zakresie wprowadzania danych.
  • Osoby z niepełnosprawnościami poznawczymi: Niektórzy użytkownicy mogą preferować lub potrzebować określonych metod wprowadzania, które są dla nich mniej obciążające poznawczo lub prostsze w użyciu.
  • Osoby z niepełnosprawnościami tymczasowymi: Na przykład osoba ze złamaną ręką może nie być w stanie używać myszy i polegać wyłącznie na klawiaturze lub sterowaniu głosowym.
  • Użytkownicy technologii wspomagających: Osoby korzystające z oprogramowania do rozpoznawania mowy (np. Dragon NaturallySpeaking) lub wirtualnych klawiatur polegają na dostępności interakcji poprzez tekstowe polecenia lub emulację klawiatury.
  • Użytkownicy preferujący różne tryby: Wiele osób pracuje na urządzeniach hybrydowych (laptopach z ekranem dotykowym) i naturalnie przełącza się między klawiaturą, myszą a dotykiem w zależności od kontekstu i preferencji. Projektowanie, które wymusza jeden tryb, jest dla nich frustrujące i niewygodne.

Zapewnienie obsługi wielu metod wprowadzania danych sprawia, że interfejs jest bardziej robustny, elastyczny i użyteczny dla wszystkich, niezależnie od ich indywidualnych zdolności, preferencji czy używanego sprzętu.

Kryterium sukcesu i wymagania

Oficjalne brzmienie kryterium sukcesu 2.5.6 to:

Treść nie ogranicza użycia jednoczesnych mechanizmów wprowadzania, ani nie ogranicza do jednego trybu wprowadzania, z wyjątkiem sytuacji, gdy jest to niezbędne.

Kluczowe aspekty tego kryterium:

  • Równoczesne mechanizmy wprowadzania: Oznacza to, że użytkownik powinien mieć możliwość używania wielu typów urządzeń wejściowych (np. klawiatury, myszy, ekranu dotykowego, rysika, poleceń głosowych) w trakcie jednej sesji, a nawet do wykonania tej samej akcji. Na przykład, kliknięcie przycisku powinno być możliwe zarówno myszą, jak i klawiaturą (Enter/Space), a także poprzez dotknięcie ekranu.
  • Ograniczanie do jednego trybu wprowadzania: Treść nie może wymuszać na użytkowniku użycia tylko jednego rodzaju interakcji. Jeśli na stronie jest element, który można przeciągać i upuszczać (drag-and-drop), nie może być on jedyną opcją. Musi istnieć alternatywa, np. możliwość przeniesienia elementu za pomocą klawiatury (np. poprzez menu kontekstowe lub dedykowane przyciski „Przenieś”).
  • Wyjątek „gdy jest to niezbędne”: Istnieją bardzo rzadkie przypadki, kiedy ograniczenie do jednego typu wprowadzania jest uzasadnione. Przykłady obejmują:
    • Rysowanie lub malowanie: W aplikacji graficznej, gdzie główną funkcjonalnością jest precyzyjne rysowanie, wymagające użycia rysika lub myszy, trudno jest zapewnić pełną alternatywę klawiaturową dla każdego ruchu pędzla.
    • Gry: Gry, w których specyficzny mechanizm wprowadzania (np. ruch gałki joysticka, precyzyjne celowanie myszą) jest integralną częścią rozgrywki i stanowi element wyzwania.

    Ten wyjątek jest bardzo wąski i nie powinien być nadużywany. Większość typowych interfejsów użytkownika powinna zapewniać wsparcie dla wielu mechanizmów wprowadzania.

Praktyczne wytyczne dla zapewnienia zgodności

Aby spełnić kryterium 2.5.6, należy przestrzegać następujących wytycznych:

  • Nie wyłączaj domyślnych zachowań przeglądarki: Unikaj nadpisywania standardowych skrótów klawiaturowych, tabulacji czy gestów dotykowych, chyba że zapewnisz równoważną lub lepszą funkcjonalność.
  • Obsługuj wiele zdarzeń wejścia: Dla interaktywnych elementów (przycisków, linków, pól formularzy) upewnij się, że reagują one na różne zdarzenia:
    • click dla myszy i dotyku.
    • keydown (szczególnie Enter i Space) dla klawiatury.
    • touchstart / touchend dla urządzeń dotykowych.
  • Nie zakładaj typu urządzenia wejściowego: Twórz komponenty w sposób agnostyczny pod względem typu wejścia. Nie zakładaj, że użytkownik zawsze ma mysz, klawiaturę czy ekran dotykowy.
  • Zapewnij alternatywy dla złożonych interakcji: Jeśli masz elementy wymagające precyzyjnego przeciągania (drag-and-drop), gestów szczypania (pinch-to-zoom) lub skomplikowanych sekwencji dotykowych, zawsze oferuj alternatywne metody interakcji, które można wykonać za pomocą klawiatury lub prostszych kliknięć.
  • Używaj semantycznego HTML: Standardowe elementy HTML (<button>, <a>, <input>) domyślnie wspierają interakcję klawiaturą, myszą i dotykiem. Gdy tworzysz niestandardowe komponenty, naśladuj ich zachowanie.
  • Zapewnij widoczny wskaźnik fokusu: Upewnij się, że każdy interaktywny element ma wyraźny wskaźnik fokusu, który pomaga użytkownikom klawiatury i technologii wspomagających śledzić, gdzie się znajdują.
  • Testuj na różnych urządzeniach i z różnymi metodami: Regularne testy z użyciem samej klawiatury, ekranu dotykowego oraz, jeśli to możliwe, z oprogramowaniem do rozpoznawania mowy, pomogą zidentyfikować potencjalne problemy.

Przykłady implementacji

Przykład 1: Przycisk z obsługą wielu mechanizmów wejścia

Ten przykład pokazuje poprawną implementację przycisku, który działa z myszą, klawiaturą i dotykiem.

<button id="myButton">Kliknij mnie</button>
#myButton {
  padding: 10px 20px;
  font-size: 16px;
  cursor: pointer;
}

#myButton:focus {
  outline: 2px solid blue;
  outline-offset: 2px;
}
document.getElementById('myButton').addEventListener('click', function() {
  alert('Przycisk kliknięty!');
});

// Standardowy element <button> domyślnie obsługuje klawiaturę (Enter/Space)
// oraz zdarzenia dotykowe. Nie ma potrzeby dodawania dodatkowych listenerów dla tych.

W tym przykładzie standardowy element <button> automatycznie obsługuje kliknięcia myszą, naciśnięcia klawiszem Enter lub spacji (po ustawieniu fokusu) oraz dotknięcia ekranu. Styl :focus zapewnia widoczny wskaźnik fokusu dla użytkowników klawiatury.

Przykład 2: Niestandardowy element interaktywny (Slider)

Ten przykład przedstawia niestandardowy komponent slidera, który musi działać zarówno z przeciąganiem (mysz/dotyk), jak i klawiaturą.

<div class="custom-slider" role="slider" aria-valuemin="0" aria-valuemax="100" aria-valuenow="50" tabindex="0">
  <div class="slider-thumb"></div>
</div>
.custom-slider {
  width: 200px;
  height: 20px;
  background-color: #eee;
  border-radius: 10px;
  position: relative;
  margin: 20px;
  cursor: grab;
}

.custom-slider:focus {
  outline: 2px solid green;
  outline-offset: 2px;
}

.slider-thumb {
  width: 30px;
  height: 30px;
  background-color: #007bff;
  border-radius: 50%;
  position: absolute;
  top: -5px;
  left: calc(50% - 15px); /* Initial position */
  cursor: grab;
}
document.addEventListener('DOMContentLoaded', () => {
  const slider = document.querySelector('.custom-slider');
  const thumb = slider.querySelector('.slider-thumb');
  let isDragging = false;

  function updateSliderPosition(clientX) {
    const rect = slider.getBoundingClientRect();
    let newLeft = clientX - rect.left - thumb.offsetWidth / 2;
    newLeft = Math.max(-thumb.offsetWidth / 2, Math.min(rect.width - thumb.offsetWidth / 2, newLeft));
    thumb.style.left = newLeft + 'px';

    const value = Math.round(((newLeft + thumb.offsetWidth / 2) / rect.width) * 100);
    slider.setAttribute('aria-valuenow', value);
    console.log('Slider value:', value);
  }

  // Mouse and Touch events for dragging
  ['mousedown', 'touchstart'].forEach(eventType => {
    slider.addEventListener(eventType, (e) => {
      e.preventDefault(); // Prevent text selection etc.
      isDragging = true;
      slider.style.cursor = 'grabbing';
      thumb.style.cursor = 'grabbing';
    });
  });

  ['mousemove', 'touchmove'].forEach(eventType => {
    window.addEventListener(eventType, (e) => {
      if (isDragging) {
        const clientX = e.touches ? e.touches[0].clientX : e.clientX;
        updateSliderPosition(clientX);
      }
    });
  });

  ['mouseup', 'touchend', 'mouseleave'].forEach(eventType => {
    window.addEventListener(eventType, () => {
      if (isDragging) {
        isDragging = false;
        slider.style.cursor = 'grab';
        thumb.style.cursor = 'grab';
      }
    });
  });

  // Keyboard events for accessibility
  slider.addEventListener('keydown', (e) => {
    let currentValue = parseInt(slider.getAttribute('aria-valuenow'));
    let step = 1;

    if (e.shiftKey) {
      step = 10;
    }

    if (e.key === 'ArrowRight' || e.key === 'ArrowUp') {
      e.preventDefault();
      currentValue = Math.min(100, currentValue + step);
    } else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') {
      e.preventDefault();
      currentValue = Math.max(0, currentValue - step);
    }

    const rect = slider.getBoundingClientRect();
    const newLeft = ((currentValue / 100) * rect.width) - (thumb.offsetWidth / 2);
    thumb.style.left = newLeft + 'px';
    slider.setAttribute('aria-valuenow', currentValue);
    console.log('Slider value (keyboard):', currentValue);
  });
});

W tym przykładzie slider:

  • Jest elementem <div> z rolą ARIA slider oraz atrybutami aria-valuemin, aria-valuemax i aria-valuenow, co informuje technologie wspomagające o jego funkcji.
  • Ma tabindex="0", dzięki czemu jest fokusowalny klawiaturą.
  • Obsługuje zdarzenia mousedown / mousemove / mouseup dla interakcji myszą.
  • Obsługuje zdarzenia touchstart / touchmove / touchend dla interakcji dotykowej.
  • Obsługuje zdarzenia keydown dla strzałek (lewo/prawo, góra/dół) w celu zmiany wartości suwaka za pomocą klawiatury.
  • Posiada widoczny wskaźnik fokusu (:focus).

Przykład 3: Niepoprawna implementacja

Ten przykład pokazuje typowy błąd, gdzie interakcja jest ograniczona do jednego typu wejścia.

<div id="draggableBox">Przeciągnij mnie!</div>
#draggableBox {
  width: 150px;
  height: 100px;
  background-color: lightcoral;
  color: white;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: grab;
  position: absolute;
  top: 50px;
  left: 50px;
}
document.addEventListener('DOMContentLoaded', () => {
  const draggableBox = document.getElementById('draggableBox');
  let isDragging = false;

  draggableBox.addEventListener('mousedown', (e) => {
    isDragging = true;
    draggableBox.style.cursor = 'grabbing';
    let offsetX = e.clientX - draggableBox.getBoundingClientRect().left;
    let offsetY = e.clientY - draggableBox.getBoundingClientRect().top;

    function onMouseMove(event) {
      if (isDragging) {
        draggableBox.style.left = (event.clientX - offsetX) + 'px';
        draggableBox.style.top = (event.clientY - offsetY) + 'px';
      }
    }

    function onMouseUp() {
      isDragging = false;
      draggableBox.style.cursor = 'grab';
      window.removeEventListener('mousemove', onMouseMove);
      window.removeEventListener('mouseup', onMouseUp);
    }

    window.addEventListener('mousemove', onMouseMove);
    window.addEventListener('mouseup', onMouseUp);
  });

  // BRAK obsługa klawiatury lub dotyku
});

W tym przykładzie element #draggableBox można przesuwać tylko za pomocą myszy (zdarzenia mousedown/mousemove/mouseup). Brak jest wsparcia dla:

  • Klawiatury: Użytkownicy klawiatury nie mogą przenieść ani aktywować tego elementu. Brakuje tabindex i obsługi zdarzeń keydown.
  • Dotyku: Brak jest obsługi zdarzeń touchstart/touchmove/touchend, co uniemożliwia interakcję na urządzeniach dotykowych.

Taka implementacja narusza kryterium 2.5.6, ponieważ ogranicza interakcję do jednego mechanizmu wprowadzania.

Najlepsze praktyki i typowe pułapki

Najlepsze praktyki:

  • Używaj semantycznego HTML: Zawsze, gdy to możliwe, używaj standardowych elementów HTML (<button>, <a>, <input>) zamiast tworzyć niestandardowe elementy z <div> lub <span>. Standardowe elementy mają wbudowane wsparcie dla klawiatury i technologii wspomagających.
  • Dodaj tabindex="0" do niestandardowych elementów interaktywnych: Upewnij się, że niestandardowe elementy, które mają być interaktywne, są fokusowalne klawiaturą.
  • Zawsze zapewniaj widoczny wskaźnik fokusu: Pamiętaj o stylach dla :focus, aby użytkownicy klawiatury wiedzieli, gdzie aktualnie znajduje się ich fokus.
  • Testuj klawiaturą: Po zakończeniu implementacji, spróbuj użyć strony wyłącznie za pomocą klawiatury. Czy wszystkie funkcjonalności są dostępne?
  • Testuj na urządzeniach dotykowych: Sprawdź, czy strona jest w pełni funkcjonalna na smartfonie lub tablecie, używając tylko dotyku.
  • Rozważ obsługę gestów dla czytników ekranu: Niektóre technologie wspomagające (np. VoiceOver, TalkBack) mają własne gesty. Upewnij się, że Twoja implementacja nie koliduje z nimi.
  • Wykorzystaj ARIA: Dla złożonych, niestandardowych komponentów, używaj ról i atrybutów ARIA (np. role="button", aria-pressed="true", role="slider", aria-valuenow), aby zapewnić kontekst technologiom wspomagającym.

Typowe pułapki:

  • Nadpisywanie domyślnych zachowań: Celowe blokowanie lub zmiana standardowego działania klawiszy (np. Tab, Enter) bez zapewnienia odpowiedniej alternatywy.
  • Tworzenie interakcji tylko dla myszy: Stosowanie wyłącznie zdarzeń typu mouseover, mousemove lub click, ignorując zdarzenia klawiatury (keydown) i dotyku (touchstart).
  • Brak alternatyw dla gestów: Wymaganie złożonych gestów (np. drag-and-drop, pinch-to-zoom) jako jedynej metody interakcji bez zapewnienia odpowiedniej alternatywy klawiaturowej lub prostszej interakcji kliknięciem.
  • Brak widocznych wskaźników fokusu: Usunięcie lub ukrycie domyślnych obramowań fokusu, co dezorientuje użytkowników klawiatury.
  • Zależność od precyzji: Projektowanie elementów interfejsu, które wymagają bardzo precyzyjnego pozycjonowania kursora, co jest trudne dla osób z trudnościami manualnymi lub używających ekranów dotykowych.

Zgodność z kryterium 2.5.6 jest kluczowa dla budowania dostępnych i użytecznych aplikacji internetowych, które respektują różnorodność sposobów, w jaki ludzie wchodzą w interakcje z technologią.

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.