Привет, Хабр!

Мне нравятся красивые и удобные интерфейсы. С самого начала карьеры я всегда старался делать всё, что мог для комфорта пользователя. Этим я выделялся среди коллег. Большая часть из них не тратили время, продумывая взаимодействие пользователя с интерфейсом.

Я даже думал, что есть разработчики, которые специально хотели помучить пользователей. К сожалению, тогда я ничего не знал об ужасных интерфейсах, поэтому не мог помочь им. Хочу исправиться!

Сегодня я рассмотрю несколько практических ловушек, из-за которых пользователи вспомнят разработчиков не очень хорошим словом. Будьте в этом уверены. В основном мы будем использовать только HTML. Так что вы быстро сможете внедрить их в свои проекты.

Давайте посмотрим, что я вам подготовил.

Заставьте вводить данные карты с помощью маленьких клавиш

Формы редактирования — это важное место для мук пользователя, но они точно уступают платёжным. Тут уже можно мучить очень много людей. А главное сделать это очень просто.

Я нашёл отличный пример. Давайте попробуем добавить данные банковской карты для будущих покупок, используя смартфон. Начнём с номера карты.

Интерфейс отображает стандартную клавиатуру, на которой клавиши с цифрами очень маленькие. По ним сложно попасть. И это всё благодаря тому, что разработчики используют стандартный тип text для элемента type.

<!-- другие элементы -->
<div class="input-wrap--uGxpV">
  <input type="text" id="card_num" autocomplete="off" placeholder="0000 0000 0000 0000" maxlength="23" class="input--KtU1U" name="cardNumber">
  <label for="card_num" class="label-floating--VkVBY"><span class="name--uX6pJ">Номер карты</span></label>
</div>
<!-- другие элементы -->

Думаете, это единственное поле с таким типом ввода? Нет! Давайте посмотрим на поле для ввода месяца и года.

Конечно же у элемента input такое же значение для атрибута type.

<!-- другие элементы -->
<div class="input-wrap--uGxpV">
  <input type="text" id="card_exp" autocomplete="off" placeholder="MM/YY" class="input--KtU1U" name="expiration">
  <label for="card_exp" class="label-floating--VkVBY"><span class="name--uX6pJ">ММ/ГГ</span></label>
</div>
<!-- другие элементы -->

Мы видим тот же тип type. Прекрасно! Пусть пользователи мучаются.

Это отличные примеры использования атрибута type для плохих интерфейсов. Номер и дата действия карты относятся к числовому типу данных, т. е. при их вводе нужны только цифры.

Важно ещё то, что разработчики не используют атрибут inputmode. Значение numeric помогло бы отобразить более удобную виртуальную клавиатуру. И вся работа была бы проделана зря. Ловушки бы не было.

Сделайте кнопку очистки поля ввода недоступной с клавиатуры

Пользователям часто приходится заполнять формы. Я всегда говорю, что это отличный способ сделать его жизнь сложнее. У многих форм есть возможность очистки поля. Для примера я нашёл сайт, на котором можно создать объявление.

Лично я, когда хочу воспользоваться функцией очистки поля, нажимаю клавишу Tab, ожидая, что интерфейс перенесёт меня на кнопку. Попробуем сделать так же в нашем примере.

Интерфейс пропустил кнопку! Конечно, я сразу стал смотреть причину такого поведения.

<!-- другие элементы -->
<button type="button" class="styles-module-root-HrOiI" tabindex="-1" aria-label="закрыть" data-marker="title-field-23/clear">
  <svg class="styles-module-closeIcon-PK8hJ" width="100%" height="100%" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="M9.00001 10.8428L16.15 17.9928L17.5642 16.5786L10.4142 9.42857L17.5643 2.27851L16.1501 0.864296L9.00001 8.01436L1.84994 0.864296L0.43573 2.27851L7.58579 9.42857L0.435787 16.5786L1.85 17.9928L9.00001 10.8428Z" fill="currentColor"></path>
  </svg>
</button>
<!-- другие элементы -->

Сначала я увидел элемент button и подумал, что всё в порядке. А потом пригляделся и очень сильно удивился. Разработчики добавили атрибут tabindex со значением -1. Так была отключена интерактивность элемента. Класс!

Но самая главная фишка этого решения в другом. Я уверен, что разработчики с помощью элемента button пытались скрыть использования атрибута tabindex. Представьте, как сложно продвинуть такую ловушку в продакшен.

Есть же код-ревью. Тестировщики. И всё это. А так смотришь на код, видишь элемент button и не подозреваешь проблем.

Прячьте обводку вокруг интерактивных элементов

Очень давно многие авторы статей по веб-разработке говорят, что не надо использовать свойством outline со значением none. Очень жаль, что многие следуют этому совету, но есть и те, кто придумал гениальную хитрость.

Я нашёл проект, где её реализовали. Давайте попробуем переключаться по интерфейсу клавишей Tab, чтобы посмотреть, как отображается обводка.

К сожалению, сначала голубая обводка хорошо заметна на белом фоне. Но давайте посмотрим, что будет на кнопке «Найти».

Вот, где гениальная задумка! Обводка сливается с цветом кнопки. Теперь её просто так не найти. Таким образом разработчики сначала расслабляют пользователя чётким восприятием обводки, а потом её прячут.

