Полный гид по HTML-формам и валидации ограничений

В этой статье мы рассмотрим поля форм HTML и возможности валидации, предлагаемые HTML5. Также мы рассмотрим, как эти возможности можно улучшить с помощью CSS и JavaScript.

Что такое Контролируемая Валидация?

У каждого поля формы есть своё назначение. И это назначение часто регулируется ограничениями — или правилами, определяющими, что и что не должно вводиться в каждое поле формы. Например, поле email потребует валидный адрес электронной почты; поле password может требовать определенные типы символов и иметь минимальное количество требуемых символов; а текстовое поле может иметь ограничение на количество вводимых символов.

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

Клиентская сторона против Серверной стороны Валидации

Бóльшая часть JavaScript-кода, написанного в ранних годах языка, занималась клиентской стороной валидации форм. Даже сегодня разработчики тратят значительное время на написание функций для проверки значений полей. Необходимо ли это ещё в современных браузерах? Скорее всего, нет. В большинстве случаев, это действительно зависит от того, что вы пытаетесь сделать.

Но сначала, вот большое предупреждение:

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

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

Поля ввода HTML5

HTML предлагает:

  • <textarea> для многострочных текстовых полей
  • <select> для выпадающего списка опций
  • <button> для … кнопок

Но вы будете использовать <input> чаще всего:

<input type="text" name="username" />

Атрибут type устанавливает тип управления, и есть большой выбор вариантов:

type description
button a button with no default behavior
checkbox a check/tick box
color a color picker
date a date picker for the year, month, and day
datetime-local a date and time picker
email an email entry field
file a file picker
hidden a hidden field
image a button which displays the image defined by the src attribute
month a month and year picker
number a number entry field
password a password entry field with obscured text
radio a radio button
range a slider control
reset a button that resets all form inputs to their default values (but avoid using this, as it’s rarely useful)
search a search entry field
submit a form submission button
tel a telephone number entry field
text a text entry field
time a time picker with no time zone
url a URL entry field
week a week number and year picker

Браузер возвращается к text, если вы пропустите атрибут type или он не поддерживает вариант. Современные браузеры хорошо поддерживают все типы, но старые браузеры все равно покажут текстовое поле ввода.

Другие полезные атрибуты <input> включают:

attribute description
accept file upload type
alt alternative text for the image types
autocomplete hint for field auto-completion
autofocus focus field on page load
capture media capture input method
checked checkbox/radio is checked
disabled disable the control (it won’t be validated or have its value submitted)
form associate with a form using this ID
formaction URL for submission on submit and image buttons
inputmode data type hint
list ID of <datalist> autocomplete options
max maximum value
maxlength maximum string length
min minimum value
minlength minimum string length
name name of control, as submitted to server
pattern a regular expression pattern, such as [A-Z]+ for one or more uppercase characters
placeholder placeholder text when the field value is empty
readonly the field is not editable, but it will still be validated and submitted
required the field is required
size the size of the control (often overridden in CSS)
spellcheck set true or false spell-checking
src image URL
step incremental values in numbers and ranges
type field type (see above)
value the initial value

Поля вывода HTML

Помимо входных типов, HTML5 предоставляет только для чтения выходные данные:

  • output: текстовый результат вычисления или действия пользователя
  • progress: индикатор прогресса с атрибутами value и max
  • meter: шкала, которая может изменяться между зеленым, желтым и красным в зависимости от значений, установленных для атрибутов value, min, max, low, high и optimum.

Метки ввода

Поля должны иметь связанный <label>, который можно обернуть вокруг элемента:

<label>your name <input type="text" name="name" /><label>

Или связать поле с меткой с помощью атрибута for:

<label for="nameid">your name</label>
<input type="text" id="nameid" name="name" />

Метки важны для доступности. Возможно, вы сталкивались с формами, которые используют placeholder для экономии места на экране:

<input type="text" name="name" value="" placeholder="your name" />

Текст заполнителя исчезает, как только пользователь что-то вводит — даже один пробел. Лучше показывать метку, чем заставлять пользователя запоминать, что требуется от поля!

Поведение ввода

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

Большинство типов полей очевидны, но есть исключения. Например, кредитные карты являются числовыми, но увеличение/уменьшение счетчика бесполезно, и слишком легко нажимать вверх или вниз при вводе 16-значного числа. Лучше использовать стандартный тип text, но установить атрибут inputmode в numeric, что показывает соответствующую клавиатуру. Установка autocomplete="cc-number" также предлагает любые предварительно настроенные или ранее введенные номера карт.

Использование правильного поля type и autocorrect предлагает преимущества, которые было бы трудно достичь на JavaScript. Например, некоторые мобильные браузеры могут:

Автоматическая проверка

