Wielokrotna ekspozycja kreatywnych rysunków tematycznych i tła wnętrza biura

Jak ukrywać elementy na stronie? display, visibility i aria-hidden

11 min. czytania

Ukrywanie elementów na stronie to nie tylko kwestia estetyki, ale też kluczowy aspekt dostępności. Różne techniki (CSS, HTML, ARIA) inaczej wpływają na to, co widzą użytkownicy i technologie asystujące, takie jak czytniki ekranu. W praktyce warto wiedzieć, jak poprawnie korzystać z display, visibility, atrybutu hidden, technik „visually hidden” oraz aria-hidden, z naciskiem na dostępność.

1. Dlaczego sposób ukrywania ma znaczenie?

Na współczesnej stronie internetowej element można ukryć na różne sposoby:

  • nadal mieć w DOM, ale go nie renderować,
  • renderować wizualnie, ale ukryć przed czytnikami ekranu,
  • ukryć wizualnie, ale zostawić w drzewie dostępności,
  • ukryć całkowicie – zarówno wizualnie, jak i z punktu widzenia technologii asystujących.

Dla dostępności krytyczne są dwa „drzewa”: DOM (struktura dokumentu, z którą pracuje JavaScript) oraz drzewo dostępności (uproszczona reprezentacja widocznej i istotnej treści, którą odczytują czytniki ekranu i inne technologie pomocnicze).

To, że element istnieje w DOM, nie oznacza, że jest widoczny dla użytkownika lub technologii asystujących – zależy to od kombinacji CSS (display, visibility), HTML (hidden) i ARIA (aria-hidden).

2. Podstawowe metody ukrywania w CSS i HTML

Najczęściej spotykane mechanizmy i ich zastosowania:

  • CSS display: none,
  • CSS visibility: hidden,
  • HTML hidden,
  • ARIA aria-hidden="true",
  • klasy typu .visually-hidden / .sr-only (ukrycie tylko wizualne).

Każda z tych technik ma inne skutki dla następujących obszarów:

  • layoutu (czy element zajmuje miejsce),
  • interakcji (czy można go fokusować),
  • dostępności (czy jest w drzewie dostępności).

3. display: none – całkowite usunięcie z renderowania

Jak działa?

Przykładowa reguła CSS wygląda tak:

.element { display: none; }

Po zastosowaniu tej reguły element nie jest renderowany – zostaje usunięty z układu strony, jakby go w ogóle nie było.

Skutki stosowania tej techniki:

  • wizualnie – element niewidoczny, nie zajmuje miejsca,
  • dostępność – element jest usuwany z drzewa dostępności, czytnik ekranu go nie „widzi”,
  • fokus / interakcje – element nie może otrzymać fokusu i nie jest interaktywny.

Atrybut HTML hidden

Wyłączenie widoczności semantycznie można osiągnąć tak:

<div hidden>Ta treść jest ukryta</div>

Atrybut hidden działa jak semantyczny odpowiednik display: none. Dla jasności i wsparcia starszych przeglądarek można dodać regułę CSS:

[hidden] { display: none; }

Efekt jest ten sam: brak renderowania wizualnego oraz brak wpisu w drzewie dostępności.

Kiedy używać display: none / hidden?

Oto dobre zastosowania tych technik:

  • nieaktywne sekcje interfejsu, które nie powinny być dostępne (np. zakładki nieaktywne),
  • wstępnie ukryte modale / menu, które pojawiają się po interakcji (po pokazaniu zmieniasz display lub zdejmujesz hidden),
  • treści tymczasowo nieaktywne, które nie powinny być ani widoczne, ani dostępne.

Niedobre zastosowania: ukrywanie treści, które powinny być dostępne dla czytników (np. ważne komunikaty) oraz ukrywanie elementów, które mają być na żywo ogłaszane – do tego lepiej użyć regionów aria-live i przemyślanego sposobu aktualizacji zamiast prostego pokazywania elementu przez display: block.

4. visibility: hidden – ukryj, ale zostaw miejsce

Jak działa?

Przykładowa reguła CSS wygląda tak:

.element { visibility: hidden; }

Element jest niewidoczny, ale w układzie rezerwuje miejsce o takich samych wymiarach, jak gdyby był widoczny.

