WCAG 1.4.13: Treść przy najechaniu lub fokusie

Wprowadzenie do WCAG 1.4.13: Treść przy najechaniu lub fokusie

Kryterium sukcesu WCAG 1.4.13 „Treść przy najechaniu lub fokusie” (Content on Hover or Focus) na poziomie AA dotyczy dynamicznie wyświetlanej treści, która pojawia się, gdy użytkownik najeżdża kursorem myszy lub ustawia fokus klawiatury na elemencie. Jego celem jest zapewnienie, że taka treść jest dostępna, możliwa do interakcji i nie znika przedwcześnie, utrudniając użytkownikom jej postrzeganie lub obsługę.

To kryterium ma zastosowanie do wszelkiej dodatkowej treści, która staje się widoczna wyłącznie po najechaniu kursorem myszy (hover) lub ustawieniu fokusu klawiatury (focus) na elemencie wyzwalającym. Typowe przykłady to etykietki narzędzi (tooltips), niestandardowe menu kontekstowe, podmenu, komunikaty o błędach pojawiające się po ustawieniu fokusu na polu formularza czy rozwijane listy.

Co to jest „Treść przy najechaniu lub fokusie”?

Mówiąc o „treści przy najechaniu lub fokusie”, mamy na myśli komponenty interfejsu użytkownika, które:

  • Nie są początkowo widoczne na stronie.
  • Stają się widoczne, gdy użytkownik najeżdża na nie wskaźnikiem myszy lub ustawia na nich fokus klawiatury.
  • Znikają, gdy wskaźnik myszy lub fokus opuszcza wyzwalający element.

Kryterium 1.4.13 ma na celu zapewnienie, że użytkownicy mają wystarczająco dużo czasu i możliwości, aby wchodzić w interakcje z taką treścią, bez obawy, że zniknie ona, zanim zdążą ją przeczytać lub aktywować.

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

To kryterium jest kluczowe dla szerokiego grona użytkowników z różnymi rodzajami niepełnosprawności, ponieważ treści pojawiające się na żądanie często sprawiają problemy z dostępnością:

  • Użytkownicy z niepełnosprawnościami ruchowymi: Osoby, które mają trudności z precyzyjnym sterowaniem myszą lub wymagają użycia klawiatury, mogą mieć problem z dotarciem do treści, która znika zbyt szybko. Szybkie zniknięcie treści uniemożliwia im kliknięcie linku wewnątrz tooltpu lub naciśnięcie przycisku w rozwijanym menu.
  • Użytkownicy słabowidzący i korzystający z lupy ekranowej: Osoby powiększające ekran muszą przesuwać powiększony obszar widoku, aby przeczytać całą treść. Jeśli treść znika, gdy kursor opuści obszar wyzwalający, nie są w stanie jej odczytać. Mogą potrzebować czasu, aby przesunąć powiększony obszar na wyskakującą treść, a jeśli ta znika po prostu dlatego, że kursor przesunął się poza element wyzwalający, staje się ona niedostępna.
  • Użytkownicy z niepełnosprawnościami poznawczymi: Osoby te mogą potrzebować więcej czasu na przetworzenie informacji. Szybko znikające treści powodują frustrację, stres i uniemożliwiają zrozumienie przekazu.
  • Użytkownicy z problemami z uwagą: Nagłe pojawianie się i znikanie treści może być rozpraszające i utrudniać skupienie się na zadaniu.

Zapewnienie, że treści pojawiające się przy najechaniu lub fokusie spełniają wymagania tego kryterium, gwarantuje, że wszyscy użytkownicy mają równy dostęp do informacji i funkcji oferowanych przez stronę internetową.

Kryteria sukcesu i wymagania

Kryterium WCAG 1.4.13 wymaga, aby dodatkowa treść pojawiająca się przy najechaniu kursorem (hover) lub fokusie klawiatury (focus) spełniała trzy warunki:

1. Możliwość zamknięcia (Dismissible)

Użytkownik musi mieć możliwość zamknięcia dodatkowej treści bez przesuwania wskaźnika myszy lub fokusu klawiatury, chyba że dodatkowa treść przekazuje błąd wprowadzania lub nie zasłania ani nie zastępuje innej treści.

  • Oznacza to, że powinna istnieć np. opcja zamknięcia komunikatu za pomocą klawisza Esc lub dedykowany przycisk „Zamknij”.
  • Wyjątek: Jeśli treść jest komunikatem o błędzie wprowadzania danych i nie zasłania innych elementów, lub jeśli treść jest nieinwazyjna (np. nie blokuje interakcji z tłem, nie ma na niej elementów aktywnych), to nie zawsze jest wymagany mechanizm zamknięcia.

