Валидация HTML5-форм

Несколько месяцев назад, Sandeep представил на всеобщее обозрение HTML Constraint API, показав, как можно использовать новые HTML5-элементы ввода и их атрибуты для валидации форм с минимальным использованием JavaScript.

В этой статье, я собираюсь разобрать валидацию на примере простой формы заказа, используя Constraint API, сделав акцент на том, чтобы не снизить удобства использования.

На всякий случай напомню, если вы не читали статью Sandeep о нововведениях в HTML5 относительно новых типов элементов ввода и атрибутов тега <input>, которые позволяют браузерам самостоятельно производить валидацию на клиентской стороне без необходимости использования JavaScript. Чтобы начать использование новых возможностей, вам нужно просто добавить новые атрибуты и типы элементов ввода к тегу <input>.

Строго говоря, вам следует использовать HTML5 DOCTYPE, иначе HTML-валидатор выдаст ошибки на странице. Но хорошая новость состоит в том, что новые функции имеют обратную совместимость. Если, к примеру, какой-нибудь старый браузер их не поддерживает, то это не «сломает» всю HTML-страницу – неподдерживаемые элементы будут отображены как <input type=”text”>.

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

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

<form action="" method="post">
     <fieldset>
         <legend>Booking Details</legend>
         <div>
             <label for="name">Name (required):</label>
             <input type="text" id="name" name="name" value="" aria-describedby="name-format">
             <span id="name-format" class="help">Format: firstname lastname</span>
         </div>
         <div>
             <label for="email">Email (required):</label>
             <input type="text" id="email" name="email" value="">
         </div>
         <div>
             <label>Website:</label>
             <input type="text" id="website" name="website" value="">
         </div>
         <div>
             <label for="numTickets"><abbr title="Number">No.</abbr> of Tickets (required):</label>
             <input type="text" id="numTickets" name="numTickets" value="">
         </div>
         <div class="submit">
             <input type="submit" value="Submit">
         </div>
     </fieldset>
 </form>

В данном примере каждый тег <input> ассоциирован с тегом <label>. Атрибут for тега <label> сравнивается со значением атрибута id соответствующего тега <input>. Это позволяет однозначно присвоить значения меток (тегов <label>) нужным элементам ввода. Также, это означает, что если вы кликните на метке, то соответствующий элемент ввода получит фокус.

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

Я также использовал WAI ARIA атрибут aria-describedby, который помогает пользователям с ограниченными возможностями ввести свое имя в правильном формате.

<label for="name">Name (required):</label> 
<input type="text" id="name" name="name" value="" aria-describedby="name-format">
  <span id="name-format" class="help">Format: firstname lastname</span>

Это отображается, когда поле ввода получает фокус, предоставляя контекстно-зависимую справку:

.help {     display:none;     font-size:90%; } input:focus + .help {     display:inline-block; }

Чтобы провести валидацию этой формы, нам необходимо:

  • Проверить заполнены ли обязательные поля;
  • Убедиться, что значение поля с именем является именно именем;
  • Проверить формат введенного email-адреса;
  • Проверить, чтобы введенный URL-адрес соответствовал формату;
  • Убедиться, что было указано количество билетов.

Обязательные поля

Валидация обязательных полей на предмет их правильного заполнения, не сложнее добавления для поля ввода атрибута required. В нашем случае, это поля Name, Email и Number of Tickets. Например, поле Name с изменениями будет выглядеть так:

<div>
         <label for="name">Name:</label>
         <input id="name" name="name" value="" aria-describedby="name-format" required>
         <span id="name-format" class="help">Format: firstname lastname</span>
</div>

Если мы попытаемся отправить данную форму, не заполнив всех обязательных полей, браузер оповестит о необходимости это сделать:

Обязательные поля

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

Предупреждение: не все браузеры имеют поддержку атрибута required, поэтому в некоторых комбинациях «браузер/программа чтения с экрана» могут возникать ошибки. Поэтому, на данный момент лучшей практикой будет указание атрибута aria-required=”true”:

<input id="name" name="name" value="" aria-describedby="name-format" required aria-required=”true”/>

Валидация данных

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

Нам нужно, чтобы содержимое поля 'Name' имело формат 'Firstname Lastname' и включало в себя только буквы и пробелы (в реальных сценариях, возможно, нужно будет принять во внимание и другие символы).

Этого можно достичь, добавив атрибут pattern к полю 'Name', установив его значение в виде регулярного выражения, которое описывает правило, которому должны соответствовать вводимые данные:

<input id="name" name="name" value="" aria-describedby="name-format" required aria-required=”true” pattern="[A-Za-z-0-9]+s[A-Za-z-'0-9]+">

При использовании атрибута pattern, символы ^ и $ зарезервированы для начала и конца регулярного выражения и не должны в него включаться.

Вы можете помочь пользователю, использовав атрибут title, который подсказывает требуемый формат ввода:

<input id="name" name="name" value="" aria-describedby="name-format" required aria-required=”true” pattern="[A-Za-z-0-9]+s[A-Za-z-'0-9]+"  title="firstname lastname">

Текст в атрибуте title затем присоединяется к встроенному валидационному сообщению:

Валидация данных

Стоит заметить, что некоторые сочетания «программа чтения с экрана/браузер» могут привести к ситуации, когда значение атрибута title будет прочитано несколько раз, в дополнение к тексту атрибута aria-describedby, поэтому обратите на это внимание.