Skutki stosowania tej techniki:

  • wizualnie – element niewidoczny, w układzie zostaje „pusta przestrzeń”,
  • dostępność – element jest ukryty również dla technologii asystujących (wykluczony z drzewa dostępności),
  • fokus / interakcje – nie powinien być fokusowany ani interaktywny.

W praktyce skutki dostępności są bardzo podobne do display: none. Wybór sprowadza się do tego, czy chcesz zachować przestrzeń w layoucie. Typowe użycie: gdy chcesz zapobiec przeskakiwaniu layoutu lub przygotować miejsce pod animację elementu, który wróci w to samo miejsce.

5. aria-hidden – ukrywanie tylko przed technologiami asystującymi

Co robi aria-hidden?

Atrybut ARIA można zastosować w ten sposób:

<div aria-hidden="true">Treść niewidoczna dla czytników</div>

To część specyfikacji WAI‑ARIA i służy do ukrywania elementu wyłącznie przed technologiami asystującymi (np. czytnikami ekranu).

Skutki stosowania tej techniki:

  • wizualnie – brak zmian, element pozostaje widoczny i zachowuje miejsce w layoucie,
  • dostępność – element oraz wszyscy jego potomkowie są usuwani z drzewa dostępności,
  • fokus / interakcje – element nadal może być fokusowany z poziomu DOM, co bywa niebezpieczne, jeśli nie zadbasz o spójność.

Zgodnie z dokumentacją: aria-hidden="true" ukrywa całe poddrzewo w drzewie dostępności; element jest uznawany za ukryty także wtedy, gdy którykolwiek z jego przodków ma aria-hidden="true" lub nie jest renderowany (display: none, hidden).

Kiedy używać aria-hidden?

Oto dobre zastosowania tej techniki:

  • dekoracyjne ikony, które nie niosą informacji (np. gwiazdka w przycisku),
  • powielone treści, które są już dostępne w inny sposób i duplikat ma być pominięty przez czytniki,
  • elementy UI bez znaczenia semantycznego (ozdobne linie, obrazki tła wstawione jako elementy <img> zamiast CSS).

Czego aria-hidden nie robi: nie zastępuje display: none / hidden (element nadal jest widoczny i zajmuje miejsce) oraz nie kontroluje klawiatury (focus może trafić na elementy w DOM, np. przez tabindex).

Kluczowe zasady bezpieczeństwa

Stosując aria-hidden, pamiętaj o trzech regułach:

  • nie stosuj na elementach fokusowalnych – linki, przyciski i pola formularzy powinny być widoczne dla czytników;
  • nie umieszczaj fokusowalnych potomków w poddrzewie ukrytym ARIA – unikniesz „ślepych” pułapek fokusa;
  • utrzymuj spójność stanu – jeśli coś jest wizualnie widoczne i ma być dostępne, nie może mieć aria-hidden="true".

Aby zachować spójność przy dynamicznym pokazywaniu panelu, zastosuj równoległe zmiany:

panel.hidden = false; panel.setAttribute('aria-hidden', 'false');

Przy pokazywaniu treści usuń lub ustaw aria-hidden na "false" – w przeciwnym razie czytniki nadal zignorują zawartość.

6. Techniki „visually hidden” / .sr-only

Czasem potrzebujemy odwrotnej sytuacji: element ma być niewidoczny wizualnie, ale dostępny dla czytników ekranu.

Popularne klasy, które to realizują, to:

  • .sr-only,
  • .visually-hidden,
  • .visuallyhidden.

Taka klasa zwykle spełnia kilka warunków:

  • ustawia elementowi minimalne wymiary,
  • pozycjonuje go poza ekranem lub stosuje technikę clip/clip-path,
  • ukrywa element z punktu widzenia layoutu, ale nie używa display: none ani visibility: hidden.

Przykładowa, nowoczesna wersja klasy visually hidden wygląda tak:

.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }

Ta technika to rekomendowany sposób na „ukrycie na ekranie, ale nie przed czytnikiem”.

Przykłady użycia

Tekstowy opis ikony w przycisku:

<button> <span class="icon" aria-hidden="true">🔍</span> <span class="visually-hidden">Szukaj</span> </button>

