Турникет: формы и место, где продукты теряют людей
Всё, что продукт обещает, обналичивается в форме. И это единственное место, где мелкая ошибка заставляет человека уйти совсем, — притом что платформа почти всё уже решила за тебя бесплатно.
Двенадцать полей. Ты заполняешь все, жмёшь «Отправить», страница перезагружается: сверху красная строка «некорректный ввод», поле пароля пустое, выбранная дата пропала, и нигде не сказано, какое именно поле не понравилось.
Это чувство ты знаешь в точности — с принимающей стороны. Стоит заметить другое: всё в нём было чьим-то решением. Включая решение очистить поля.
Формы — место, где продукты теряют людей. Регистрация, оплата, бронирование, поиск, публикация — всё ценное, что делает пользователь, проходит через форму. И это та часть интерфейса, где браузер уже сделал бо́льшую часть работы, если ему позволить.
Используй элемент form
Самая частая современная ошибка — набор div-ов с обработчиком клика, который дёргает API. В демо работает и тихо теряет кучу поведения, которое приходило вместе с настоящей формой бесплатно.
Настоящая форма отправляется по Enter в текстовом поле — а именно так отправляет формы огромная доля людей, и они никогда не сообщат, что этого не хватает, они просто решат, что сайт сломан. Она позволяет браузеру предложить сохранить, а потом подставить учётные данные. Она даёт одно событие отправки вместо россыпи обработчиков. Она работает, когда JavaScript не загрузился или упал, — а это не гипотетическое состояние, это любое дрянное соединение и любой блокировщик рекламы в плохой день.
Тот же довод, что и в статье про семантику, применённый к самой рискованной части страницы: настоящие элементы приносят поведение, которое иначе ты напишешь хуже.
У каждого поля есть подпись и тип
Два атрибута несут бо́льшую часть качества формы.
Подпись, всегда, привязанная к полю. Не плейсхолдер. Плейсхолдер исчезает, как только человек начал печатать, — ровно тогда, когда сильнее всего нужно вспомнить, о чём спрашивали, — он проваливается по контрасту и делает заполненное поле неотличимым от пустого при беглом взгляде. Подпись над полем, связанная через for, чтобы клик по подписи ставил фокус в поле, а скринридер произносил вопрос.
Правильный type. Здесь форма, собранная на ноутбуке, ломается на телефоне. type="email" даёт клавиатуру с собакой; type="tel" — цифровую панель; type="url", type="date", type="number" меняют то, что достанется пальцам. Неверный тип — маленький налог, взимаемый с каждого мобильного пользователя каждый раз.
Дальше добавь autocomplete. Это самый недоиспользуемый атрибут во фронтенде: autocomplete="email", "given-name", "street-address", "cc-number", "one-time-code". Правильные значения позволяют браузеру подставить адрес одним касанием и вставить код из СМС, не выходя из приложения. Неверные или отсутствующие превращают пятнадцатисекундную задачу в полторы минуты набора.
Проси меньше
Каждое поле чего-то стоит, и платят за него люди, закрывшие вкладку.
Поэтому полезный вопрос к каждому: что реально сломается, если не спрашивать? Маркетингу нужен телефон, а кто и зачем будет звонить, никто не решил. Форма просит название компании, которое дальше нигде не появляется. Регистрация хочет дату рождения ради возрастного ограничения, которое проверяется вопросом «да/нет».
Две смежные привычки. Не дели то, что человек считает одним: одно поле «имя» лучше, чем «фамилия/имя/отчество», для большей части мира, а один адрес лучше пяти. И принимай форматы, которые люди действительно набирают: пробелы в номере карты, дефисы в телефоне, лишний пробел после вставки. Убрать это самому — одна строка; заставить пользователя — потерять часть пользователей.
Проверяй вовремя
У проверки есть проблема момента, и неверный момент ощущается как придирка.
Проверять на каждое нажатие — значит сообщать человеку, что его почта некорректна, на третьем символе. Проверять только при отправке — значит позволить заполнить двенадцать полей, чтобы потом сказать, что второе не годится.
Работает такое правило: проверяй, когда человек ушёл из поля, а после того как ошибка на поле уже появилась, перепроверяй по мере набора — чтобы ошибка снималась в момент исправления, а не при следующей отправке. Успех молчалив: отсутствия претензии достаточно.
И встроенная проверка везёт довольно далеко вообще без кода: required, type, min, max, pattern, minlength. Она срабатывает до отправки, она в браузере, а состояния можно оформить через :invalid и :user-invalid — второй срабатывает только после того, как человек реально повзаимодействовал с полем, и почти всегда нужен именно он.
Про одно стоит сказать прямо: проверка на клиенте — это удобство, а не защита. Обойти её в инструментах разработчика можно за десять секунд. Сервер проверяет всё заново, всегда, — по-настоящему эту историю рассказывает сфера «Безопасность», но правило абсолютное.
Ошибки, которые помогают
В полезном сообщении об ошибке три части: что произошло, почему и что теперь делать. В «некорректном вводе» нет ни одной. В «этот адрес уже зарегистрирован — войдите или используйте другой» есть все три.
Где оно появляется, важно не меньше, чем что в нём написано. Сообщение стоит у поля, а не только в сводке сверху, и должно быть доступно вспомогательным технологиям: полю ставится aria-invalid, сообщение связывается через aria-describedby, чтобы скринридер прочитал проблему при попадании фокуса. При отправке переводи фокус на первое поле с ошибкой — иначе человеку с клавиатуры сообщили, что где-то в форме проблема, и предложили её искать.
И ни при каких обстоятельствах не очищай поля. Потеря набранного — самое бесящее, что форма может сделать, и это всегда баг, а не мера безопасности.
Состояния, которые никто не проектирует
У формы больше состояний, чем «пустая» и «заполненная», и доверие теряется именно в нелюбимых:
Отправка идёт. Кнопка обязана стать недоступной и сказать, что что-то происходит, иначе люди нажмут трижды и ты создашь три заказа. Каждый раз.
Отправка провалилась. Сеть отвалилась с их данными на полпути. Сохрани всё, что они набрали, скажи, что случилось, и дай повторить без перенабора.
Длинную форму прервали. У человека зазвонил телефон на десятой минуте заявки. Сохранение черновика в локальное хранилище по ходу — несколько строк кода, которые превращают потерянную заявку в продолженную.
Отправка удалась. Скажи, что произошло и что дальше. Форма, которая просто опустела, оставляет человека гадать, не отправить ли ещё раз.
Собери форму один раз, но как следует
Это хрестоматийный случай для идеи сферы «Как учиться» о намеренной сборке чанков. «Форма» — одна из той дюжины структур, которые ты будешь строить до конца карьеры, и быстрее всего она осваивается так: собрать одну эталонную реализацию, осознанно, со всеми состояниями — пустое, в фокусе, заполненное, невалидное, отправляется, провалилось, удалось, — а через неделю собрать её заново с нуля, не подглядывая в первую.
Работу делает именно пересборка, и именно её все пропускают. Мучительное вспоминание, снимается ли ошибка по вводу или по уходу из поля, — ровно то усилие, которое превращает набор отдельных фактов в один блок, который ты потом развернёшь не задумываясь.
Форма — разговор, в котором вопросы задаёт только одна сторона. Минимум, который ты можешь сделать: спрашивать мало, спрашивать понятно и не терять ответы.
На практике
Заполни собственную форму с телефона, одной рукой, как посторонний. Не тестовый аккаунт с сохранённым автозаполнением, а свежий, только большим пальцем. Всё, что с ней не так, всплывает секунд за девяносто.
Посчитай поля и удали одно. И спроси, что реально сломается. Делай это каждый раз, когда собираешь форму; ответ часто — «ничего».
Выключи JavaScript и попробуй отправить. Если не происходит вообще ничего, ты собрал форму, которая существует условно.
Проверь с автозаполнением браузера и с менеджером паролей. Неверные значения autocomplete вылезают мгновенно.
Напиши тексты ошибок раньше счастливого пути. Иначе это та часть, которую ты напишешь последней, уставшим, в два слова.
Держи личную эталонную форму со всеми семью состояниями и копируй из неё. Это твой чанк, вынесенный наружу, — а пересборка по памяти раз в квартал держит его живым.
Проверь себя
Закрой статью и ответь своими словами:
- Назови четыре вещи, которые даёт настоящий элемент
formи не даётdivс обработчиком клика. - Почему плейсхолдер не годится в качестве подписи?
- Что меняет атрибут
typeдля мобильного пользователя и что меняетautocomplete? - Когда стоит проверять поле и когда ошибка должна сниматься?
- Почему проверка на клиенте никогда не является мерой безопасности?
- Из каких трёх частей состоит полезное сообщение об ошибке и где оно должно появляться?
- Перечисли состояния формы помимо пустой и заполненной и скажи, что ломается, если пропустить каждое.
Коротко
- Формы — место, где продукты теряют людей, и место, где платформа уже сделала за тебя бо́льшую часть работы.
- Используй настоящий
form: отправка по Enter, сохранение пароля, одно событие отправки и поведение, переживающее падение JavaScript. - Каждому полю нужны настоящая подпись через
for, правильныйtypeради вызываемой клавиатуры и корректное значениеautocomplete. - Проси меньше: каждое поле стоит пользователей, одно поле имени лучше трёх, а приём «грязных» форматов — одна строка твоего кода вместо трения для всех.
- Проверяй по уходу из поля, перепроверяй по ходу исправления, пользуйся встроенными атрибутами проверки — и всегда проверяй заново на сервере.
- Ошибка говорит, что произошло, почему и что делать, стоит у поля, объявляется вспомогательными технологиями и никогда не стирает набранное.
- Спроектируй нелюбимые состояния: отправляется, провалилось, прервали, удалось.
- Собери одну эталонную форму со всеми состояниями, а через неделю пересобери по памяти — именно пересборка превращает её в чанк.