2. Możliwość najechania (Hoverable)

Jeśli treść jest widoczna, gdy wskaźnik myszy najeżdża na element wyzwalający, musi być możliwe przesunięcie wskaźnika myszy nad dodatkową treścią bez jej zniknięcia.

  • Jest to szczególnie ważne dla użytkowników lup ekranowych, którzy potrzebują czasu, aby przesunąć mysz z elementu wyzwalającego na samą wyskakującą treść, aby ją zobaczyć w całości.
  • Jeśli treść znika, gdy tylko kursor opuści element wyzwalający, staje się niedostępna dla tych użytkowników.

3. Możliwość zachowania (Persistent)

Dodatkowa treść pozostaje widoczna, dopóki użytkownik jej nie zamknie (patrz punkt 1) lub dopóki warunek wyzwalający nie przestanie być prawdziwy (np. fokus lub kursor myszy opuszcza zarówno element wyzwalający, jak i samą dodatkową treść), lub dopóki informacja, którą prezentuje, nie przestanie być aktualna.

  • Oznacza to, że treść nie może znikać automatycznie po krótkim czasie.
  • Musi pozostać na ekranie tak długo, jak długo użytkownik na nią patrzy lub wchodzi w interakcje.
  • Jeśli użytkownik przesunie kursor z elementu wyzwalającego na samą wyskakującą treść, treść musi pozostać widoczna. Tylko jeśli kursor opuści zarówno element wyzwalający, jak i wyskakującą treść, może ona zniknąć (zakładając spełnienie punktów 1 i 2).

Wyjątki

Istnieją wyjątki, w których te wymagania nie muszą być spełnione:

  • Komponent kontrolujący: Jeśli wygląd dodatkowej treści jest kontrolowany przez agenta użytkownika (np. domyślne dymki przeglądarki wygenerowane przez atrybut title).
  • Niezbędne: Dodatkowa treść jest niezbędna i jej usunięcie zmieniłoby znaczenie lub funkcjonalność treści.

Praktyczne wskazówki dotyczące zgodności

Aby zapewnić zgodność z WCAG 1.4.13, należy wziąć pod uwagę następujące kwestie podczas projektowania i implementacji:

  • Użyj odpowiednich zdarzeń: Do wyświetlania treści używaj zdarzeń focus i hover, ale pamiętaj o spełnieniu wszystkich trzech wymagań. Dla elementów interaktywnych (takich jak przyciski, linki), treść powinna być dostępna zarówno przy najechaniu myszą, jak i przy fokusie klawiatury.
  • Zapewnij mechanizm zamknięcia: Dla wszystkich nietrywialnych treści, które pojawiają się na żądanie (szczególnie tych, które zasłaniają inne elementy lub zawierają interaktywne komponenty), zawsze dostarczaj wyraźny przycisk zamknięcia (np. „X”) oraz możliwość zamknięcia za pomocą klawisza Esc.
  • Upewnij się, że treść jest dostępna dla klawiatury i myszy: Po pojawieniu się, wyskakująca treść musi być dostępna do interakcji zarówno za pomocą myszy (przez najechanie kursorem), jak i klawiatury (przez ustawienie fokusu). Oznacza to, że fokus klawiatury powinien być możliwy do przeniesienia do wnętrza wyskakującej treści, jeśli zawiera ona interaktywne elementy.
  • Zarządzaj czasem wyświetlania: Unikaj automatycznego zamykania treści po krótkim czasie. Treść powinna pozostawać widoczna dopóki użytkownik celowo jej nie zamknie, albo dopóki kursor/fokus nie opuści zarówno elementu wyzwalającego, jak i samej wyskakującej treści.
  • Testuj z różnymi metodami interakcji: Regularnie testuj swoje implementacje za pomocą klawiatury (bez myszy), lupy ekranowej i czytnika ekranu, aby upewnić się, że treść jest w pełni dostępna.

Przykłady implementacji

Przykład prawidłowy: Tooltip z możliwością zamknięcia i zachowania

Ten przykład przedstawia tooltip, który pojawia się przy najechaniu myszą lub fokusie klawiatury. Po pojawieniu się, pozostaje widoczny, nawet jeśli użytkownik przesunie kursor na sam tooltip. Można go zamknąć klawiszem Esc lub specjalnym przyciskiem.

HTML:

<button class="tooltip-trigger" aria-describedby="my-tooltip">Informacja</button>
<div id="my-tooltip" role="tooltip" class="tooltip" tabindex="-1">
  <p>To jest szczegółowa informacja, którą można przeczytać i z którą można wejść w interakcję.</p>
  <button class="tooltip-close">X</button>
