Блочная верстка форм
Дата публикации: 18.02.2009
Задача
Разработать схему верстки форм, которая позволяла бы без проблем сверстать форму любой сложности с соблюдением следующих требований:
- использование блочной верстки
- минимум кода (минимум элементов, классов)
- гибкость структуры
- структурированный легко читаемый код
- кроссбраузерность
- семантическая разметка
- полное разделение содержимого от оформления
- соответствие стандартам
- была возможность сохранить стандартный вид кнопок
Решение
Сначала отказываемся от использования универсального селектора для сброса отступов, чтобы избежать некотрых багов. Для этого используем reset.css.
Далее используем следующую HTML конструкцию:
<form action="..." method="...">
<div>
<label for="...">...</label>
<input type="..." id="..." />
</div>
. . .
<div>
<label for="...">...</label>
<input type="..." id="..." />
</div>
<div>
<input type="submit" value="..." />
</div>
</form>
- в качестве «строк» формы используем блоки (<div>)
- прописываем стили основным элементам формы: <div>, <label>, <input> и другим, если такие есть
- корректируем классами оформление элементов, несовпадающих по дизайну с элементами, прописанными по умолчанию (например, если в форме несколько разных по ширине input)
Update (20.10.2009): не забывайте, что после сдачи верстки, все еще может сильно измениться и/или доработаться (например, добавятся функции проверки корректности вводимых данных, вывод сообщений об ошибках в форме, подсказки пользователям и много чего еще может быть). Т.к. в выше предложенном примере линия формы — это div без класса, из-за наследования CSS свойств могут возникнуть проблемы с оформлением дополнительных элементов форм. Поэтому применяете «голые» только в простых формах, а в более сложных указывайте класс для <div>:
<form action="..." method="...">
<div class="formLine">
<label for="...">...</label>
<input type="..." id="..." />
</div>
. . .
<div class="formLine">
<label for="...">...</label>
<input type="..." id="..." />
</div>
<div class="formLine">
<input type="submit" value="..." />
</div>
</form>
CSS для формы:
form {
width: 300px; /* задаем ширину формы, чтобы сработал overflow */
overflow: hidden; /* обрезаем выступы за форму (в частности в ие6 неправильно расчитанный width для div) */
padding: 2px; /* небольшой отступ чтобы не обрезалась подсветка input в фокусе в Safari и Chrome */
}
form .formLine {
float: left; /* чтобы не было проблем с отступами между блоками */
width: 100%; /* чтобы блоки не встраивались в одну строку */
margin-bottom: 5px; /* расстояние между блоками */
}
form label {
float: left; /* делаем метки плавающими и фиксированной ширины чтобы выровнять их по одному уровню */
width: 60px;
text-align: right;
position: relative; /* выравниваем тексты меток и полей по одному уровню */
top: 2px; /* отступ сверху подбираем в зависимости от размера шрифта и дизайна полей */
margin-right: 5px; /* чтобы к меткам не прилипали поля */
}
form input[type=text], form input[type=password] {/* оформление для полей типа text и password */
width: 200px;
background: #fff; /* обязательно указываем цвет фона (или ставим его none), т.к. в браузере могут быть свои значения по умолчанию */
border: 1px solid #7f9db9; /* цвет бордюра */
height: 20px; /* явно задаем высоту, для кроссбраузерности */
}
form .formText {/* класс для ие6, который не понимает свойства по типам селекторов */
width: 200px;
background: #fff;
border: 1px solid #7f9db9;
height: 20px;
}
form input[type=submit] {/* оформление для кнопки submit */
margin-left: 65px;
cursor: pointer; /* меняем указатель для кнопки */
}
form .formSubmit {/* класс для ие6 */
margin-left: 65px;
cursor: pointer;
width: auto;
}
* html input {/* хак для ие6, котрый поможет ему понять типы селекторов */
z-index: expression(
runtimeStyle.zIndex = 1,
type == "text" ? (className = "formText") : 0,
type == "password" ? (className = "formText") : 0,
type == "submit" ? (className = "formSubmit") : 0
)
}
Детальней о методе можно узнать в статье «Как научить IE6 понимать в CSS типы».
Например, форма для входа на сайт:
<form action="php/enterToSite.php" method="post">
<div>
<label for="login">Логин:</label>
<input type="text" id="login" name="login" />
</div>
<div>
<label for="password">Пароль:</label>
<input type="password" id="password" />
</div>
<div>
<input type="submit" value="Войти" />
</div>
</form>
Усложним форму:
HTML код:
<form action="php/register.php" method="post">
<div>
<input type="radio" id="mr" name="r1" /><label for="mr" class="formLabelAuto">Господин</label>
<input type="radio" id="ms" name="r1" /><label for="ms" class="formLabelAuto">Госпожа</label>
</div>
<div>
<label for="name">ФИО:</label>
<input type="text" id="name" />
</div>
<div>
<label for="email">Email:</label>
<input type="text" id="email" />
</div>
<div>
<label>Телефон:</label>+
<input type="text" class="formCodeCountry" />
<input type="text" class="formCodeCity" />
<input type="text" />
</div>
<div>
<label for="message">Сообщение:</label>
<textarea id="message" cols="" rows=""></textarea>
</div>
<div>
<input type="checkbox" id="dispatch" />
<label for="dispatch" class="formLabelAuto">Подписаться на рассылку</label>
</div>
<div>
<input type="submit" value="Войти" />
</div>
</form>
CSS код:
form {
width: 500px;
overflow: hidden;
padding-top: 2px;
}
form div {
float: left;
width: 100%;
margin-bottom: 5px;
}
form label {
float: left;
width: 80px;
text-align: right;
position: relative;
top: 2px;
margin-right: 5px;
}
form input[type=text], form input[type=password] {
width: 150px;
background: #fff;
border: 1px solid #7f9db9;
height: 20px;
}
form .formText {
width: 150px;
background: #fff;
border: 1px solid #7f9db9;
height: 20px;
}
form input[type=submit] {
margin-left: 85px;
cursor: pointer;
}
form .formSubmit {
margin-left: 85px;
cursor: pointer;
width: auto;
}
form input[type=checkbox] {
border: none;
}
.formCheck {
background: none;
}
* html input {
z-index: expression(
runtimeStyle.zIndex = 1,
className == "formCodeCountry" ? (style.width = "20px") : 0,
className == "formCodeCity" ? (style.width = "30px") : 0,
type == "text" ? (className = "formText") : 0,
type == "password" ? (className = "formText") : 0,
type == "submit" ? (className = "formSubmit") : 0,
type == "checkbox" ? (className = "formCheck") : 0
)
}
form textarea {
width: 250px;
height: 100px;
}
form .formLabelAuto { /* для label рядом с radio и check */
width: auto; /* сбрасываем все, что уставили чтобы элемент вел себя как обычно */
float: none;
position: static;
}
form input.formCodeCountry { /* input с кодом страны */
width: 20px;
}
form input.formCodeCity { /* input с кодом города */
width: 30px;
}
form #mr { /* отступ для radio с Господин */
margin-left: 85px;
}
form #dispatch { /* отступ для checkbox */
margin-left: 85px;
}
Результат. В примере expression скрыт условными комментариями, чтобы CSS-код соответствовал стандартам.
Нормой в формах является пометка обязательных полей и стилизация сообщений об ошибках. Это можно сделать так:
обязательное поле помечаем звездочкой в <label>
<label for="name">ФИО:<span>*</span></label>
строка формы с ошибкой выглядит так:
<div class="formError"> <!-- добавили класс чтобы выделить label и input -->
<label for="email">Email:<span>*</span></label>
<input type="text" id="email" />
<span class="formErrorMess">Введите действительный email!</span> <!-- сообщение об ошибке -->
</div>
В CSS добавляем:
form label span {
color: #ff0000; /* цвет звездочки */
}
form .formError label {
color: #ff0000; /* цвет метки при ошибке */
}
form .formError input {
border-color: #ff0000; /* цвет бордюра у поля в котором была ошибка */
}
form .formErrorMess { /* оформление сообщения об ошибке */
color: #ff0000;
display: block;
margin-left: 85px;
}
Проверено в:
Для повышения юзабилити формы следует полям добавлять свойство maxlength, чтобы пользователь не мог ввести заведомо больше символов, чем отведено в базе данных для этого поля (согласовывается с программистами). Так же, если порядок полей может меняться, следует добавлять tabindex, для сохранения последовательного таб обхода.
Чтобы сохранить стандартный вид кнопок понадобилось использование определение типов полей в CSS (input[type=text], input[type=submit], input[type=checkbox] и др.), что повлекло использовние expression для IE6.
Недостатки метода из-за использования expression:
- не проходит валидацию (использование условных комментариев решает эту проблему)
- замедляет скорость загрузки страницы (только для пользователей, использующих IE6)
Если в форме используются кнопки нестандартного оформление (дизайн кнопок отличается от дизайна кнопок, которые используются по умолчанию браузерами), можно избавиться от expression:
- задаем базовое оформление для input
- для полей checkbox, submit, radio создаем отдельные классы (.checkbox, .submit, .radio)
Так код будет несколько «грязнее» из-за дополнительных классов, но зато без expression. Каждый выбирает сам, какой метод ему подходит больше.