Ukryty nagłówek dla poprawy struktury dokumentu:

<h2 class="visually-hidden">Nawigacja główna</h2> <nav>…</nav>

Informacja tylko dla czytników (np. o nowym oknie):

<a href="…" target="_blank">Dokument<span class="visually-hidden"> (otwiera się w nowym oknie)</span></a>

7. Porównanie: display, visibility, hidden, aria-hidden, „visually hidden”

Poniższa tabela zestawia kluczowe różnice między technikami ukrywania:

Technika Widoczne wizualnie? W drzewie dostępności? Zajmuje miejsce w layoucie? Typowe zastosowania
display: none Nie Nie Nie Ukrycie sekcji, zakładek, paneli, które mają być całkowicie nieaktywne
hidden (HTML) Nie Nie Nie Semantyczne ukrycie elementów – podobnie jak display: none
visibility: hidden Nie Nie Tak Ukrycie treści z zachowaniem miejsca w układzie
aria-hidden="true" Tak Nie Tak Ukrycie dekoracji i duplikatów przed czytnikami
.visually-hidden Nie Tak Nie (zazwyczaj) Teksty tylko dla czytników, niewidoczne wizualnie

8. Typowe scenariusze i wzorce

Całkowicie ukryta sekcja (np. niewybrana zakładka)

Struktura zakładek może wyglądać tak:

<div role="tablist"> <button role="tab" aria-selected="true" aria-controls="tab1">Zakładka 1</button> <button role="tab" aria-selected="false" aria-controls="tab2">Zakładka 2</button> </div> <div id="tab1" role="tabpanel">Treść zakładki 1</div> <div id="tab2" role="tabpanel" hidden>Treść zakładki 2</div>

Prosta logika przełączania może być taka:

function selectTab(id) { const tab1 = document.getElementById('tab1'); const tab2 = document.getElementById('tab2'); tab1.hidden = (id !== 'tab1'); tab2.hidden = (id !== 'tab2'); }

Użycie hidden sprawia, że nieaktywne panele nie są widoczne ani dostępne dla czytników – dokładnie tak, jak oczekujemy.

W modalu chcemy uczynić okno dialogowe widocznym i dostępnym, a jednocześnie „wyłączyć” resztę strony w drzewie dostępności.

Struktura HTML może wyglądać tak:

<main id="main-content">…główna treść…</main> <div id="modal" role="dialog" aria-modal="true" hidden>…treść okna modalnego…</div>

Przy otwieraniu modalu zastosuj spójne przełączenie stanów:

function openModal() { const modal = document.getElementById('modal'); const main = document.getElementById('main-content'); modal.hidden = false; modal.setAttribute('aria-hidden', 'false'); main.setAttribute('aria-hidden', 'true'); }

W efekcie główna treść pozostaje wizualnie w tle, ale jest ukryta przed czytnikami (aria-hidden="true"), a modal jest widoczny i dostępny.

Możesz też rozważyć atrybut inert do wyłączania interakcji z tłem (często wymaga polyfillu).

Komunikat tylko dla czytników ekranu

Jeśli chcesz wskazać, że pole jest obowiązkowe, ale bez dodatkowego tekstu wizualnie:

<label for="email">E‑mail <span class="visually-hidden">(pole obowiązkowe)</span></label> <input id="email" type="email" required>

Informacja jest odczytywana przez czytniki, ale pozostaje niewidoczna wizualnie.

Dekoracyjne ikony

Unikaj czytania przez czytnik ikon bez znaczenia semantycznego:

<button> <span class="fa fa-star" aria-hidden="true"></span> Dodaj do ulubionych </button>

Ikona jest dekoracyjna (aria-hidden="true"), a funkcję opisuje czytelny tekst przycisku.

9. Najczęstsze błędy i pułapki

aria-hidden="true" na elementach fokusowalnych

Przykład błędu:

<button aria-hidden="true">Zapisz</button>

Przycisk jest widoczny i może być dostępny z klawiatury, ale niewidoczny dla czytnika, co tworzy pułapkę. Nigdy nie stosuj aria-hidden="true" na elementach interaktywnych ani ich rodzicach, jeśli w środku są elementy interaktywne.

