Развитие валидации форм

Original author: Ryan Seddon
  • Translation

Валидация форм была педантичным занятием с момента появления web. Первой пришла серверная валидация. Затем она развилась в валидацию на стороне клиента для проверки результатов в браузере. Теперь у нас есть такие гиганты как HTML5 и CSS3: глава о формах HTML5 предлагает нам новые типы для input полей и атрибуты, которые делают возможным проверку ограничений поля. Базовый UI модуль CSS3 предоставляет несколько псевдо-классов, которые помогают нам стилизовать состояние валидности и менять внешний вид поля в зависимости от действий пользователя. Давайте взглянем на комбинацию обоих для создания валидатора форм основанного на CSS, который имеет достаточно широкую поддержку браузеров.

Чем больше мы можем дать подсказок пользователю, как правильно заполнять форму, в процессе заполнения, тем меньше шансов, что он сделает ошибку. Взгляните на пример CSS3 валидации форм в браузере поддерживающем CSS3 UI псевдо-классы, например Chrome 4+, Safari 5+ или Opera 9.6+. Я использовал CSS3 UI псевдо-классы и HTML5 атрибуты форм для создания валидации основанной на CSS. Давайте посмотрим как это работает.


CSS3 UI псевдо-классы


UI модуль содержит несколько псевдо-классов, которые помогают стилизовать поля формы в зависимости от их состояния.
  • valid
  • invalid
  • required
  • optional
  • in-range
  • out-of-range
  • read-only
  • read-write

В демо, показанном выше, я использовал псевдо-классы required, invalid и valid для выполнения проверки.
input:focus:required:invalid {
  background: pink url(ico_validation.png) 379px 3px no-repeat;
}
input:required:valid {
  background-color: #fff;
  background-position: 379px -61px;
}

* This source code was highlighted with Source Code Highlighter.

Так как мы хотим обозначить, что поле является не валидным только когда активно, мы используем псевдо-класс focus, чтобы вызвать стиль invalid для поля (Естественно, обозначать все обязательные поля как не валидные с самого начала будет плохим дизайнерским решением).

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

Все значения псевдо-классов, перечисленных выше, говорят сами за себя. Псевдо-классы in-range и out-of-range должны использоваться в сочетании с атрибутами min и max, будь то поле input[type=range] или любое другое поле принимающее эти атрибуты. Например, если пользователь вводит значение, выходящее за ограничения, мы можем использовать псевдо-класс для изменения стиля, учитывающий это состояние. Кроме того, мы можем сделать то же самое в случае попадания значения в диапазон ограничений.

В данный момент псевдо-классы range поддерживает только Opera. В ближайшее время поддержка появится и у других браузеров.

Дополнительные типы и атрибуты помогающие нам


В HTML5 формы, также внедрены новые типы input, такие как email, url и number. К примеру email вызывает псевдо-класс valid когда пользователь вводит корректный e-mail адрес, тоже самое происходит и для полей numer и url. Проверка поля url отличается в разных браузерах. В Opera набрав "http://" поле обозначается валидным, в Crome "http://w", а в Safari, просто набрав "http:".

Есть еще несколько атрибутов помогающих в проверке поля, такие как placeholder, required, maxlength, pattern, min, max и step.
<input id="postcode" name="postcode" type="number" min="1001" max="8000" maxlength="4" required />

* This source code was highlighted with Source Code Highlighter.

Поле postcode использует новый тип number и несколько новых атрибутов. В Австралии почтовый индекс может состоять, только из 4 цифр, поэтому мы устанавливаем атрибут maxlength, чтобы ограничить его. Мы так же хотим ограничить максимальное и минимальное значение индекса, для этого используются атрибуты min и max. Атрибут required говорит сам за себя(обязательное поле).

Мы можем использовать атрибут step, для большего ограничания совместно с min и max. По умолчанию step установлен в единицу. Поэтому любое число установленное в диапазоне между min и max является валидным. Если изменить значение step на 100, то будет проверяться значение в границах от min до max с шагом 100. Например атрибут step будет валиден при значениях поля 1001, 1101, 1201, 1301 и тд.

