Как сверстать форму регистрации
Эта статья основана на одном из практических заданий verstaem.online.
Вы можете читать материал как обычное руководство или сначала попробовать выполнить задание самостоятельно, а затем сравнить свое решение с подробным разбором.
Перейти к заданиюВ этом уроке мы создадим страницу регистрации пользователя. На практике разберем семантическую форму, научимся выстраивать поля в несколько колонок, оформим чекбокс с согласием на обработку данных и адаптируем интерфейс для мобильных устройств.
Создаем HTML-разметку
Сначала создадим базовую HTML-разметку с помощью Emmet. Для этого достаточно ввести ! и нажать Tab. Обратите внимание на атрибут lang. Поскольку основной контент страницы написан на русском языке, здесь используем значение ru.
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Форма регистрации</title>
</head>
<body>
</body>
</html>
Итак, делаем форму. Добавляем собственно тег <form>, и не забываем добавить два атрибута — action и method. В первый мы вставим ссылку из задания https://postman-echo.com/post, а во второй вставим POST. Так мы сможем проверить, все ли правильно улетает из нашей формы.
Далее добавим заголовок и описание. А вот ниже пойдут поля формы. У полей есть подписи сверху, поэтому правильно будет эти подписи связать с инпутом. Можно сделать эту подпись тегом <label>, и связать с полем через атрибут for, но как по мне, просто обернуть и текст, и поле в <label> гораздо проще. Так и поступим. И обязательно укажем все важные атрибуты для поля ввода. Правильный type, заполненный name, placeholder и required.
<label class="content__label">
<span class="content__caption">Имя</span>
<input
type="text"
name="first_name"
placeholder="Иван"
class="content__input"
required
/>
</label>
<label class="content__label">
<span class="content__caption">Фамилия</span>
<input
type="text"
name="last_name"
placeholder="Соколов"
class="content__input"
required
/>
</label>
<label class="content__label content__label--full">
<span class="content__caption">E-mail</span>
<input
type="email"
name="email"
placeholder="ivan@example.com"
class="content__input"
required
/>
</label>
<label class="content__label">
<span class="content__caption">Пароль</span>
<input
type="password"
name="password"
placeholder="*******"
class="content__input"
required
/>
</label>
<label class="content__label">
<span class="content__caption">Повторите пароль</span>
<input
type="password"
name="password_confirm"
placeholder="*******"
class="content__input"
required
/>
</label>
Здесь важный момент — это дополнительный класс для лейбла с email --full, чтобы это поле встало на всю ширину. А атрибут name нужен, если мы хотим, чтобы из нашей формы вообще что-то отправилось. Без него поле вообще не войдет в «отправляемые». required мы добавили, чтобы поля были обязательными, ведь вход не может быть произведен, если не введена почта и пароль.
Далее у нас чекбокс. Чекбокс делаем также в лейбле, и сразу называем его .custom-checkbox, т. к. чекбоксы не могут стилизоваться обычным методом. Нам придется хитрить, но про это в разделе CSS.
<div class="content__addition">
<label class="custom-checkbox">
<input type="checkbox" name="accept_terms" class="custom-checkbox__input" required />
<span class="custom-checkbox__text">Я принимаю условия использования сервиса и политику обработки персональных данных.</span>
</label>
</div>
Ну и остается кнопка.
<button class="content__btn" type="submit">Создать аккаунт</button>
Всем полям в форме я добавил required, чтобы форма отправлялась только тогда, когда заполнены все.
Добавляем стили
Подключим файл стилей через <link> и зададим несколько базовых правил. Для этого задания достаточно переопределить box-sizing, сбросить отступ у <body> и подключить шрифт Segoe UI, который используется в макете.
* {
box-sizing: border-box;
}
@font-face {
font-family: "Segoe UI";
src: url("../fonts/SegoeUI.woff2");
font-display: swap;
font-weight: 400;
}
@font-face {
font-family: "Segoe UI";
src: url("../fonts/SegoeUIBold.woff2");
font-display: swap;
font-weight: 700;
}
body {
margin: 0;
padding: 20px;
background: #f4f1ea;
font-family: "Segoe UI", sans-serif;
}
Сначала делаем стили самой форме, а также заголовку и описани.
.form {
margin: 0 auto;
max-width: 620px;
border-radius: 32px;
padding: 40px;
background: #fffdf9;
}
.content__title {
margin: 0;
margin-bottom: 16px;
font-weight: 700;
font-size: 40px;
line-height: 120%;
color: #232323;
}
.content__descr {
margin: 0;
margin-bottom: 40px;
max-width: 448px;
font-weight: 400;
font-size: 16px;
line-height: 120%;
color: rgba(111, 106, 100, 0.92);
}
Далее расставляем элементы внутри формы. Используем flexbox вместе с flex-wrap: wrap. А вот лейблам, помимо flexbox для отступа между текстом и инпутом, зададим еще и ширину. Но не обычную, а через calc. Мы точно рассчитываем 50% — 8px. 8 потому что общий отступ 16. И здесь же сразу указываем 100% ширины у класса --full.
.content__items {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.content__label {
display: flex;
flex-direction: column;
width: calc(50% - 8px);
gap: 8px;
}
.content__label--full {
width: 100%;
}
У инпутов нам нужны будут отступы и слева, и справа, чтобы контент не лип к краям, также нужна будет высота из макета. И конечно, не забудем указать font-family: inherit, иначе шрифт не применится. Также мы добавим псевдокласс ::placeholder, который позволит нам стилизовать цвет текста, который мы видим еще до ввода своего.
.content__caption {
font-weight: 400;
font-size: 12px;
line-height: 120%;
color: #4a4641;
}
.content__input {
border: 1px solid #e7e1d8;
border-radius: 16px;
padding: 0px 16px;
height: 54px;
font-family: inherit;
font-weight: 400;
font-size: 16px;
line-height: 120%;
color: #232323;
background: #faf8f4;
}
.content__input::placeholder {
color: #232323;
}
Далее блок с чекбоксом. Ему дадим flex и расставим элементы по краям. А вот сам чекбокс — это интересно. По сути, управлять всем будет <input>, но мы скроем его, заменив на свое представление.
.content__addition {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 16px;
margin-bottom: 16px;
gap: 20px;
}
.custom-checkbox {
position: relative;
max-width: 460px;
cursor: pointer;
}
.custom-checkbox__input {
position: absolute;
opacity: 0;
appearance: none;
}
.custom-checkbox__text {
position: relative;
display: inline-flex;
font-weight: 400;
font-size: 16px;
line-height: 120%;
color: #4a4641;
gap: 8px;
}
.custom-checkbox__text::before {
content: "";
display: block;
border: 1px solid #4a4641;
border-radius: 4px;
flex-shrink: 0;
width: 16px;
height: 16px;
}
.custom-checkbox__text::after {
content: "";
position: absolute;
left: 5px;
top: 5px;
border-radius: 2px;
width: 8px;
height: 8px;
background: #4a4641;
opacity: 0;
transition: opacity 0.3s;
}
.custom-checkbox__input:checked + .custom-checkbox__text::after {
opacity: 1;
}
.custom-checkbox__input:focus + .custom-checkbox__text {
outline: 1px solid #4a4641;
outline-offset: 3px;
border-radius: 2px;
}
Давайте разберем, что же тут сделано. Ну, во-первых, мы даем cursor: pointer для лейбла, делая его как бы кликабельным. Затем явно скрываем инпут с помощью opacity и appearance. Оно как раз и нужно, чтобы сбросить внешний вид элемента.
Далее задаем стили тексту, в том числе flexbox. И вот тут начинается магия — мы делаем псевдоэлемент ::before для текста, и рисуем с его помощью чекбокс — по сути, просто квадрат с обводкой. А с помощью ::after рисуем квадратик, который будет внутри, то есть будет обозначать, отмечен чекбокс или нет. Этот квадратик мы по умолчанию скроем с помощью opacity.
И теперь, как я и говорил, всем будет управлять скрытый <input>. Важно не скрывать его с помощью display: none, иначе он не будет работать.
.custom-checkbox__input:checked + .custom-checkbox__text::after {
opacity: 1;
}
Здесь мы явно говорим «если чекбокс отмечен, найди следующий элемент (через +), и у него псевдоэлементу ::after задай opacity: 1„. Мы используем фишку с комбинаторными селекторами, и находим следующий за инпутом элемент через селектор „+“. Как вы понимаете, если бы структура html была другой, это бы просто не сработало. Имейте это ввиду.
Ну, а далее просто стилизуем кнопку. Важно тут не забывать давать font-family: inherit, cursor: pointer, а также задавать состояние :hover.
.content__btn {
display: flex;
align-items: center;
justify-content: center;
border: none;
border-radius: 20px;
padding: 16px;
width: 100%;
min-height: 58px;
font-family: inherit;
font-weight: 700;
font-size: 16px;
line-height: 120%;
color: #fff;
background: #232323;
cursor: pointer;
transition: background 0.3s;
}
.content__btn:hover {
background: #494848;
}
В результате мы получили полноценную страницу регистрации с удобным расположением полей, чекбоксом согласия и адаптивной версией для небольших устройств. Во время выполнения задания мы закрепили навыки работы с формами, Flexbox и научились создавать интерфейсы, которые часто встречаются в современных веб-приложениях.