К примеру, я обнаружил, что использование программы NVDA с IE10 ведет к двойному прочтению: как атрибута title, так и aria-describedby. Однако NVDA с Chrome и Firefox ведет себя совершенно нормально – читается только текст атрибута aria-describedby.

Далее, мы рассмотрим этот вопрос и покажем решение с использованием CSS3.

Валидация email, URL и номеров

Чтобы убедиться, что пользователь ввел верные данные в поля email, website и number of tickets, мы можем использовать новые элементы ввода, появившиеся в HTML5:

<input **type="email"** id="email" name="email" required> … <input **type="url"** id="url" name="url"> … <input **type="number"** id="numTickets" name="numTickets" required>

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

Валидация email, URL и номеров
Валидация email, URL и номеров - 2

Также заметим, что атрибут type больше не является обязательным. Если вы явно не укажете тип элемента ввода, то по умолчанию он будет равен type="text".

Предположим, что мы хотим ограничить число билетов, которое может купить один человек. Это можно реализовать, используя атрибуты max и min:

<input type="number" min="1" max="4" id="numTickets" name="numTickets">

Если пользователь введет число меньшее 1 или большее 4, то выведется сообщение о том, что диапазон ввода ограничен.

Использование CSS для подсветки обязательных полей и неверно введенных данных

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

Селекторы обязательных полей могут использовать псевдокласс :required:

input:required {     background:hsl(180, 50%, 90%);     border:1px solid #999; }

А дополнительные – псевдокласс :optional:

input:optional {     background:hsl(300, 50%, 90%);     border:1px dotted hsl(180, 50%, 90%); }

Успешное или неудачное прохождение процедуры валидации может показываться пользователю с помощью псевдоклассов :valid, :invalid, :in-range и :out-of-range:

input:valid, input:in-range {     background:hsl(120, 50%, 90%);     border-color:hsl(120, 50%, 50%); }  input:invalid, input:out-of-range {     border-color:hsl(0, 50%, 50%);     background:hsl(0, 50%, 90%); }
Использование CSS для подсветки обязательных полей и неверно введенных данных

Ранее, я заметил, что определенные сочетания «программа чтения с экрана/браузер» ведут к двойному прочтению атрибутов title и aria-describedby.

Что ж, одним из способов обойти это препятствие является удаление атрибута title из тега элемента ввода и использование CSS3-псеводкласса :invalid, чтобы показать текст атрибута aria-describedby:

input:focus + .help, input:invalid + .help {     display:inline-block; }

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

После всех манипуляций HTML-код должен выглядеть так:

<form action="" method="post">
     <fieldset>
         <legend>Booking Details</legend>
         <div>
             <label for="name">Name:</label>
             <input id="name" name="name" value="" required  pattern="[A-Za-z-0-9]+s[A-Za-z-'0-9]+" aria-required="true" aria-describedby="name-format">
             <span id="name-format" class="help">Format: firstname lastname</span>
         </div>
         <div>
             <label for="email">Email:</label>
             <input type="email" id="email" name="email" value="" required aria-required="true">
         </div>
         <div>
             <label for="website">Website:</label>
             <input type="url" id="website" name="website" value="">
         </div>
         <div>
             <label for="numTickets"><abbr title="Number">No.</abbr> of Tickets:</label>
             <input type="number" id="numTickets" name="numTickets" value="" required aria-required="true" min="1" max="4">
         </div>
         <div class="submit">
             <input type="submit" value="Submit">
         </div>
     </fieldset>
 </form>

Отключение встроенной в браузер валидации

Вы можете отключить встроенную в браузер валидацию, добавив атрибут novalidate к тегу <form>:

<form novalidate>     … </form>

Кроссбраузерность

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

Плохая же новость заключается в частичной поддержке в настольной версии Safari и её отсутствии во всех браузерах iOS Safari и в стандартных браузерах для Android. Если вам нужна поддержка старых версий IE (ниже версии 10), то там вы ее также не обнаружите.

Что же можно сделать, если требуется поддержка браузеров, которые не имеют встроенных средств валидации?

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

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

Третий подход подразумевает использование JavaScript для обнаружения поддержки валидации форм в браузере, и, если таковая имеется, то использовать её; в противном же случае обратиться к JavaScript-валидации.

Библиотеки наподобие Modernizr могут помочь обнаружить поддержку HTML5, но вы всегда можете написать собственный код, если не хотите подключать стороннюю JavaScript-библиотеку:

// Без Moderizr
 var inputElem = document.createElement('input');
 if (!('required' in inputElem)) {
     // JavaScript-валидация формы
   }
  ...  
// С Modernizr
 if (!Modernizr.input.required) {
     // JavaScript-валидация формы
 }

Заключение

В этой статье мы обзорно изучили использование HTML5-валидации форм на стороне клиента, приведя пример её применения в форме заказа, и при этом мы не пользовались средствами JavaScript.

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

Также, было рассмотрено использование новых CSS3-псеводклассов для отображения визуальных подсказок о том, какие поля обязательны к заполнению, а какие нет, какие поля заполнены правильно, а какие - нет.

Наконец мы поговорили об отключении HTML-валидации форм и обнаружении поддержки этой возможности в различных браузерах.

Сергей Бензенкоавтор-переводчик статьи «HTML5 Form Validation»