Поиск образца


Чтобы вызывать псевдо-класс invalid у поля с более специфичными ограничениями, например у поля номер телефона, мы можем использовать атрибут pattern, который позволяет применять регулярные выражения для проверки значения поля.

<input type="tel" id="tel" name="tel" pattern="\d{10}" placeholder="Please enter a ten digit phone number" required />


* This source code was highlighted with Source Code Highlighter.


В данном примере, регулярное выражение очень простое, «Я принимаю только 10 цифр и ничего больше». Таким образом, поле будет невалидным, пока не выполнится регулярное выражение. Обратите внимание, что я использовал атрибут placeholder, чтобы дать подсказку пользователю.

В реальности мы можем задать более мощные условия в значение атрибута pattern, путем добавления, более сложных регулярных выражений, например для поля пароль:
<input id="password" name="password" type="password" title="Minimum 8 characters, one number, one uppercase and one lowercase letter" required pattern="(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*" />

* This source code was highlighted with Source Code Highlighter.

Теперь мы имеем более строгие ограничения, что позволяет заставить пользователя ввести более безопасный пароль. Пароль должен быть не менее 8 символов, содержать одно число, одну строчную и одну заглавную букву.

Чтобы помочь пользователю, мы используем атрибут title. Мы не используем атрибут placeholder в данном случае, так как он предназначен только для коротких сообщений.

Добавление полезных советов


Если пользователь не наведет курсор на поле, он никогда не увидит дополнительных инструкций в атрибуте title. Вы можете заметить, что для полей phone, postcode и password появляются полезные подсказки, это помогает, когда пользователь нуждается в дополнительных инструкциях.

<input id="password" type="password" />
<p class="validation01">
  <span class="invalid">Minimum 8 characters, one number, one uppercase letter and one lowercase letter</span>
  <span class="valid">Your password meets our requirements, thank you.</span>
</p>

* This source code was highlighted with Source Code Highlighter.

Разметка выше, содержит дополнительные контейнеры для обоих состояний — поле валидно и не валидно. Таким образом, когда поле не валидно, оно будет содержать информацию, которая поможет пользователю ввести корректные данные. Когда все верно, наше сообщение и зеленая галочка убеждают его в том, что поле заполнено верно.
.validation01 {
  background: red;
  color: #fff;
  display: none;
  font-size: 12px;
  padding: 3px;
  position: absolute;
  right: -110px;
  text-align: center;
  top: 0;
  width: 100px;
}
input:focus + .validation01 {
  display: block;
}
input:focus:required:valid + .validation01 {
  background: green;
}
input:focus:required:valid + .validation01 .invalid {
  display: none;
}
input:focus:required:invalid + .validation01 .valid {
 display: none;
}

* This source code was highlighted with Source Code Highlighter.

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

UX проблемы этого подхода


Существует одна главная проблема в использовании псевдо-класса invalid, когда поле является обязательным и существуют дополнительные условия, которые должны быть выполнены. Например когда поле обязательное и его тип email, оно будет не валидно, пока все его условия не выполнены и будут использоваться стили для invalid с самого начала, еще до того, как пользователь ввел что либо. Вот почему мы использовали псевдо-класс focus, что бы показать стили invalid, только когда это поле в фокусе. Это не оптимальное решение: если пользователь уходит из этого поля, не выполнив требования валидатора, не будет показано, что данные введены не корректно, до тех пор, пока он не вернется к редактированию этого поля.

Решением этого былобы добавление неопределенного псевдо-класса, доступного для radio и checkbox input. Технически, поля имеющие больше условий, чем просто required, пока пусты не являются ни валидными, ни не валидными, а скорее неопределенными. Эта идея может исправить состояние invalid и позволит применять оптимальные стили для полей в зависимости от состояния валидации.