</div>

CSS:

.tooltip-trigger {
  position: relative;
  padding: 8px 15px;
  border: 1px solid #ccc;
  background-color: #f0f0f0;
  cursor: pointer;
}

.tooltip {
  position: absolute;
  left: 0;
  top: 100%; /* Pod elementem wyzwalającym */
  width: 250px;
  padding: 10px;
  background-color: #fff;
  border: 1px solid #0056b3;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  visibility: hidden; /* Domyślnie ukryty */
  opacity: 0;
  transition: opacity 0.3s, visibility 0.3s;
  z-index: 100;
}

/* Tooltip pojawia się przy najechaniu na trigger */
.tooltip-trigger:hover + .tooltip,
.tooltip-trigger:focus + .tooltip {
  visibility: visible;
  opacity: 1;
}

/* Tooltip pozostaje widoczny, jeśli kursor najedzie na sam tooltip */
.tooltip:hover {
  visibility: visible;
  opacity: 1;
}

/* Gdy tooltip jest jawnie widoczny przez JS (np. po kliknięciu) */
.tooltip.is-visible {
  visibility: visible;
  opacity: 1;
}

.tooltip-close {
  position: absolute;
  top: 5px;
  right: 5px;
  border: none;
  background: none;
  font-size: 1em;
  cursor: pointer;
  padding: 2px 5px;
}

.tooltip-close:hover {
  color: red;
}

JavaScript:

document.addEventListener('DOMContentLoaded', () => {
  const trigger = document.querySelector('.tooltip-trigger');
  const tooltip = document.getElementById('my-tooltip');
  const closeButton = tooltip.querySelector('.tooltip-close');

  // Obsługa klawisza ESC do zamykania tooltipa
  document.addEventListener('keydown', (e) => {
    if (e.key === 'Escape' && tooltip.classList.contains('is-visible')) {
      tooltip.classList.remove('is-visible');
      trigger.focus(); // Przywróć fokus na wyzwalacz
    }
  });

  // Obsługa kliknięcia przycisku zamknięcia
  closeButton.addEventListener('click', () => {
    tooltip.classList.remove('is-visible');
    trigger.focus();
  });

  // Zapewnienie, że tooltip jest widoczny przy fokusie i nie znika od razu
  // Można by tu użyć bardziej zaawansowanego zarządzania fokusem, 
  // np. przenoszenie fokusu do tooltipa po jego otwarciu.
  trigger.addEventListener('focus', () => {
    tooltip.classList.add('is-visible');
  });

  trigger.addEventListener('blur', (e) => {
    // Sprawdzamy, czy fokus nie przeszedł do samego tooltipa
    if (!tooltip.contains(e.relatedTarget)) {
      tooltip.classList.remove('is-visible');
    }
  });

  // Dodatkowa obsługa, aby tooltip pozostał widoczny, gdy użytkownik
  // najedzie na niego myszą po tym, jak się pojawił przez trigger:hover.
  // (CSS w tym przypadku już to obsługuje, ale można też przez JS)
  tooltip.addEventListener('mouseleave', () => {
    // Usuń klasę 'is-visible' tylko jeśli nie jest to otwarcie przez trigger:focus
    // oraz jeśli mysz opuściła cały obszar tooltipa i triggera
    if (!trigger.matches(':focus') && !trigger.matches(':hover')) {
        tooltip.classList.remove('is-visible');
    }
  });

  trigger.addEventListener('mouseleave', (e) => {
    // Jeśli mysz opuszcza trigger, ale nie wchodzi na tooltip
    if (!tooltip.contains(e.relatedTarget)) {
      // Opóźnienie, aby dać czas na najechanie na tooltip
      setTimeout(() => {
        if (!tooltip.matches(':hover') && !trigger.matches(':focus')) {
          tooltip.classList.remove('is-visible');
        }
      }, 100); // Krótkie opóźnienie
    }
  });
});

Przykład nieprawidłowy: Tooltip znikający zbyt szybko

W tym przykładzie tooltip znika natychmiast po opuszczeniu kursorem elementu wyzwalającego, uniemożliwiając interakcję z jego zawartością lub dokładne przeczytanie.

HTML:

<button class="tooltip-trigger-incorrect" aria-describedby="bad-tooltip">Nieprawidłowy tooltip</button>
<div id="bad-tooltip" role="tooltip" class="tooltip-incorrect">
  <p>Ta informacja zniknie zbyt szybko!</p>
  <a href="#">Link w tooltipie</a>
</div>

CSS:

