В этой статье мы рассмотрим поля HTML-формы и варианты проверки, предлагаемые HTML5. Мы также рассмотрим, как их можно улучшить с помощью CSS и JavaScript.
- Что такое проверка ограничений?
- Проверка на стороне клиента и на стороне сервера
- Поля ввода HTML5
- Поля вывода HTML
- Метки входа
- Входное поведение
- Автоматическая проверка
- Создание пользовательских входных данных JavaScript
- Стиль проверки CSS
- JavaScript и API проверки ограничений
- Проверка формы
- Проверка поля
- Создание настраиваемого валидатора форм
- Form Finesse
Что такое проверка ограничений?
У каждого поля формы есть цель. И эта цель часто регулируется контрсилами — или правила, регулирующие то, что следует и не следует вводить в каждое поле формы. Например, для emailполя потребуется действующий адрес электронной почты; passwordполе может потребовать определенных типов символов и иметь минимальное количество требуемых символов; а текстовое поле может иметь ограничение на количество вводимых символов.
Современные браузеры могут проверять соблюдение пользователями этих ограничений и предупреждать их о нарушении этих правил. Это известно как проверка ограничения.
Проверка на стороне клиента и на стороне сервера
Большая часть кода JavaScript, написанного в первые годы существования языка, обрабатывала проверку формы на стороне клиента. Даже сегодня разработчики тратят много времени на написание функций для проверки значений полей. Это все еще необходимо в современных браузерах? Наверное, нет. В большинстве случаев это действительно зависит от того, что вы пытаетесь сделать.
Но сначала вот большое предупреждающее сообщение:
Проверка на стороне клиента — это тонкость, которая может предотвратить распространенные ошибки ввода данных до того, как приложение тратит время и пропускную способность, отправляя данные на сервер. Это не замена проверки на стороне сервера!
Всегда дезинфицируйте данные на стороне сервера. Не каждый запрос будет поступать из браузера. Даже в этом случае нет гарантии, что браузер проверил данные. Любой, кто знает, как открыть инструменты разработчика браузера, также может обойти ваш с любовью созданный HTML и JavaScript.
Поля ввода HTML5
HTML предлагает:
- <textarea> для многострочных текстовых полей
- <select> для раскрывающегося списка опций
- <button> для… кнопок
Но <input>чаще всего вы будете использовать :
<input type="text" name="username" />
typeАтрибут задает тип управления, и есть большой выбор вариантов:
type | описание |
button | кнопка без поведения по умолчанию |
checkbox | флажок / галочка |
color | палитра цветов |
date | выбор даты для года, месяца и дня |
datetime-local | выбор даты и времени |
поле для ввода электронной почты | |
file | сборщик файлов |
hidden | скрытое поле |
image | кнопка, которая отображает изображение, определяемое srcатрибутом |
month | сборщик месяца и года |
number | поле ввода номера |
password | поле ввода пароля с затемненным текстом |
radio | радио-кнопка |
range | ползунок |
reset | кнопка, которая сбрасывает все входные данные формы до значений по умолчанию (но не используйте ее, так как она редко бывает полезной) |
search | поле ввода поиска |
submit | кнопка отправки формы |
tel | поле для ввода номера телефона |
text | поле ввода текста |
time | выбор времени без часового пояса |
url | поле ввода URL |
week | номер недели и сборщик года |
Браузер возвращается к работе, textесли вы опускаете typeатрибут или не поддерживает параметр. Современные браузеры хорошо поддерживают все типы, но старые браузеры по-прежнему отображают поле ввода текста.
Другие полезные <input>атрибуты включают:
атрибут | описание |
accept | тип загрузки файла |
alt | альтернативный текст для типов изображений |
autocomplete | подсказка для автозаполнения полей |
autofocus | поле фокуса при загрузке страницы |
capture | метод ввода захвата мультимедиа |
checked | флажок / радио отмечен |
disabled | отключить элемент управления (он не будет проверен и его значение не будет отправлено) |
form | связать с формой, используя этот идентификатор |
formaction | URL для отправки на кнопки отправки и изображения |
inputmode | подсказка по типу данных |
list | ID <datalist>вариантов автозаполнения |
max | максимальное значение |
maxlength | максимальная длина строки |
min | минимальное значение |
minlength | минимальная длина строки |
name | имя элемента управления, отправленное на сервер |
pattern | шаблон регулярного выражения, например, [A-Z]+для одного или нескольких символов верхнего регистра |
placeholder | текст-заполнитель, когда значение поля пустое |
readonly | поле недоступно для редактирования, но оно все равно будет проверено и отправлено |
required | поле обязательно для заполнения |
size | размер элемента управления (часто переопределяется в CSS) |
spellcheck | набор trueили falseпроверка орфографии |
src | URL изображения |
step | инкрементные значения в числах и диапазонах |
type | тип поля (см. выше) |
value | начальное значение |
Поля вывода HTML
Помимо типов ввода, HTML5 предоставляет выходные данные только для чтения:
- output: текстовый результат вычисления или действия пользователя
- progress: Прогресс бар с valueи maxатрибуты
- meter: Шкала, которая может меняться между зеленым, желтым и красным цветом в зависимости от значений, установленных для value, min, max, low, high, и optimumатрибутов.
Метки входа
Поля должны иметь связанный <label>элемент, который можно обернуть вокруг элемента:
<label>your name <input type="text" name="name" /><label>
Или свяжите поле idс меткой с помощью 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. Например, некоторые мобильные браузеры могут:
- импортировать данные кредитной карты путем сканирования карты с помощью камеры
- импортировать одноразовые коды, отправленные по SMS
Автоматическая проверка
Браузер обеспечивает входное значение прилипает с ограничениями, определяемыми 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.
- Стандартные элементы управления сложно стилизовать
Стили CSS ограничены и часто требуют хаков, таких как наложение ввода с его метками ::beforeи ::afterпсевдоэлементами. Ситуация улучшается, но ставьте под сомнение любой дизайн, в котором форма важнее функции.
- Современные <input>типы не поддерживаются в старых браузерах.
По сути, вы пишете код для Internet Explorer. Пользователи IE не получат средства выбора даты, но все равно смогут вводить даты в YYYY-MM-DDформате. Если ваш клиент настаивает, загрузите полифилл только в IE. Нет необходимости перегружать современные браузеры.
- Вам нужен новый тип ввода, который никогда раньше не реализовывался.
Такие ситуации редки, но всегда начинаются с соответствующих полей HTML5. Они быстрые и работают даже до загрузки сценария. При необходимости вы можете постепенно улучшать поля. Например, добавление JavaScript может гарантировать, что дата окончания календарного события наступает позже даты начала.
Подводя итог: избегайте повторного изобретения элементов управления HTML!
Стиль проверки CSS
Вы можете применить следующие псевдоклассы к полям ввода, чтобы стилизовать их в соответствии с текущим состоянием:
селектор | описание |
:focus | поле с фокусом |
:focus-within | элемент содержит поле с фокусом (да, это родительский селектор!) |
:focus-visible | элемент имеет фокус из-за навигации с клавиатуры, поэтому необходимо кольцо фокусировки или более очевидный стиль |
:required | поле с requiredатрибутом |
:optional | поле без requiredатрибута |
:valid | поле, прошедшее проверку |
:invalid | поле, которое не прошло проверку |
:user-valid | поле, прошедшее проверку после взаимодействия с ним пользователя (только Firefox) |
:user-invalid | поле, которое не прошло проверку после того, как пользователь взаимодействовал с ним (только Firefox) |
:in-range | значение находится в пределах диапазона на входе numberилиrange |
:out-of-range | значение вне допустимого диапазона на входе numberилиrange |
:disabled | поле с disabledатрибутом |
:enabled | поле без disabledатрибута |
:read-only | поле с read-onlyатрибутом |
:read-write: | поле без read-onlyатрибута |
:checked | установленный флажок или переключатель |
:indeterminate | неопределенный флажок или радио-состояние, например, когда все переключатели не отмечены |
:default | кнопка отправки по умолчанию или изображение |
Вы можете стилизовать placeholderтекст ввода с помощью ::placeholderпсевдоэлемента:
/* blue placeholder on email fields */ input[type="email"]::placeholder { color: blue; }
Указанные выше селекторы имеют одинаковую специфику, поэтому порядок может иметь значение. Рассмотрим этот пример:
input:invalid { color: red; } input:enabled { color: black; }
Недопустимые входы имеют красный текст, но он применяется только к входам с disabledатрибутом, поэтому все включенные входы черные.
Браузер применяет стили проверки при загрузке страницы. Например, в следующем коде каждое недопустимое поле выделено красной рамкой:
:invalid { border-color: #900; }
Пользователь сталкивается с устрашающим набором красных прямоугольников, прежде чем начать взаимодействие с формой. Отображение ошибок проверки после первой отправки или при изменении значения улучшит впечатление. Вот где на помощь приходит JavaScript…
JavaScript и API проверки ограничений
Constraint Validation 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Событие также срабатывают на каждом недействительном поле. Это не пузырится: обработчики должны быть добавлены к каждому элементу управления, который его использует.
// validate form on submission function validateForm(e) { const form = e.target; if (form.checkValidity()) { // form is valid - make further checks } else { // form is invalid - cancel submit e.preventDefault(); } };
Действительная форма теперь может подвергаться дальнейшим проверкам. Точно так же недопустимая форма может иметь выделенные недопустимые поля.
Проверка поля
Отдельные поля имеют следующие свойства проверки ограничений:
- 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 | значение не является действительным адресом электронной почты или URL |
.valueMissing | requiredзначение пусто |
Для отдельных полей используются следующие методы проверки ограничений:
- setCustomValidity(message): устанавливает сообщение об ошибке для недопустимого поля. Если поле действительно, необходимо передать пустую строку, иначе поле останется недействительным навсегда.
- checkValidity(): возвращается, trueкогда ввод действителен. valitity.validСвойство делает то же самое, но checkValidity()также вызывает invalidсобытие на поле, которое может быть полезным.
Функция- validateForm()обработчик может перебирать каждое поле и при необходимости применять invalidкласс к его родительскому элементу:
function validateForm(e) { const form = e.target; if (form.checkValidity()) { // form is valid - make further checks } else { // form is invalid - cancel submit e.preventDefault(); // apply invalid class Array.from(form.elements).forEach(i => { if (i.checkValidity()) { // field is valid - remove class i.parentElement.classList.remove('invalid'); } else { // field is invalid - add class 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>когда электронная почта не указана или недействительна. CSS может отображать или скрывать сообщение проверки при отправке формы:
.help { display: none; } .invalid .help { display: block; } .invalid label, .invalid input, .invalid .help { color: red; border-color: red; }
Создание настраиваемого валидатора форм
Следующая демонстрация показывает пример контактной формы, для которой требуется имя пользователя и либо адрес электронной почты, либо номер телефона, либо и то, и другое:
Он реализован с использованием универсального класса проверки формы с именем FormValidate. При создании экземпляра объекта передается элемент формы. Может быть установлен необязательный второй параметр:
- true для проверки каждого поля при взаимодействии с ним пользователя
- false (по умолчанию) для проверки всех полей после первой отправки (после этого выполняется проверка на уровне поля)
// validate contact form const contactForm = new FormValidate(document.getElementById('contact'), false);
.addCustom(field, func)Метод определяет пользовательские функции проверки. Следующий код гарантирует, что поля emailили telдопустимы (ни у одного из них нет requiredатрибутов):
// custom validation - email and/or telephone 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);
А FormValidateобъект отслеживает оба из следующих действий :
- focusout события, которые затем проверяют отдельное поле
- submitсобытия формы, которые затем проверяют каждое поле
Оба вызывают.validateField(field)метод, который проверяет, проходит ли поле стандартную проверку ограничений. Когда это происходит, все пользовательские функции проверки, назначенные этому полю, выполняются по очереди. Все должны вернуться, trueчтобы поле было действительным.
Недопустимые поля имеют invalidкласс, примененный к родительскому элементу поля, который отображает красное справочное сообщение с помощью CSS.
Наконец, объект вызывает пользовательскую submitфункцию, когда действительна вся форма:
// custom 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предотвращает запуск дальнейших обработчиков, когда форма недействительна.
Form Finesse
Формы являются основой всех веб-приложений, и разработчики тратят много времени на манипулирование пользовательским вводом. Хорошо поддерживается проверка ограничений: браузеры могут обрабатывать большинство проверок и отображать соответствующие параметры ввода.
Рекомендации:
- По возможности используйте стандартные типы ввода HTML. Набор min, max, step, minlength, maxlength, pattern, required, inputmode, и autocompleteатрибуты по мере необходимости.
- При необходимости используйте немного JavaScript, чтобы включить настраиваемую проверку и сообщения.
- Для более сложных полей постепенно улучшайте стандартные входные данные.
Наконец: забудьте про Internet Explorer!
Если ваши клиенты не являются преимущественно пользователями IE, нет необходимости реализовывать собственные резервные функции проверки. Все поля ввода HTML5 работают в IE, но могут потребовать дополнительных усилий от пользователя. (Например, IE не обнаруживает, когда вы вводите неверный адрес электронной почты.) Вам все равно нужно проверять данные на сервере, поэтому рассмотрите возможность использования этого в качестве основы для проверки ошибок IE.