Браузер обеспечивает соответствие введенного значения ограничениям, определенным атрибутами type, min, max, step, minlength, maxlength, pattern и required. Например:

<input type="number" min="1" max="100" required />

Попытка отправки пустого значения предотвращает отправку формы и показывает следующее сообщение в Chrome:

Сплетники не разрешат значения вне диапазона от 1 до 100. Похожие сообщения о валидации появляются, если вы введете строку, которая не является числом. Все без единой строки JavaScript.

Вы можете отключить валидацию браузера следующим образом:

  • добавив атрибут novalidate к элементу <form>
  • добавив атрибут formnovalidate к кнопке или изображению отправки

Создание пользовательских JavaScript-входов

Если вы пишете новый компонент ввода даты на основе JavaScript, пожалуйста, остановитесь и отойдите от клавиатуры!

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

Есть три основные причины, по которым разработчики выбирают создание входов на основе JavaScript.

1. Стандартные элементы управления сложно стилизовать

Стилизация CSS ограничена и часто требует хаков, таких как наложение входа на псевдоэлементы ::before и ::after метки. Ситуация улучшается, но задайте вопрос любому дизайну, который ставит форму превыше функции.

2. Современные типы <input> не поддерживаются в старых браузерах

По сути, вы программируете под Internet Explorer. Пользователи IE не получат выбор даты, но могут вводить даты в формате ГГГГ-ММ-ДД. Если ваш клиент настаивает, то загрузите полифилл только в IE. Современным браузерам это не нужно.

3. Вам требуется новый тип ввода, который никогда не был реализован ранее

Такие ситуации редки, но всегда начинайте с подходящих полей HTML5. Они быстрые и работают даже до загрузки скрипта. Вы можете постепенно улучшать поля по мере необходимости. Например, немного JavaScript может обеспечить, чтобы конечная дата мероприятия календаря наступала после начальной даты.

В заключение: избегайте изобретения собственных HTML-элементов управления!

Стилизация валидации CSS

Вы можете применять следующие псевдо-классы к полям ввода для стилизации их в зависимости от текущего состояния:

selector description
:focus the field with focus
:focus-within an element contains a field with focus (yes, it’s a parent selector!)
:focus-visible an element has focus owing to keyboard navigation, so a focus ring or more evident styling is necessary
:required a field with a required attribute
:optional a field without a required attribute
:valid a field that has passed validation
:invalid a field that has not passed validation
:user-valid a field that has passed validation after the user has interacted with it (Firefox only)
:user-invalid a field that hasn’t passed validation after the user has interacted with it (Firefox only)
:in-range the value is within range on a number or range input
:out-of-range the value is out of range on a number or range input
:disabled a field with a disabled attribute
:enabled a field without a disabled attribute
:read-only a field with a read-only attribute
:read-write: a field without a read-only attribute
:checked a checked checkbox or radio button
:indeterminate an indeterminate checkbox or radio state, such as when all radio buttons are unchecked
:default the default submit button or image

Вы можете стилизовать текстовое содержимое placeholder с помощью псевдо-элемента ::placeholder:

/* синий плейсхолдер для полей электронной почты */
input[type="email"]::placeholder {
  color: blue;
}

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

input:invalid { color: red; }
input:enabled { color: black; }

Неверные входные данные имеют красный текст, но он применяется только к полям с атрибутом disabledтак что все активные поля имеют черный цвет.

Браузер применяет стили валидации при загрузке страницы. Например, в следующем коде каждое неверное поле получает красную границу:

:invalid {
  border-color: #900;
}

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

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

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

  • приостановить валидацию до тех пор, пока пользователь не взаимодействует с полем или не отправляет форму
  • показать сообщения об ошибках с настраиваемым стилем
  • предоставить настраиваемую валидацию, которая невозможна только с помощью HTML. Это часто необходимо, когда нужно сравнить два входа – например, когда вы вводите адрес электронной почты или телефонный номер, проверяете, что “новый” и “подтверждающий” пароли имеют одинаковое значение, или убеждаетесь, что одна дата наступает после другой.

Проверка формы

Перед использованием API ваш код должен отключить стандартную валидацию и сообщения об ошибках, установив свойство формы noValidate в true (что аналогично добавлению атрибута novalidate):

const myform = document.getElementById('myform');
myform.noValidate = true;

Затем вы можете добавить обработчики событий – например, когда форма отправляется:

myform.addEventListener('submit', validateForm);

Обработчик может проверить, действительна ли вся форма, используя методы checkValidity() или reportValidity(), которые возвращают true, если все входы формы действительны. (Разница в том, что checkValidity() проверяет, подвергаются ли какие-либо входы ограничению валидации.)

Документация Mozilla объясняет:

Событие invalid также срабатывает на каждом невалидном поле. Оно не всплывает: обработчики должны быть добавлены к каждому контролю, который его использует.

// проверять форму при отправке
function validateForm(e) {

  const form = e.target;

  if (form.checkValidity()) {

    // форма валидна - проводить дополнительные проверки

  }
  else {

    // форма невалидна - отменить отправку
    e.preventDefault();

  }

};

A valid form could now incur further validation checks. Similarly, an invalid form could have invalid fields highlighted.

Проверка полей

Отдельные поля имеют следующие свойства проверки ограничений:

  • willValidate: возвращает true если элемент является кандидатом для проверки ограничений.

  • validationMessage: сообщение о проверке. Это будет пустая строка, если поле валидно.

  • valitity: объект ValidityState. У него есть свойство valid, которое устанавливается в true, если поле является действительным. Если оно равно false, одно или несколько из следующих свойств будут равны true:

    ValidityState описание
    .badInput браузер не может понять ввод
    .customError было установлено сообщение о настройке действительности
    .patternMismatch значение не соответствует указанному атрибуту pattern
    .rangeOverflow значение больше, чем атрибут max
    .rangeUnderflow значение меньше, чем атрибут min
    .stepMismatch значение не соответствует правилам атрибута step
    .tooLong длина строки больше, чем атрибут maxlength
    .tooShort длина строки меньше, чем атрибут minlength
    .typeMismatch значение не является действительным email или URL
    .valueMissing требуемое значение пустое

Отдельные поля имеют следующие методы проверки валидации ограничений:

  • setCustomValidity(message): устанавливает сообщение об ошибке для недействительного поля. Пустая строка должна быть передана, когда поле действительно, иначе поле останется недействительным навсегда.
  • checkValidity(): возвращает true, если ввод действителен. Свойство valitity.valid делает то же самое, но checkValidity() также вызывает событие invalid на поле, что может быть полезно.

Обработчик функции validateForm() может перебирать каждое поле и применять класс invalid к его родительскому элементу при необходимости:

function validateForm(e) {
  const form = e.target;
  if (form.checkValidity()) {
    // форма действительна - проверяем дальше
  }
  else {
    // форма недействительна - отменяем отправку
    e.preventDefault();
    // применяем класс invalid
    Array.from(form.elements).forEach(i => {
      if (i.checkValidity()) {
        // поле действительно - удаляем класс
        i.parentElement.classList.remove('invalid');
      }
      else {
        // поле недействительно - добавляем класс
        i.parentElement.classList.add('invalid');
      }
    });
  }
};

Предположим, что ваш HTML определил поле электронной почты:

<div>
  <label for="email">email</label>
  <input type="email" id="email" name="email" required />
  <p class="help">Please enter a valid email address</p>
</div>

Скрипт применяет класс invalid к <div> когда email не указан или недействителен. CSS может показывать или скрывать сообщение о валидации при отправке формы:

.help { display: none; }
.invalid .help { display: block; }
.invalid label, .invalid input, .invalid .help {
  color: red;
  border-color: red;
}

Создание пользовательского валидатора формы

Следующий демонстрационный пример показывает пример контактной формы, которая требует имя пользователя и либо адрес электронной почты, либо номер телефона, либо оба:

Он реализован с использованием общего класса валидации формы под названием FormValidate. При создании объекта передается элемент формы. Возможен второй параметр:

  • true для валидации каждого поля при взаимодействии пользователя с ним
  • false (по умолчанию) для валидации всех полей после первой отправки (валидация на уровне поля происходит после этого)
// валидация контактной формы
const contactForm = new FormValidate(document.getElementById('contact'), false);

Метод .addCustom(field, func) определяет пользовательские функции валидации. Следующий код обеспечивает, что либо поле email, либо поле tel являются действительными (ни одно из них не имеет атрибута required):

// пользовательская валидация - email и/или телефон
const
  email = document.getElementById('email'),
  tel = document.getElementById('tel');

contactForm.addCustom(email, f => f.value || tel.value);
contactForm.addCustom(tel, f => f.value || email.value);

A FormValidate object monitors both of the following:

  • focusout события, которые затем проверяют отдельное поле
  • события submit формы, которые затем проверяют каждое поле

Оба вызывают метод .validateField(field), который проверяет, проходит ли поле стандартную валидацию ограничений. Когда это так, любые назначенные пользовательские функции валидации для этого поля выполняются последовательно. Все они должны возвращать true для того, чтобы поле считалось действительным.

Неверные поля имеют примененный класс invalid к родительскому элементу поля, который отображает сообщение справки красного цвета с помощью CSS.

Наконец, объект вызывает пользовательскую функцию submit при валидности всей формы:

// пользовательский submit
contactForm.submit = e => {
  e.preventDefault();
  alert('Form is valid!\n(open the console)');
  const fd = new FormData(e.target);
  for (const [name, value] of fd.entries()) {
    console.log(name + ': ' + value);
  }
}

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

Усовершенствование форм

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

Рекомендации:

  • Используйте стандартные типы HTML-входов, где это возможно. Установите атрибуты min, max, step, minlength, maxlength, pattern, required, inputmode, и autocomplete по мере необходимости.
  • При необходимости используйте немного JavaScript для активации пользовательской валидации и сообщений.
  • Для более сложных полей постепенно улучшайте стандартные входы.

Наконец: забудьте о Internet Explorer!

Если ваши клиенты в основном не используют Internet Explorer, нет необходимости реализовывать свои собственные функции проверки валидации. Все поля ввода HTML5 работают в IE, но могут потребовать больше усилий от пользователя. (Например, IE не обнаружит, когда вы вводите неверный адрес электронной почты.) Вы все равно должны проверять данные на сервере, поэтому рассмотрите возможность использования этого в качестве основы для проверки ошибок в IE.

Часто задаваемые вопросы (FAQ) о HTML-формах и ограничительной валидации

Почему важна валидация HTML-форм?

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

Как HTML5 улучшает валидацию форм?

HTML5 вводит несколько новых элементов и атрибутов форм, которые значительно упрощают и делают более эффективной валидацию форм. Например, он предоставляет новые типы ввода, такие как email, URL и number, которые автоматически валидируют введенные данные в зависимости от типа. HTML5 также вводит новые атрибуты, такие как required, pattern и min/max, которые позволяют указывать различные ограничения на вводимые данные. Более того, HTML5 предоставляет встроенный API валидации, который позволяет выполнять пользовательскую валидацию с помощью JavaScript.

Могу ли я выполнять валидацию форм без JavaScript?

Да, вы можете выполнять базовую валидацию формы с использованием только HTML5. HTML5 предоставляет несколько новых типов ввода и атрибутов, которые позволяют указывать различные ограничения на вводимые данные. Например, вы можете использовать атрибут required, чтобы сделать поле обязательным, атрибут pattern для обеспечения определенного формата и атрибуты min/max для установки диапазона для числовых входов. Однако для более сложной валидации вам все равно может потребоваться использовать JavaScript.

Как я могу настроить сообщения об ошибках валидации формы HTML5?

HTML5 предоставляет API валидации, который позволяет настроить сообщения об ошибках. Вы можете использовать метод setCustomValidity объекта ValidityState для установки пользовательского сообщения об ошибке для поля. Этот метод принимает строковый аргумент, который становится сообщением о валидации поля, когда поле недействительно. Вы можете вызывать этот метод в ответ на событие invalid, которое срабатывает, когда поле не проходит валидацию.

Как отключить валидацию формы HTML5?

Вы можете отключить валидацию формы HTML5, добавив атрибут novalidate к элементу формы. Когда этот атрибут присутствует, браузер не будет выполнять никакой валидации формы при ее отправке. Это может быть полезно, если вы хотите полностью обрабатывать валидацию на стороне сервера или с использованием пользовательского JavaScript.

Как в HTML5 проверить несколько полей вместе?

HTML5 не предоставляет встроенного способа проверки нескольких полей вместе. Однако это можно реализовать с помощью JavaScript. Вы можете написать пользовательскую функцию проверки, которая проверяет значения нескольких полей и устанавливает пользовательское сообщение о достоверности, если они не соответствуют требуемым критериям. Вы можете вызвать эту функцию в ответ на событие отправки формы или события ввода/изменения полей.

Как я могу проверить поле на основе значения другого поля в HTML5?

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

Как я могу выполнить асинхронную проверку в HTML5?

HTML5 не поддерживает асинхронную проверку из коробки. Однако это можно реализовать с помощью JavaScript. Вы можете написать пользовательскую функцию проверки, которая выполняет асинхронную операцию, такую как AJAX-запрос, и устанавливает пользовательское сообщение о достоверности на основе результата. Вы можете вызвать эту функцию в ответ на события ввода/изменения полей или на событие отправки формы.

Как я могу стилизовать сообщения об ошибках в HTML5 форм проверки?

Внешний вид сообщений об ошибках валидации HTML5 форм определяется браузером и не может быть напрямую стилизован с использованием CSS. Однако вы можете создавать пользовательские сообщения об ошибках с помощью JavaScript и стилизовать их по своему усмотрению. Вы можете использовать API валидации для определения, когда поле недействительно, и отображать соответствующее пользовательское сообщение об ошибке.

Как проверить валидацию HTML-формы?

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

Source:
https://www.sitepoint.com/html-forms-constraint-validation-complete-guide/