Кроме того, мы можем сделать некоторую довольно большую функционатьность без JavaScript. Мы можем сказать какое состояние у поля если оно в фокусе, если требуется, сказать ему соответствовать определенному шаблону, заданному в регулярном выражении, указать минимальные и максимальные значения и многое другое. Но что если этого не достаточно? Что если мы хотим большего? К счастью глава о формах HTML5 так же определяет API проверки ограничений валидации.

API проверки ограничений валидации


Наряду со всеми новыми атрибутами, типами input и CSS3 псевдо-классами, глава о HTML5 формах, так же определяет простой JavaScript API, что позволяет расширять возможности валидации форм несколькими полезными встроенными методами, атрибутами и событиями. Давайте взглянем на обновленное демо, которое подключает API для проверки ограничений валидации.

Каждое поле формы имеет новый атрибут validity. Атрибут validity возвращает объект ValidityState, который предоставляет текущее состояние валидности. Объект ValidityState содержит несколько булевых переменных, которые определяют какое состояние у определенного элемента. В основном их ответы это true/false которые дают возможность разработчику понять что не так с полем:
  • valueMissing
    Этот атрибут возвращает true, если обязательное поле пустое.
  • typeMismatch
    Распространяется на новые типы input. Например, если значение email не корректно, этот атрибут возвратит true.
  • patternMismatch
    Если элемент содержит атрибут pattern и его значение не соответствует условиям регулярного выражения, атрибут вернет true.
  • tooLong
    Если значение какого либо элемента превышает его maxlength, этот атрибут вернет true.
  • rangeUnderflow и rangeOverflow
    Если значение элемента выходит за пределы атрибутов min или max, то этот атрибут вернет true.
  • stepMismatch
    Когда элемент с атрибутом step не соответствует требуемому значению, этот атрибут вернет true.
  • valid
    Если любое из вышеперечисленных значений возвращает true, то этот атрибут вернет false. В противном случае, если все условия выполнятся, то вернет true.

Это еще не все


Событие invalid несет еще одну полезную функцию. Он будет вызываться полем, пока его значение будет оставаться невалидным. Так что, с его помощью, мы можем изменять стили полей в соответствии с их текущим состоянием.

Кроме того, метод checkValidity() может быть выполнен на любом отдельном поле или формы в целом, вернув true или false.

Применим к демо


Давайте возьмем наше предыдущее демо и улучшим его при помощи API проверки ограничений валидации. Принимая то, что мы узнали от Luke Wroblewski в статье Inline Validation in Web Forms и наши собственные данные, мы можем применить эти идеи в нашей демо форме, чтобы создать оптимальный валидатор.

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

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

Если поле имеет некорректное значение, а пользователь переходит к следующему полю, событие blur проверит валидность поля, а потом применит invalid стили. Для того, чтобы пользователь мог знать об ошибке. Это сохранит отображение стилей ошибок, до их исправления.

Что насчет старых браузеров?


Во всех топиках обсуждаются новинки и поддержка современных браузеров, все это хорошо, но двайте не будем забывать о реальном мире, где мы должны поддерживать и устаревшие браузеры. Для этого я написал скрипт помогающий это делать.

Для браузеров не поддерживающих HTML5 формы и API проверки ограничений валидации скрипт эмулирует эту функциональность. Для браузеров поддерживающих эту функциональность, скрипт определит наличие поддержки и выполнится функциональность средствами браузера. Давайте взглянем на очередное обновление демо с добавленным скриптом. Проверьте в IE или Firefox, чтобы увидеть функциональность скрипта, такую же как у браузеров поддерживающих нужную функциональность.

Поддержка браузерами



Скрипт протестирован и работает в следующих браузерах:
  • IE6+
  • Firefox 1+ — FF4 будет иметь встроенную поддержку;
  • Chrome 4+ — Встроенная поддержка;
  • Safari 3.2+ — Safari 5 имеет встроенную поддержку;
  • Opera 9.6+ — Встроенная поддержка.

