Формы и валидация
Формы - это мост между пользователем и сервером. Пользователь вводит данные, браузер отправляет их на сервер, сервер обрабатывает (на стороне PHP - см. уроки про формы).
Базовая форма
<form method="post" action="/signup">
<label for="email">Почта</label>
<input id="email" name="email" type="email" required />
<label for="pass">Пароль</label>
<input id="pass" name="password" type="password" minlength="8" required />
<button type="submit">Регистрация</button>
</form>
method - HTTP-метод (get или post). action - URL, куда отправить данные. name - ключ, под которым данные придут на сервер.
GET vs POST
GET - данные в URL:
/search?query=flexbox&lang=ru
Используй для поиска, фильтров, пагинации. Данные видны в адресной строке, сохраняются в истории, можно поделиться ссылкой.
POST - данные в теле запроса:
POST /signup HTTP/1.1
Content-Type: application/x-www-form-urlencoded
email=ivan%40mail.ru&password=12345678
Используй для паролей, персональных данных, создания записей. Данные не видны в URL, не сохраняются в истории.
Типы полей ввода
<!-- Текст -->
<input type="text" /> <!-- обычный текст -->
<input type="email" /> <!-- email (браузер проверит @) -->
<input type="password" /> <!-- пароль (скрыт точками) -->
<input type="url" /> <!-- URL -->
<input type="tel" /> <!-- телефон (мобильная клавиатура с цифрами) -->
<input type="number" /> <!-- число (стрелки + / -) -->
<input type="search" /> <!-- поиск (крестик для очистки) -->
<!-- Дата/время -->
<input type="date" /> <!-- календарь -->
<input type="time" /> <!-- часы -->
<input type="datetime-local" /> <!-- дата + время -->
<!-- Выбор -->
<input type="checkbox" /> <!-- галочка -->
<input type="radio" /> <!-- один из группы -->
<input type="range" min="0" max="100" /> <!-- слайдер -->
<input type="color" /> <!-- выбор цвета -->
<input type="file" /> <!-- загрузка файла -->
<!-- Скрытое -->
<input type="hidden" name="csrf" value="abc123" />
type определяет не только вид поля, но и клавиатуру на мобилке: type="email" покажет клавиатуру с @, type="tel" - цифровую.
Элементы формы
textarea - многострочный текст
<textarea name="message" rows="5" placeholder="Ваше сообщение..."></textarea>
select - выпадающий список
<select name="role">
<option value="">Выберите роль</option>
<option value="backend">Backend</option>
<option value="frontend">Frontend</option>
<option value="fullstack">Fullstack</option>
</select>
fieldset + legend - группировка
<fieldset>
<legend>Контактная информация</legend>
<label>Имя <input name="name" required /></label>
<label>Email <input name="email" type="email" required /></label>
</fieldset>
HTML-валидация
Браузер может проверять данные до отправки:
<!-- Обязательное поле -->
<input required />
<!-- Минимальная/максимальная длина -->
<input minlength="8" maxlength="100" />
<!-- Числовой диапазон -->
<input type="number" min="1" max="120" />
<!-- Регулярное выражение -->
<input pattern="[0-9]{10}" title="Введите 10 цифр" />
<!-- Email - встроенная проверка -->
<input type="email" />
Браузер покажет всплывающую подсказку, если данные не проходят валидацию.
Стилизация валидации
CSS-псевдоклассы для стилей валидации:
/* Валидное поле */
input:valid {
border-color: #38a169;
}
/* Невалидное поле (после попытки отправки) */
input:invalid {
border-color: #e53e3e;
}
/* Невалидное и пользователь уже взаимодействовал */
input:invalid:not(:placeholder-shown) {
border-color: #e53e3e;
background: #fff5f5;
}
/* Поле в фокусе */
input:focus {
outline: 2px solid #3182ce;
outline-offset: 2px;
}
:placeholder-shown - хитрость, чтобы не показывать красную рамку сразу при загрузке (пока пользователь не начал заполнять).
Отправка формы через JavaScript
<form id="contactForm">
<input name="email" type="email" required />
<textarea name="message" required></textarea>
<button type="submit">Отправить</button>
</form>
const form = document.getElementById('contactForm');
form.addEventListener('submit', async (e) => {
e.preventDefault(); // не перезагружать страницу
const data = new FormData(form);
const response = await fetch('/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(Object.fromEntries(data))
});
if (response.ok) {
form.reset();
alert('Сообщение отправлено!');
} else {
alert('Ошибка отправки');
}
});
FormData собирает все поля формы автоматически. Object.fromEntries() превращает FormData в обычный объект для JSON.
Загрузка файлов
<form enctype="multipart/form-data" method="post" action="/upload">
<input type="file" name="avatar" accept="image/*" />
<button type="submit">Загрузить</button>
</form>
enctype="multipart/form-data" - обязательно для файлов. Без него файл не отправится. accept ограничивает типы файлов в диалоге выбора (но сервер всё равно должен проверять).
Доступность форм
<!-- Всегда связывай label с input -->
<label for="name">Имя</label>
<input id="name" name="name" />
<!-- Или оборачивай input в label -->
<label>
Email
<input name="email" type="email" />
</label>
<!-- aria-describedby для подсказок -->
<input id="pass" aria-describedby="pass-hint" />
<small id="pass-hint">Минимум 8 символов, одна цифра</small>
<!-- Кнопка submit, не div с onclick -->
<button type="submit">Отправить</button> <!-- доступна с клавиатуры -->
<div onclick="submit()">Отправить</div> <!-- не доступна -->
Мини-задание
- Сделай форму «обратная связь» с полями: имя, email, сообщение (textarea), тема (select)
- Добавь
required,minlength,type="email" - Добавь стилизацию валидации через
:valid/:invalid - Перехвати submit через JavaScript и отправь данные через
fetch() - Посмотри в DevTools → Network как выглядит отправленный запрос