Сто процентов придётся хорошенько напрячь глаза, чтобы увидеть обводку. Истинные пропагандисты ужасного интерфейса!

А главное, что ещё не факт, что эту ловушку быстро найдут тестировщики или дизайнеры. Все посмотрят, что на белом фоне обводка заметна, да и успокоятся. Так что супер решение!

Минимизируйте количество заголовков в разметке

Заголовки — важный элемент, который пользователи используют для ориентации по сайту. Быстро визуально находим все заголовки на странице и уже понимаем основную структуру.

Тут сложно усложнить пользователям жизнь, поскольку дизайнеры нам не дадут этого сделать. Но есть пользователи скринридеров. Они также используют заголовки для ориентации по странице. Я скажу больше, это один из основных способов понять основные разделы.

В скринридере NVDA можно даже вывести все заголовки в удобный список и навигироваться по нему. Давайте для примера я выведу все заголовки с главной страницы своего личного кабинета.

Мы видим один заголовок первого уровня «Профиль». А теперь посмотрим визуально на страницу.

На ней как минимум есть заголовки разделов «Имя» и «Контактные данные», но для скринридера их нет. Всё дело в том, что вместо заголовков в разметке используется элемент div.

<!-- другие элементы -->
<div class="mb-4">Имя</div>
<div class="form-group">
  <input placeholder="Имя" type="text" class="form-control not-empty" id="profile_name" value="Стас" name="name" required>
  <label for="profile_name">Имя</label>
</div>
<div class="form-group">
  <input placeholder="Фамилия" type="text" class="form-control not-empty" id="profile_last_name" value="Мельников " name="last_name" required>
  <label for="profile_last_name">Фамилия</label>
</div>

<div class="mb-4 mt-5">Контактные данные</div>
<div class="form-group">
  <input placeholder="Электронная п��чта" type="email" class="form-control not-empty" id="profile_email" value="melnik909@ya.ru" name="email" required>
  <label for="profile_email">Электронная почта</label>
</div>
<!-- другие элементы -->

Теперь пользователю скринридера недоступен удобный список и горячие клавиши для переключения между заголовками. Им придётся проходить по каждому элементу, чтобы понять основные разделы страницы.

Не связывайте текстовые подписи с полями для ввода данных

Наряду со свойством outline элемент label наиболее часто встречающийся аспект в статьях о веб-разработке. Вы же видели, что везде пишут: «Используйте элемент label и связывайте его с элементом input».

Меня восхищают люди, которые в 2026 году не следуют этому совету! Это же сколько нужно хитрости и ловкости, чтобы эта ловушка дошла до пользователя. Я не могу упустить шанс показать такую работу.

Однажды я заполнял профиль на сайте с разными историями. В таких формах я часто нажимаю на подписи, чтобы перейти в поле ввода. В этот раз я сделал так же.

Вместо переноса, у меня выделился текст! Я очень сильно удивился и сразу же стал инспектировать код.

<!-- другие элементы -->
<div class="_wrapper_1p9ua_4" data-fullsize="true">
  <div class="_caption_1p9ua_19">Электронная почта</div>
  <div class="_controls_1p9ua_63">
    <input class="_input_1p9ua_31" data-size="normal" data-with-tooltip="false" data-with-icon="false" placeholder="Не указана" type="email" value="melnik909@ya.ru">
  </div>
</div>
<!-- другие элементы -->

Подпись размечена элементом div. Почему это решение лучше для ужасных интерфейсов, чем элемент label?

Да всё просто. Элемент label расширяет кликабельную область элементам input, если они связаны. Таким образом по ним проще попасть пользователю с тремором или травмой руки.

Если используется любой другой элемент, то кликабельность поля ввода ограничивается его размерами. Соответственно, по ним сложнее попасть. Говорю по своему личному опыту. У меня как раз травма руки, и мне каждый раз больно попадать на такие поля.

Заключение

Подведём итог. В этой статье мы с вами рассмотрели советы для создания ужасных интерфейсов. Вот они:

  • Старайтесь прятать обводку вокруг интерактивных элементов так, чтобы она сливалась с фоном.

  • Формы для добавления банковской карты должны заполняться маленькими клавишами виртуальной клавиатуры.

  • Не дайте пользователю клавиатуры попасть на кнопку очистки поля ввода данных.

  • Кликабельная область полей ввода данных не должна быть увеличена с помощью подписки.

  • Минимизируйте количество элементов h1h2h3h4h5 и h6.

Теперь вы знаете, как ухудшить любой интерфейс и сделать из него настоящую пытку для пользователя. Это, разумеется, не полная коллекция вредных техник, но даже то, что я показал, уже гарантирует вам массу «благодарностей». Задача по созданию неудобств — выполнена!

А теперь давайте начистоту. Вы хотите этого? Вы хотите, чтобы ваша работа приносила негатив пользователю?

Я хочу верить, что ваш ответ «нет». Пусть эта статья станет для вас не руководством к действию, а скорее чек-листом, где вы будете вычёркивать все эти «прекрасные» решения как баги, которые обязательно нужно исправить.

На этом всё. Спасибо за чтение!

P. S. Помогаю больше узнать про CSS и дружелюбные интерфейсы в своих закрытых ТГ-каналах CSS isn't magic и UX + Dev = a11y. Присоединяйтесь. Как вступить, написано в профиле.

© 2026 ООО «МТ ФИНАНС»