Функции эмулируемые скриптом:
  • Каждое поле имеет объект validity, который дает возможность узнать текущее состояние;
  • Доступен метод checkValidity() указывающий что форма или какой то отдельный элемент не валиден;
  • Поддержка атрибутов placeholder, required, min, max и step;
  • Поддержка атрибутов placeholder и required для textarea;
  • Поддержка атрибура required для элемента select;
  • Типы email и url для input будут проверяться с помощью встроенного регулярного выражения.

Изобилие проверок


Поддержка браузерами HTML5 форм и моделя CSS3 UI начинает улучшаться. Opera9 продолжит поддержку Web Forms 2.0 пока они не будут объединены с HTML5 формами. В Chrome появилась поддержка с версии 4, Safari получил ее недавно с выходом версии 5, Firefox должен добавить поддержку в предстоящей бета-версии 4 и IE9, если они продолжат свое развитие в таком темпе, тоже должен получить поддержку.

Мы можем сделать удивительные вещи при помощи соответствующих разделов CSS3 и HTML5. Все браузеры улучшают поддержку и такой способ проверки форм становится жизнеспособным, способным проверять любые простые или сложные формы.

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 31

    +1
    Хорошая работа, спасибо.
    Обязательно буду использовать.
      +10
      Все бы хорошо, но конкретная реализация в демо мне не понравилась. Почему как только я встаю курсором в текстовое поле, возникает красная подсказка? Причем я не имею ничего против подсказки, но она не должна пугать своим красным фоном — я ведь пока никаких ошибок не делал. Почему бы не показывать ошибки валидации после потери фокуса полем?
      И насчет ограничения пароля минимум 8 символами соврали — один символ валидацию проходит.
      ЗЫ. ФФ4, последнее демо
        0
        да вообще глупая затея впихивать поведение в css, которое должно отвечать только за отображение, вместо js
        –1
        что-то мне не нравится пути развития css3 и html5. почему смушивается оформление и поведение?
        [input id=«password» pattern="(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*" /]
          +1
          Оформление и поведение пересекаются в вебформах. Уж лучше так, чем без этого.
            +1
            Может, я что-то не понял, но где в приведённом Вами коде есть смешивание оформления и поведения?
              0
              в данном примере то, что заключено в атрибут pattern.
              «идеологически», в хтмл должны указываться лишь элементы, а уже через id (для скриптов) или же class (для css) ими можно оперировать как угодно, т.е. указывать необходимые паттерны или же размер шрифта. в данном же случае есть возвращение к html4.1, где бэкграунд задавался через аттрибут background, например.
                +1
                паттерн валидации — это поведение, а не оформление
                  0
                  да, в первом посте опечатолсо :)
                  я про то, что поведение (так же как и оформление) должно быть отдельно от представления.
                    0
                    Ну как бы так объяснить…
                    Безусловно, они должны быть разделены.
                    Но вэб идет по направлению разгрузки серверов и переноса части задач на клиента.
                    Если все это разделять, то нужно было бы добавить еще некую сущность, или какой-то протокол…
                    Что-то типа HTML/CSS/JS/BP (behavoir patterns), что принесло бы массу проблем и сложностей.

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

                    Конечно, это не исключает серверную валидацию, но чтобы сделать web app более «rich» и не дергать при этом на каждый чих сервер — самое оно
                0
                Я тоже считаю, что это спорный момент. Как я это вижу — мы, с помощью регулярного выражения, описали, что мы хотим видеть в данном поле. Согласен, что это влияет на поведение самого поля.
                О чем, кстати, можно забыть, а значит это усложняет процесс программирования. Да-с, момент очень даже спорный. Поэтому стоит хорошо подумать, прежде чем все это применять на практике взамен жесткого разделения как сейчас.
                  0
                  оно не должно быть «взамен», оно должно быть «в дополнение»
                    0
                    Вот об этом тоже стоит крепко подумать — взамен или вместе? Да, стоит сразу уточнить, что проверку на стороне сервера я не отменял. А вот использовать на стороне клиента одновременно проверку регэкспом и яваскриптом — спорное решение. Изменяем правила проверки — и изменять нужно и регэксп, и яваскрипт. То есть дополнение внешнее может быть(что опять же нагружает функциями оформления яваскрипт), а вот саму операцию проверки на стороне клиента я бы сосредоточил в одном месте.
                    Надеюсь я правильно понял Ваш комментарий?
              0
              Спасибо, отличная работа! Хотелось бы про возможности валидации поля файл почитать.
                0
                Я думаю не хватает тэга alistapart
                  0
                  на alistapart есть ссылка ;)
                    +3
                    Дело не в инсточниках, дело в поиске же.
                  +1
                  ИМХО — это спорное направление развития. С одной стороны да, хорошо, меньше велосипедов изобретать придётся и меньше кодить клиентской части. Но опять же немного разное поведение разных браузеров, ну вроде как при валидации url убивает многие эти фичи. Лучше уж самому писать по одним правилам, чтобы работало всегда однозначно.

                  Да и вообще, при использовании этого всего серверную проверку никто не отменял. Она обязательна. Т.к. существуют инструменты редактирования html кода, а следовательно и правил, прямо в браузере. js может быть просто отключен (крайне редко конечно это сейчас, но мало ли… да и мобильный браузеры не всегда поддерживают это всё).

                  И потом, программист-новичок не видевший ничего кроме css3 и html5, создаст поле с проверкой в браузере телефона, к примеру. И будет уверен что ему придут только цифры, а не sql инъекция.
                    0
                    Самому писать по одним правилам не получится хотя бы потому, что бразеры по разному реализуют javascript. Эта статья скорее о будущем, нежели о настоящем. Ни html5, ни css3 пока не являются стандартами. Но как только они таковыми станут, их можно будет использовать и это будет работать в большинстве современных браузеров.

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

                      True! Всё изложенное в топике не стоит и гроша, если сервер не (пере)проверяет поступившие данные. :)
                      AJAX и Flash-формы в этом отношении тоже ощутимо усыпляют бдительность разработчиков.
                      +2
                      я думаю что при валидации URL нужно всетаки позволять вводить его без схемы, для большенства людей http, https, ftp и т.д. — просто загадочные буковки, на сервере уже можно проверять урл на наличие схемы, перед этим добавив http:// в фильтре, если схемы нет.
                        0
                        Наверное, в заголовке статьи нужно указать, что эта статья об использовании новых возможностей CSS для валидации форм. А то я уж подумал, тут про супердвижок на, скажем, PHP речь идет :)
                          0
                          Что-то в демке плейсхолдеры как-то убого реализованы и явно не через соответствующий атрибут в HTML5. По крайней мере в Хроме, котоый точно его поддерживает, если дать элементу фокус, увести его и снова вернуь фокус в него — текст плейсхолдера становится текстом в инпуте.
                            +1
                            Не стоит забывать про то, что на стороне сервера придется делать все тоже самое.
                            Иначе пользователь сохранит форму на диск, уберет все ваши чудо-проверки и вуаля!
                              0
                              Firefox -> Web Developer toolbar -> Disable Javascript -> «вуаля!», но суть правильная — на сервере делать обязательно.
                                0
                                описанная в статье валидация работает без участия js, но валидацию на сервере всё равно делать надо, да.
                                  0
                                  к сожалению, в реальной жизни такая валидация работать будет совсем-совсем не везде, поэтому без js пока никак
                              0
                              Последняя демка некорректа в FF — приняло за валидное мыло mail@mail а в поле телефон где 10 цифр, принимает и больше цифр… сыровата эмуляция…
                                0
                                такое оущение, что тот, кто придумал записывать паттерны валидации в html, никогда ничего сложнее hello world не писал.
                                ведь на стороне сервера тоже придется делать такой паттерн
                                  0
                                  раз уж всё-равно нужно реализовывать в ручную для старых браузеров, то почему бы не использовать её и для новых? какой профит тут от нативной поддержки перед единообразной?

                                  Only users with full accounts can post comments. Log in, please.