Pokazanie treści bez aktualizacji aria-hidden

Przykład niekonsekwencji:

<div id="panel" aria-hidden="true" hidden>Treść panelu</div>

Skrypt pokazujący panel:

panel.hidden = false; // zapomniano zaktualizować aria-hidden: panel.setAttribute('aria-hidden', 'false');

W efekcie panel jest widoczny wizualnie, ale niewidoczny dla czytnika. Rozwiązanie: przy pokazywaniu usuń aria-hidden lub ustaw je na "false", a przy ukrywaniu ustaw "true" – zawsze spójnie ze stanem wizualnym.

Ukrywanie treści tylko opacity: 0 lub prymitywnym przesuwaniem poza ekran

opacity: 0 nie ukrywa elementu z drzew dostępności – element nadal bywa ogłaszany, a focus może na niego trafić. Podobnie przesunięcie position: absolute; left: -9999px bez dodatkowych stylów może powodować niespójności.

Jeśli celem jest ukrycie dla wszystkich, użyj display: none, visibility: hidden lub hidden. Jeśli celem jest ukrycie tylko wizualne, użyj sprawdzonej klasy .visually-hidden zamiast opacity: 0.

Zbyt szerokie stosowanie aria-hidden

Przykład nadmiernego zakresu:

<div aria-hidden="true">…cała sekcja serwisu…</div>

Taki zabieg usuwa z drzew dostępności potencjalnie ważne linki, przyciski i treści. Stosuj aria-hidden precyzyjnie, na możliwie małym zakresie.

10. Dobre praktyki w projektach

  1. Zawsze definiuj cel ukrywania – wybierz technikę adekwatnie do odbiorcy:

    • „chcę ukryć dla wszystkich” → display: none / hidden / visibility: hidden (w zależności od layoutu),
    • „chcę ukryć tylko wizualnie” → .visually-hidden,
    • „chcę ukryć tylko przed czytnikami” → aria-hidden="true".
  2. Dbaj o spójność między stanem wizualnym a dostępnościowym – jeśli coś jest widoczne i ma być dostępne, nie może mieć aria-hidden="true"; jeśli jest ukryte dla wszystkich, zwykle wystarczy display: none lub hidden.

  3. Nie ukrywaj elementów interaktywnych przed czytnikami – żaden fokusowalny element nie powinien znajdować się w poddrzewie z aria-hidden="true".

  4. Stosuj sprawdzone wzorce CSS dla visually hidden – korzystaj z .visually-hidden lub .sr-only zamiast eksperymentów typu opacity: 0.

  5. Testuj na żywych narzędziach – przejdź stronę samą klawiaturą i sprawdź ją z czytnikiem (NVDA, JAWS, VoiceOver), aby upewnić się, że fokus nie „ląduje” w niewidocznych miejscach, a ważne treści nie są przypadkiem ukryte.

  6. Zwracaj uwagę na aktualizacje treści dynamicznych – przy komunikatach w trakcie działania strony rozważ regiony aria-live i kontrolowane aktualizacje zamiast prostego pokazywania/ukrywania bloków.

11. Checklist do użycia w projekcie

Przed wypuszczeniem nowego komponentu, który coś „ukrywa”, odpowiedz na poniższe pytania:

  • czy wiesz, kogo chcesz „pozbawić” tego elementu,
  • czy dla „wszystkich użytkowników” używasz display: none / hidden / visibility: hidden, dla „użytkowników czytników” – aria-hidden="true", a dla „użytkowników wzrokowych” – .visually-hidden,
  • czy żaden element interaktywny nie jest ukryty przez aria-hidden="true",
  • czy stan aria-hidden jest aktualizowany razem z widocznością, gdy ukrywasz/pokazujesz element dynamicznie,
  • czy nie używasz opacity: 0 ani prymitywnego przesuwania poza ekran jako metody „ukrycia z dostępności”,
  • czy przetestowałeś komponent klawiaturą i czytnikiem ekranu (NVDA, JAWS, VoiceOver).

Jeśli na wszystkie pytania odpowiadasz twierdząco, sposób ukrywania elementów w Twoim projekcie najpewniej jest zgodny z dobrymi praktykami dostępności.