Улучшаем опыт взаимодействия с формами

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

Часто меня спрашивают студенты: «Какой элемент сайта самый важный?», на что я им отвечаю — формы. Ведь с помощью форм пользователи совершают почти все конверсионные действия. Именно с этим элементом связано больше всего проблем. В этой статье я постараюсь рассказать, что можно улучшить при взаимодействии с формами. А заодно описать новые возможности работы с ними в браузерах.

Александр Першин подробно рассказывал об этом подходе в своей статье Progressive Enhancement. Если вы до сих пор не сталкивались с ним, то я вам крайне рекомендую прочитать.

Ещё один нюанс: я не считаю, что интерфейс должен работать и выглядеть одинаково во всех браузерах. Я твёрдо уверен в том, что не стоит мучить пользователей со старыми браузерами вашими многокилобайтными библиотеками — им и без этого плохо.

Браузерная статистика рунета

Так как я буду показывать подходы, использующие новые возможности браузеров, взглянем на текущую статистику рунета. Каждый сможет для себя определить степень готовности пользователей. Я разделил её на две категории: полная и частичная поддержка.

Все приёмы в этой статье оценят 56,8% пользователей. В этой статистике присутствуют браузеры: IE 10, Firefox 11-17, Chrome 4-24, Safari 6, Opera 12.

Часть приёмов оценят 80,1% пользователей. Сюда дополнительно включил поддержку: IE 8-9, Safari 4-5, Opera 10-11.

Мобильные браузеры в статистику не включал, хотя они бы дали ещё больший процент поддержки. Информацию брал из LiveInternet со срезом по России. В расчёт попал средний трафик за 3 месяца (октябрь-декабрь) 2012 года.

Новые атрибуты форм в HTML5

Внимание: примеры в этой статье не содержат jQuery кода. Весь JavaScript написан с помощью фреймворка Vanilla JS.

Для начала, напомню о новых атрибутах у полей формы, которые буду использовать: required, autofocus, placeholder.

Вместе с этим появилось много новых типов полей: date, email, number, range и другие. Однако, самое безобидное из них (email), до сих пор используется с опаской. А ведь для того, чтобы оно заработало специальных действий не нужно. Браузеры, которые не знают этот тип полей, будут считать его текстовым.

Также появились дополнительные селекторы в CSS: E:valid, E:invalid, E:required — с помощью которых можно описывать стилевое оформление полей в разных ситуациях.

Демонстрация работы новых атрибутов полей и их оформления.

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

Запись данных формы по мере ввода

Одна из частых проблем заполнения форм — введённые данные теряются. Это может произойти по разным причинам: ошибка сайта, переход по ссылке, в конце концов, может отключиться интернет. Решить эту проблему можно по-разному, например, записывать данные в localStorage по мере ввода.

Валидация формы и отправка данных аяксом

Раз уж мы используем атрибуты required, то можно и валидацию сделать по-новому. В спецификации HTML5 для элемента формы добавлен метод checkValidity(). Он возвращает true или false. Стратегия работы формы будет очень простой: если проверка валидации даёт отрицательный результат — мы блокируем отправку формы, в обратном случае — разрешаем отправку.

Теперь добавим возможность отправлять форму без перезагрузки, с помощью аякс. Со второй версией спецификации XMLHttpRequest мы получили много интересного. Например, мы можем больше не заниматься сбором данных для отправки формы, для этого есть объект FormData.

При работе с асинхронными запросами следует помнить, что некоторые браузеры кэшируют результат. Например, это делает Internet Explorer, Mobile Safari (iOS 6) и другие. Чтобы избежать эту проблему, можно добавлять к адресу запроса текущее время.

Сейчас ответ от сервера мы получаем в текстовом виде (xhr.responseText), но со временем это изменится. Например, если мы точно знаем, что ответом будет JSON, мы можем получить JavaScript объект сразу.

Обратите внимание, что ответ сервера будет в свойстве xhr.response. А свойство xhr.responseType может принимать и другие значения, например: arraybuffer, blob, document.

Демонстрация сохранения данных формы и отправки их с помощью XMLHttpRequest.

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

Предварительный просмотр закачиваемых фотографий

Плавно переходим на работу с файлами в формах. До недавнего времени почти никаких средств для работы с файлами не было. Но всё меняется. Начнём с простого — новые атрибуты для полей загрузки файлов.

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

Хочу напомнить: поле с такими атрибутами будет работать в старых браузерах. Ограничением будет:

Попробуем улучшить опыт взаимодействия с файлами. Раз мы ожидаем от пользователей добавления фотографий, логично сделать возможным предварительный просмотр. Для этого мы будем использовать объект FileReader из спецификации File API.

Таким образом, все выбранные фотографии мы сразу же отображаем на сайте.

А для того, чтобы отправить их с помощью аякса, мы собираем их в массиве queue. Ранее в статье мы использовали объект FormData, сейчас мы просто добавим к нему список файлов.

Только и всего, остальное остаётся таким же. Форма будет отправлена с файлами без перезагрузки.

Демонстрация предварительного просмотра фотографий и отправки их с помощью аякс.

Drag and drop файлов

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

Допустим, зоной для перемещения файлов будет блок с классом wrapper. Добавим события для него.

Как видите, мы добавили события начала (dragover) и конца (drop) перемещения файлов. Все перемещённые файлы мы передаём функции previewImages. Таким образом, наша форма работает одинаково с файлами выбранными через сайт и перемещёнными с компьютера.

Процесс загрузки файлов (progress bar)

Фотографии бывают очень большими, поэтому попробуем отобразить процесс загрузки. Для визуализации этого процесса я возьму элемент progress, а вы можете взять div с двигающимся фоном. Сам процесс будет происходить в событии progress из спецификации XMLHttpRequest.

Демонстрация drag & drop и прогресса загрузки файлов.

В итоге

Наша простая форма имеет ряд значительных улучшений в области UX.

При этом, так как мы действовали в соответствии с прогрессивным улучшением, наша форма работает везде:

Уверен, занимаясь улучшением UX форм, можно найти более интересные решения. Пожалуйста, добавьте ваши решения, советы, критику в комментариях ниже. Спасибо!