Блочная верстка форм
Дата публикации: 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. Каждый выбирает сам, какой метод ему подходит больше.