EverProduct
Фронтенд

Этап 02 · Страница, которая держит удар

Турникет: формы и место, где продукты теряют людей

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

Двенадцать полей. Ты заполняешь все, жмёшь «Отправить», страница перезагружается: сверху красная строка «некорректный ввод», поле пароля пустое, выбранная дата пропала, и нигде не сказано, какое именно поле не понравилось.

Это чувство ты знаешь в точности — с принимающей стороны. Стоит заметить другое: всё в нём было чьим-то решением. Включая решение очистить поля.

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

Используй элемент 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 вылезают мгновенно.

Напиши тексты ошибок раньше счастливого пути. Иначе это та часть, которую ты напишешь последней, уставшим, в два слова.

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

Проверь себя

Закрой статью и ответь своими словами:

  1. Назови четыре вещи, которые даёт настоящий элемент form и не даёт div с обработчиком клика.
  2. Почему плейсхолдер не годится в качестве подписи?
  3. Что меняет атрибут type для мобильного пользователя и что меняет autocomplete?
  4. Когда стоит проверять поле и когда ошибка должна сниматься?
  5. Почему проверка на клиенте никогда не является мерой безопасности?
  6. Из каких трёх частей состоит полезное сообщение об ошибке и где оно должно появляться?
  7. Перечисли состояния формы помимо пустой и заполненной и скажи, что ломается, если пропустить каждое.

Коротко

  • Формы — место, где продукты теряют людей, и место, где платформа уже сделала за тебя бо́льшую часть работы.
  • Используй настоящий form: отправка по Enter, сохранение пароля, одно событие отправки и поведение, переживающее падение JavaScript.
  • Каждому полю нужны настоящая подпись через for, правильный type ради вызываемой клавиатуры и корректное значение autocomplete.
  • Проси меньше: каждое поле стоит пользователей, одно поле имени лучше трёх, а приём «грязных» форматов — одна строка твоего кода вместо трения для всех.
  • Проверяй по уходу из поля, перепроверяй по ходу исправления, пользуйся встроенными атрибутами проверки — и всегда проверяй заново на сервере.
  • Ошибка говорит, что произошло, почему и что делать, стоит у поля, объявляется вспомогательными технологиями и никогда не стирает набранное.
  • Спроектируй нелюбимые состояния: отправляется, провалилось, прервали, удалось.
  • Собери одну эталонную форму со всеми состояниями, а через неделю пересобери по памяти — именно пересборка превращает её в чанк.