Oto kolejny odcinek Wpadek i wypadków!
Dzisiaj zajmiemy się wzorcem, który ostatnimi czasy zdobywa naprawdę sporą popularność: umieszczaniem linków w przyciskach i przycisków w linkach. Mówię tutaj o konstrukcjach typu:
<a href="#">
<button>Jestem przyciskiem w linku</button>
</a>
<button>
<a href="#">Jestem linkiem w przycisku</a>
</button>
Tego typu konstrukcje są złe z kilku powodów:
-
Z perspektywy semantyki nie mają absolutnie żadnego sensu. Przyciski to elementy służące do zupełnie innych celów niż linki. Specyfikacja HTML określa przyciski jako elementy zdolne do wysłania formularzy. Jedyny przykład dla przycisku, który nie jest związany z wysłaniem formularza, to kod przycisku otwierającego okienko
alert
. Z kolei linki to elementy reprezentujące hiperlinki, czyli odsyłacze do innych zasobów (wewnątrz i na zewnątrz danej strony), których kliknięcie powoduje nawigację do tych zasobów.Inaczej mówiąc: przyciski służą do wykonania akcji, a linki – do przejścia na inną stronę/inne miejsce na danej stronie. Połączenie tych dwóch elementów próbuje pogodzić ze sobą dwa wzajemnie się wykluczające znaczenia.
-
Takie łączenie elementów jest wprost zabronione przez specyfikację HTML, przy użyciu tzw. modelów zawartości. Model zawartości to po prostu lista elementów, jakie można umieścić w danym elemencie. Dla elementu
a
model jest zdefiniowany następująco:Transparent, but there must be no interactive content descendant,
a
element descendant, or descendant with thetabindex
attribute specified.[Przezroczysty, ale nie może zawierać potomka będącego treścią interaktywną, elementu
a
lub potomka ze zdefiniowanym atrybutem[tabindex]
.]Z kolei dla elementu
button
model zawartości jest zdefiniowany tak:Phrasing content, but there must be no interactive content descendant and no descendant with the tabindex attribute specified.
[Zawartość frazowa, ale nie może zawierać potomka będącego treścią interaktywną lub potomka ze zdefiniowanym atrybutem
[tabindex]
.]Jak widać, definicje modelów dla obu elementów są bardzo podobne. Hasłem-kluczem jest
treść interaktywna
, którą specyfikacja HTML definiuje w taki sposób:Interactive content is content that is specifically intended for user interaction.
a
(if thehref
attribute is present),audio
(if thecontrols
attribute is present),button
,details
,embed
,iframe
,img
(if theusemap
attribute is present),input
(if thetype
attribute is not in the Hidden state),label
,object
(if theusemap
attribute is present),select
,textarea
,video
(if thecontrols
attribute is present).[Interaktywna zawartość to zawartość, która jest przeznaczona do interakcji z użytkownikiem.
a
(jeśli jest obecny atrybut[href]
),audio
(jeśli jest obecny atrybutcontrols
),button
,details
,embed
,iframe
,img
(jeśli jest obecny atrybut[usemap]
),input
(jeśli pole nie jest[type=hidden]
),label
,object
(jeśli jest obecny atrybut[usemap]
),select
,textarea
,video
(jeśli jest obecny atrybut[controls]
).]Umieszczanie linków w przyciskach albo przycisków w linkach jest po prostu niepoprawne z punktu widzenia składni HTML-a.
-
Całkowicie psuje to nawigację klawiaturą. Jeśli na przykładowej stronie spróbuje się nawigować przy pomocy klawiatury, naciskając Tab, to szybko zauważy się, że na każdym przycisku istnieją dwa tab stopy. Tym samym każdy element trzeba przejechać dwukrotnie.
Tego typu zachowanie jest jeszcze bardziej mylące dla użytkowników czytników ekranowych.
-
Jeśli już jesteśmy przy czytnikach ekranu, to zagnieżdżanie w sobie interaktywnych elementów może prowadzić do konsternacji. Użytkownik nie będzie wiedział, czemu strona ma przycisk „Kup teraz” oraz link „Kup teraz” i czemu jedno z nich wydaje się nie działać (lub czemu obydwa robią to samo).
Zresztą ten problem można także odtworzyć na przykładowej stronie. Jeśli sfocusujemy link, w którym jest przycisk (trzeci tab stop), to wówczas po naciśnięciu Entera/spacji nic się nie stanie. Akcja jest bowiem przypisana dopiero do przycisku. Gdyby nasz link miał nieco większy
padding
, to można byłoby nawet powtórzyć to samo przy pomocy myszki.
Jaka jest zatem alternatywa? Po prostu ostylować link identycznie jak przycisk lub przycisk identycznie jak link. Tego typu rozwiązanie jest zdecydowanie mniej problematyczne niż wzorzec polegający na zagnieżdżaniu tych elementów. Niemniej wciąż wprowadza to niekonsystencję doświadczenia, sprawiając trudności m.in. w czasie używania programów do kontroli głosem (użytkownik widzi przycisk, więc instruuje program, żeby kliknął przycisk i nic się nie dzieje, bo ten przycisk to w rzeczywistości link). W idealnym świecie linki wyglądałyby jak linki a przyciski jak przyciski. W naszym świecie wydaje się, że a[role=button]
to – na chwilę obecną – najlepsze, co mamy.