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
displaylub zdejmujeszhidden), - 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: noneanivisibility: 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.
Modal i tło strony
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
-
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".
- „chcę ukryć dla wszystkich” →
-
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 wystarczydisplay: nonelubhidden. -
Nie ukrywaj elementów interaktywnych przed czytnikami – żaden fokusowalny element nie powinien znajdować się w poddrzewie z
aria-hidden="true". -
Stosuj sprawdzone wzorce CSS dla visually hidden – korzystaj z
.visually-hiddenlub.sr-onlyzamiast eksperymentów typuopacity: 0. -
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.
-
Zwracaj uwagę na aktualizacje treści dynamicznych – przy komunikatach w trakcie działania strony rozważ regiony
aria-livei 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-hiddenjest aktualizowany razem z widocznością, gdy ukrywasz/pokazujesz element dynamicznie, - czy nie używasz
opacity: 0ani 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.