.tooltip-trigger-incorrect {
  position: relative;
  padding: 8px 15px;
  border: 1px solid #ccc;
  background-color: #f0f0f0;
  cursor: pointer;
}

.tooltip-incorrect {
  position: absolute;
  left: 0;
  top: 100%;
  width: 250px;
  padding: 10px;
  background-color: #fff;
  border: 1px solid #b30000; /* Czerwona ramka dla błędnego przykładu */
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.3s, visibility 0.3s;
  z-index: 100;
}

/* Błąd: Tooltip pojawia się, ale nie ma stanu hover na samym tooltipie */
.tooltip-trigger-incorrect:hover + .tooltip-incorrect,
.tooltip-trigger-incorrect:focus + .tooltip-incorrect {
  visibility: visible;
  opacity: 1;
}

/* Brak reguły .tooltip-incorrect:hover, co powoduje natychmiastowe zniknięcie */

JavaScript:

document.addEventListener('DOMContentLoaded', () => {
  const triggerIncorrect = document.querySelector('.tooltip-trigger-incorrect');
  const tooltipIncorrect = document.getElementById('bad-tooltip');

  triggerIncorrect.addEventListener('focus', () => {
    tooltipIncorrect.style.visibility = 'visible';
    tooltipIncorrect.style.opacity = '1';
  });

  triggerIncorrect.addEventListener('blur', () => {
    // Błąd: Znika natychmiast po utracie fokusu z triggera, nawet jeśli użytkownik chciałby wejść w interakcję z tooltipem
    tooltipIncorrect.style.visibility = 'hidden';
    tooltipIncorrect.style.opacity = '0';
  });

  // Podobnie dla myszy, CSS w tym przypadku nie pozwala na najechanie na sam tooltip
  // Jeśli JS byłby użyty do obsługi, wyglądałoby to podobnie:
  // triggerIncorrect.addEventListener('mouseenter', () => {
  //   tooltipIncorrect.style.visibility = 'visible';
  //   tooltipIncorrect.style.opacity = '1';
  // });
  // triggerIncorrect.addEventListener('mouseleave', () => {
  //   tooltipIncorrect.style.visibility = 'hidden';
  //   tooltipIncorrect.style.opacity = '0';
  // });
});

Najlepsze praktyki i często popełniane błędy

Najlepsze praktyki:

  • Zawsze dostarczaj mechanizm zamknięcia: Upewnij się, że użytkownik może zamknąć wyskakującą treść za pomocą klawisza Esc oraz, w miarę możliwości, przycisku „Zamknij”.
  • Używaj semantyki ARIA: Używaj odpowiednich ról ARIA (np. role="tooltip", role="menu", role="dialog") i atrybutów (np. aria-describedby, aria-labelledby, aria-haspopup) do prawidłowego opisywania relacji między elementem wyzwalającym a wyskakującą treścią. Pomoże to czytnikom ekranu interpretować kontekst.
  • Zapewnij wystarczający kontrast: Upewnij się, że tekst i interaktywne elementy w wyskakującej treści mają wystarczający kontrast kolorów w stosunku do tła, zgodnie z WCAG 1.4.3 i 1.4.11.
  • Nie polegaj wyłącznie na najechaniu myszą: Zawsze upewnij się, że treść jest dostępna również dla użytkowników klawiatury (poprzez fokus).
  • Zarządzanie fokusem: Jeśli wyskakująca treść zawiera interaktywne elementy, upewnij się, że fokus klawiatury może być przeniesiony do wnętrza tej treści i że użytkownik może swobodnie się po niej poruszać. Po zamknięciu, fokus powinien wrócić do elementu, który wyzwolił pojawienie się treści.

Często popełniane błędy:

  • Treść znika po przesunięciu kursora lub fokusu: Najczęstszy błąd, gdy tooltip lub menu znika, gdy tylko kursor opuści element wyzwalający, uniemożliwiając najechanie na samą wyskakującą treść.
  • Brak możliwości interakcji z treścią: Wyskakująca treść zawiera linki lub przyciski, ale nie można na nie kliknąć, ponieważ treść znika, zanim użytkownik zdąży do niej dotrzeć.
  • Brak łatwo dostępnego mechanizmu zamknięcia: Użytkownik nie może zamknąć treści za pomocą klawiatury (np. Esc) ani nie ma widocznego przycisku „Zamknij”.
  • Niewystarczający kontrast: Tekst w tooltipie jest trudny do odczytania ze względu na słaby kontrast kolorów.
  • Automatyczne zamykanie po czasie: Treść znika po z góry określonym czasie, bez względu na to, czy użytkownik zdążył ją przetworzyć.
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.