HTML: погані сторони
Ймовірно, ви чули заяви типу «HTML і так за замовчуванням має accessibility» або «Не потрібно винаходити цей абсолютно ідеальний елемент управління HTML». Я вважаю, що це загальні заяви, а чи не універсальні істини. Веб-розробникам дуже важливо усвідомлювати недоліки платформи, тому я вирішив зібрати кілька прикладів того, коли у HTML виникають труднощі з точки зору як accessibility, так і usability.
Це неповний список, і він не включає недоліки ARIA. Мені хотілося знайти баланс між широко відомими проблемами і найчастіше зустрічаються (але менш відомими), а також додати до списку те, що ми сприймаємо як належне. У кожному розділі я вкажу ступінь серйозності проблеми, альтернативні рішення та посилання, за якими можна знайти більш детальну інформацію.
<select multiple>
Почнемо з простого. Атрибут multiple
елемента <select>
не варто використовувати практично ніколи. Він нагадує повну протилежність одиночного <select>
. Єдине, що його виправдовує, то це те, що я поки не зустрічав цей атрибут в жодній кодовій базі.
Цитата користувача програми для читання екрана (з чудової статті Сари Хіглі, посилання на яку наведено нижче):
Це зламаний listbox. Він зовсім поламаний, я не бачу, як це можна виправити.
Серйозність : висока. Є велика ймовірність того, що більшість ваших користувачів не вміє працювати з цим жахливим елементом керування.
Що використовувати замість : цілком підходяща альтернатива – список чекбоксів; або можна створити власний listbox із множинним вибором.
Додаткове читання : <select> your poison part 2: test all the things (стаття Сари Хіглі).
<i> (для піктограм)
Ще один простий приклад для розігріву. Елемент <i>
семантично несуттєвий, тому необов’язково «поганий», якщо використовується для звичайного текстового вмісту. Однак найчастіше він застосовується для шрифтів значків.
У звичайній ситуації я навіть не став би включати його до списку, адже це більше помилка розробників, ніж проблема платформи. Проте вже 2024 рік, а я, як і раніше, зустрічаю елемент <i>
, що використовується з чимось на кшталт FontAwesome. Це проблемно в основному тому, що веб-шрифт використовується для заміни текстових символів (які можуть мати одне значення) на значки (які ніяк не пов’язані з текстовими символами). сторінки та за промовчанням будуть включені в accessibility-дерево. Крім того, вони погано виглядають, часто (і непередбачувано 🐴) ламаються, призводять до інших проблем з accessibility. Докладніше про всі ці проблеми можна дізнатися з поста Тайлера Стіка, посилання на який наведено нижче.
Серйозність : низька або середня. Можна підвищити accessibility, виключивши його з accessibility-дерева (за допомогою aria-hidden
) і задавши текстову альтернативу (за допомогою візуально прихованого тексту ), але елемент все одно залишається проблематичним.
Що використовувати замість : SVG! У них хороша підтримка, і вони у багатьох відношеннях кращі. На відміну від шрифтів SVG призначені саме для відображення графіки, тому через них в accessibility-дереві не з’явиться несподіваний текст. Крім того, їх можна застосовувати безліччю різних способів, так що ви можете вибирати: вбудовувати їх, використовувати спрайти або зберігати всередині CSS (за допомогою mask
).
При використанні <svg>
слід застосовувати наступний надійний патерн: aria-hidden
разом із додатковим альтернативним текстом (який за потреби можна візуально приховати). Наприклад, розмітка кнопки виглядає так:
<button>
<svg aria-hidden="true"><use href="#heart" /></svg>
<span>Favorite</span>
</button>
Додаткове читання : Seriously, Don’t Use Icon Fonts (стаття Тайлера Стіка)
<ul> та <ol>
Неможливо скласти список проблемного HTML та не включити до нього ці списки.
Я не кажу «не користуйтеся списками», у багатьох ситуаціях вони дуже корисні. Але розробники схильні використовувати їх занадто активно, часто просто видалити стилі списків. Іноді ми навіть причіплюємо до них роль ARIA (перевизначаючи таким чином семантику списку), або, гірше за те, додаємо дочірні елементи без <li>
стилізації або чогось іншого (створюючи таким чином неприпустиму розмітку). У всіх таких ситуаціях ми втрачаємо всі переваги елементів-списків та потенційно додаємо нові проблеми.
На це надмірне використання списків звернули увагу розробники Safari та почали в деяких випадках видаляти семантику списків; списки, що знаходяться зовні nav
та стилізовані list-style: none
, Safari списками не вважає. Хоча наміри розробників були хорошими, це призвело до того, що навіть правильно стилізовані списки стають виключно візуальними.
Крім того, упорядковані списки теж мають власні дива. Браузери вважають номери елементів «візуальними», тому при виборі та копіюванні списку номери не включаються до текстового елемента буфера обміну. Це порушує очікування користувачів, особливо якщо номери для них важливі, наприклад, у разі юридичних документів.
Серйозність : низька або середня. Я думаю, що цілком нормально дозволити Safari/VoiceOver робити те, що вони роблять; їх користувачі звикли до цього і навіть можуть очікувати, що веб майже немає списків. Проблема впорядкованих списків та буфера обміну може бути досить серйозною, але її можна вирішити обхідними шляхами.
Що використовувати замість : якщо вам сильно потрібно зберегти семантику списків, то <ul>
можна додати role="list"
. Якщо ви використовуєте іншу роль, то цілком підійдуть звичайні <div>
. Ще однією потенційною альтернативою для пар «ключ-значення» може бути <dl>
.
<ul role="list">
<li>…</li>
<li>…</li>
<li>…</li>
</ul>
Якщо важливими є номери пунктів списку, можна спробувати використати невпорядковані списки, в яких числа — частина текстового вмісту.
Додаткове читання : “Fixing” Lists (стаття Скотта О’Хара), пост у Twitter Джеймса Крейга з Apple та “I Blame the W3C’s HTML Standard for Ordered Lists” (стаття Сібіли Бостонієнсіс).
Атрибут title
Атрибут title
напружує мене найбільше, зокрема, через його довгу історію. Він настільки поганий, що у специфікації HTML прямим текстом не рекомендують використовувати його. Проте я зустрічав цей атрибут у кожній кодовій базі, з якою працював.
Ось лише деякі з безлічі проблем title
:
- Зрячі клавіатурні користувачі ніяк не зможуть отримати доступ до вмісту
title
. - Користувачі з сенсорними екранами також не можуть отримати доступ до вмісту
title
. - Стандартну стилізацію підказок (tooltip) не можна змінити ніяким способом.
- Над тригером потрібно тримати покажчик довільно довгий час, перш ніж з’явиться.
- Підказку, що спливає, неможливо закрити без переміщення вказівника, тому вона може закривати інші частини сторінки.
- На підказку неможливо навести покажчик, тобто миша повинна знаходитися над елементом тригера. Тому підказку може перекрити курсор миші, її текст неможливо вибрати, а користувачі екранної лупи не зможуть переглянути її.
- Текст усередині спливаючої підказки не масштабується разом з рівнем користувача зуму.
- Перенесення довгого тексту всередині підказки неможливо реалізувати; в деяких браузерах він стає шириною з екрана (навіть виходячи за межі вікна браузера), і тільки потім починає працювати перенесення.
- Не можна вказати, чи має
title
бути частиною імені або опису елемента (або ні те, ні інше). - Програми для читання екрана по-різному читають вміст
title
у різних елементах.
Серйозність : висока. Використовуючи цей атрибут, ви навмисно вибираєте зниження accessibility для більшого відсотка користувачів.
Що використовувати замість : у багатьох випадках достатньо включити текст у вигляді частини вмісту елемента; при необхідності цей текст може бути візуально прихований. В інших випадках aria-labelledby
або aria-describedby
працюють краще, ніж title
. Один із винятків — це iframe, які потрібно розмічати за допомогою title
.
Майже у всіх випадках, поряд з описаними вище техніками, краще, ніж title
підійде власна підказка. Однак у підказок є свої проблеми, тому ще краще буде перепроектувати так, щоб повністю позбутися необхідності підказок. Наприклад, завжди можна відображати текст або використовувати паттерн disclosure.
Додаткове читання : The Trials and Tribulations of the Title Attribute (стаття Скотта О’Хара) і Using the HTML title attribute (стаття Стіва Фолкнера).
<datalist>
Спочатку елемент datalist
видається успішною альтернативою своїх комбобоксів. Однак чим більше ви його використовуєте, тим глибшим стає розчарування.
- Стандартна стилізація елемента вкрай сумнівна.
- У десктопному Chrome він відображається як дивно зміщений спливаючий контейнер (popover), який різко змінює своє місце розташування, коли користувач вводить текст; одночасно він від’єднується від елемента введення, коли користувач прокручує сторінку.
- У Chrome під Android він відображається поверх віртуальної клавіатури (а не на сторінці) і лише у портретному режимі.
- Його зовнішній вигляд неможливо налаштувати. Він не враховує навіть
color-scheme
. - Він не враховує розмір користувача шрифту і рівень зуму.
- В цілому він добре підтримується десктопними програмами читання екрана, але на мобільних для взаємодії з опціями необхідно перейти до кінця сторінки.
- У Firefox під Android він взагалі не працює!
Серйозність : середня або висока. У кращому випадку цей елемент може бути корисним як необов’язкова підказка полів введення, які будуть повністю робітниками без додаткової допомоги з боку опцій автоматичного завершення.
Що використовувати замість : <select>
або власний комбобокс.
Додаткове читання : Under-Engineered Comboboxen? (Стаття Адріана Розеллі)
<input placeholder>
Текст-заповнювач повинен допомагати користувачеві, підказуючи, коли поле введення порожнє. Насправді він часто виконує зворотну функцію.
Текст-заповнювач зазвичай схильний до проблем контрастністю кольорів. Якщо спробувати виправити контрастність кольорів, то він може стати невідмінним від реальних значень, що вводяться. Якщо помістити в нього важливу інформацію (наприклад, вимоги до пароля), то значення, що вводиться, приховує цю важливу інформацію відразу після того, як користувач почне друкувати.
Серйозність : середня або висока. У найкращому разі його можна ігнорувати. У гіршому він може дратувати користувачів та шкодити прибутку.
Що використовувати замість : може, нічого? Цілком можливо досить помітного label. Якщо вам потрібен текст підказки, можна розмістити його зовні поля введення і зв’язати їх за допомогою aria-describedby
.
<label for="phone">Phone number</label>
<input id="phone" aria-describedby="phone-hint" />
<div id="phone-hint">Example: 123-456-7890</div>
Додаткове читання : Don’t Use The Placeholder Attribute (стаття Еріка Бейлі)
<input type=number>
Числові поля введення виконують інкремент/декремент під час використання колеса миші, жестів чи клавіш зі стрілками, внаслідок чого вкрай ймовірні неприємності.
І це на додаток до інших проблем з accessibility, узгодженістю та стилізацією.
- Деякі браузери мовчки ігнорують нечислове введення без будь-якого зворотного зв’язку.
- Інші браузери дозволяють вводити довільні числа, але запускають події з порожніми значеннями, втрачаючи таким чином дані, введені користувачем.
- Кнопки зі стрілками дуже малі та їх складно натискати.
- Кнопки зі стрілками неможливо стилізувати (крім простої схеми кольору).
Серйозність : висока. Щоб відмовитися від елемента, достатньо проблеми зі скролінгом, тому що користувачі можуть ввести неправильне число, навіть не зрозумівши цього.
Що використовувати замість : <input inputmode="numeric" pattern="[0-9]*">
. Атрибут inputmode
допомагає відображати на пристроях із сенсорним екраном зручнішу клавіатуру, а атрибут pattern
допомагає з валідацією.
Додаткове читання : Why the GOV.UK Design System
<input type=date>
Нативні елементи вибору дати мають неузгодженість у браузерах, а деякі їх частини порушують accessibility.
- У десктопному Chrome на кнопку календаря неможливо перейти клавішею Tab.
- У десктопному Safari елемент вибору дати не можна закрити з клавіатури.
- У десктопному Safari елемент вибору дати має крихітний розмір і неможливо збільшити.
- У Chrome та Firefox під Android в елемент вибору дати не можна нічого ввести, тому доводиться використовувати незручний UI календар, навіть якщо користувачу відома дата.
У всіх середовищах формат даних відображається як текст-замінник, який, як ми вже з’ясували, викликає проблеми. Формат дати визначає браузер і він може вибрати щось дивне (наприклад, формат дати США), що призводить до непотрібних труднощів.
Серйозність : висока. Ці неузгодженості не просто невеликі незручності, вони створюють реальні перешкоди для accessibility.
Що використовувати замість прості поля введення тексту, а в деяких випадках навіть select.
Також можна використовувати окремі поля для дня/місяця/року та згрупувати їх за допомогою fieldset. Цей fieldset навіть можна стилізувати так, щоб він виглядав, як одне суцільне поле форми . Однак якщо ви вирішите сховати label поля введення, то я б рекомендував відображати формат дати поза поля вводу (як частина легенди або під полями введення).
Відомо, що власні елементи введення дати дуже складно реалізувати правильно, тому якщо вирішите створити їх, вони повинні бути опціональними і доповнювати поля введення тексту.
Додаткове відео : What makes an accessible date picker? Is it even possible? (Доповідь Расса Уїклі)
<menu>
Просто не користуйтеся ними. Якої б поведінки ви не очікували від цього елемента… ви, швидше за все, помилитеся. Спочатку елемент <menu>
мав на увазі як “контекстне меню”, але його так і не реалізували, а тепер він замінений <ul>
.
Серйозність : низька. <menu>
просто перетворюється на <ul>
.
Що використовувати замість : оскільки термін «меню» перевантажений значеннями, це залежить від того, що ви хочете зробити. Ось деякі з альтернатив:
<ul>
(абоrole="list"
), якщо у вас є список.role="menu"
якщо у вас меню в десктопному стилі.role="listbox"
, коли у вас щось нагадує власний<select>
.<dialog>
абоrole="dialog"
якщо у вас стандартний спливаючий контейнер (можливо, зrole="list"
всередині).
Варто зазначити, що деякі з цих ролей вимагають підключення взаємодій із JavaScript.
Додаткове читання : Be Careful Using ‘Menu’ (стаття Адріана Розеллі)
<button disabled>
Відключені кнопки чомусь активно використовують, можливо через їхню звичність. Ось два популярні сценарії застосування відключених кнопок:
- коли дія тимчасово недоступна, наприклад через те, що потрібна якась обов’язкова задача (наприклад, вибір елемента або правильне заповнення форми).
- при відправленні форми, щоб уникнути повторного відправлення.
Однак атрибут disabled
не просто запобігає клікам. Він також вимикає функції hover та focus. І це має багато негативних наслідків. Вимкнені кнопки не можуть відображати підказки (які можуть пояснювати, чому кнопка вимкнена). Клавіатурні користувачі не можуть дістатися до вимкнених кнопок через Tab. Якщо кнопка раптово стає вимкненою (наприклад, при відправленні форми), фокус може загубитися і збити з пантелику. Крім того, відключені кнопки звільняються від вимоги контрастності кольорів , підвищуючи ймовірність їх поганої контрастності.
Серйозність : висока. Відключені кнопки зручні (та й то не особливо) тільки для невеликого відсотка бази користувача.
Що використовувати замість : aria-disabled="true"
і вручну вимкнути кліки. Однак, при можливості, переробте дизайн так, щоб він не вимагав відключених кнопок.
Додаткове читання : Making Disabled Buttons More Inclusive (стаття Сандрини Перейра)
<video>
Нативний програвач відео, як і раніше, має безліч проблем з accessibility і usability. У багатьох браузерах у клавіатурних користувачів виникає проблема з фокусом, тому що вони можуть дістатися не всіх елементів управління, і ці елементи пропадають після початку відтворення відео. У деяких аспектах він незручний і для користувачів програм читання екрана, особливо у разі «просунутих» функцій на кшталт режиму «картинка у картинці».
Рекомендую прочитати наведену нижче статтю Адріана Розеллі, щоб глибше вивчити підтримку цього елемента в різних браузерах і програмах читання екрана.
Серйозність : середня або висока.
Що використовувати замість : точно не знаю. Можливо, альтернативний програвач відео, якщо він розроблявся з урахуванням accessibility. Але чим би ви не користувалися, не забудьте додати підписи та транскрипції, а також надайте можливість скачування відео для його перегляду у зручному для користувача плеєрі. І заради піклування про користувачів не застосовуйте autoplay
.
Додаткове читання : Browser Video Players Review (стаття Адріана Розеллі)
Протоколи посилань (tel:, mailto:)
Посилання в Інтернеті можуть мати протокол, що не відноситься до http на кшталт mailto:
або tel:
. Ці протоколи активно використовують, щоб допомогти користувачам (або спамерам) надіслати електронний лист або набрати номер. Однак дуже сміливо було б вважати, що користувач заходить на сайт з того ж пристрою, який буде використовуватися для надсилання електронного листа або набору телефонного номера, і що він хоче використовувати для цього програму за промовчанням. Це може призвести до роздратування, коли користувач просто шукає спосіб скопіювати номер або набрати його з іншого пристрою. Найгірше, адресу пошти/номер часто приховують під посиланням, відображаючи замість нього щось марне типу «Написати мені».
Серйозність : низька або середня. Це дратує і збиває з пантелику, але, напевно, нічого особливо страшного в цьому немає. Користувачі знаходять способи вирішити проблему.
Що використовувати замість : просто покажіть реальну адресу пошти або номер телефону. Його можна легко скопіювати або перенести вручну на потрібний пристрій. Крім того, багато пристроїв автоматично відображають підказку під час вибору тексту, який можна розпізнати як пошту/номер.
Додаткове читання : tel: me.about.it. (Стаття Браяна Керделла)
Підведемо підсумок
На завершення хочу повторити, що з реалізації accessibility недостатньо «просто використовувати HTML». Навіть маючи найкращі наміри та використовуючи абсолютно правильну розмітку HTML, можна створити UI без потрібного рівня accessibility, якщо підійти до справи без старанності.
Я впевнений, що за десять років цей список буде виглядати інакше (і, сподіваюся, стане коротшим). Чим більше людей цікавитиметься цією темою, тим доступнішою стане інформація. Це змусить органи стандартизації та постачальників браузерів удосконалювати платформу та наблизити нас до Інтернету з більшим ступенем accessibility. Ви особисто можете допомогти, повідомляючи про нових баг або коментуючи вже знайдені: