Проблемы с элементами форм

Еще до рождения спецификации CSS level 2 элементы форм уже работали во всех основных браузерах. Спецификация CSS2 толком не говорила как конкретно элементы форм должны выглядеть. Поскольку эти элементы присутствуют практически на каждой веб странице, авторы спецификации предпочли оставить внешний вид на усмотрение производителей браузеров. За годы существования элементов форм веб-девелоперы сделали кучи тестов и попыток причесать элементы типа input, select, fieldset, legend и textarea, так чтобы они выглядели кроссбраузерно. В этой статье мы поговорим о некоторых приемах которые используют девелоперы чтобы укротить внешний вид этих элементов.

Тесты Роджера Йохансена

В 2004 году, а потом еще и 2007, Роджер Йохансен сделал глобальный тест форм в разных браузерах. Тесты, которые можно посмотреть в его статье Styling form controls with CSS, revisited, ведут к неприятному выводу который Йохансен выразил так:

Что показывает этот эксперимент? Как я уже говорил, он показывает что при помощи CSS невозможно добиться одинакового отображения элементов форм в разных браузерах. И еще тесты показывают что многие браузеры ингорируют многие CSS свойства, когда они применяются к элементам форм.

Несмотря на то что все это верно, девелоперы настойчиво продолжали искать золотую середину между дефолтным отображением форм браузерами и авторскими стилем.

Начальные значения

Спецификация говорит что элементы формы как то textarea, input и select являются инлайн-блочными элементами:

textarea, input, select {
    display: inline-block;
}

Form и fieldset, наоборот, блочные.

fieldset, form {
    display: block;
}

Это все что говорит спецификация. Остальное дело производителей браузеров. Хотя это тоже что-то, эти правила подразумевают следующее:

  • Инлайн-блочные элементы можно оформлять как строчные элементы, это значит что мы можем применять к ним line-height, vertical-align чтобы контролировать высоту и вертикальное выравнивание. Отступы и маржины тоже можно использовать для внутренних и внешних отступов. Инлайн-блоки понимают ширину и высоту, поскольку они отчасти блочные элементы.
  • Блочные элементы можно оформлять на основе хорошо известного блочного контекста. Проблемы начинаются с элементами legend и fieldset, потому что они полностью полагаются на дефолтные стили браузера.

Как с этим всем бороться?

Определение размеров

p Девелоперы заметили что браузеры могут странно отображать инлайн-блочные элементы когда дело доходит до определения их размеров:

input, select {
    width: 120px;
    height: 32px;
}

Попытка превратить элементы в блочные тоже ни к чему не приводит, за исключением textarea. Выход из проблемы не использовать высоту и вместо этого пользоваться размером шрифта и отступами.

Браузеры не применяют шрифт и размер который у вас определен дефолтными, поэтому первое что надо сделать это “нормализовать” их:

input, select {
    width: 120px;
    font: 1em Arial, sans-serif;
}

Пример – CSS: Defining Form Element Dimensions

После этого можно добавлять отступы:

input, select {
    width: 120px;
    font: 1em Arial, sans-serif;
    padding: 3px 6px;
}

Textarea и input имеют дефолтный бордер который влияет на бокс-модель, то бишь на размеры.

input[type="text"],
input[type="password"],
textarea {
    border: 1px solid #ccc;
}

Элементы типа button и submit имеют дополнительный отступ который устанавливается браузером, лучше нормализовать эти отступы:

input[type="button"],
input[type="submit"] {
    padding: 2px;
}

Проблема в том что веб браузеры имею специфические свойства для этих элементов, поэтому padding не всегда решает задачу. К примеру, в вебкитах вы можете увидеть нечто такое:

input[type="button"], input[type="submit"],
input[type="reset"], input[type="file"]::-webkit-file-upload-button,
button {
    -webkit-box-align: center;
    text-align: center;
    cursor: default;
    color: buttontext;
    padding: 2px 6px 3px;
    border: 2px outset buttonface;
    border-image: initial;
    background-color: buttonface;
    box-sizing: border-box;
}
input[type="button"], input[type="submit"], input[type="reset"] {
    -webkit-appearance: push-button;
    white-space: pre;
}

Если применять padding к элементам fieldset и legend то следует помнить что:

  • Применение padding к fieldset обнуляет отступ элемента legend в некоторых браузерах ** Применение padding = 0 к элементу legend приводит к тому что он сжимается

Select, checkbox, radio можно достойно нормализовать только для некоторых свойств, а именно:

  • font-family
  • font-size
  • width только на селектах
  • padding

Применение других свойств к этой группе элементов приводит к разным результатам в разных браузерах.

Выравнивание

Элементы форм можно выравнивать по вертикали и горизонтали. Они могут быть выложены на одной линии или как группа боксов на нескольких строках. Чтобы выровнять их на одной линии нужно следовать одному из двух подходов:

  1. Использовать плавающие блоки (floating)
  2. Использовать инлайновый контекст для некоторых элементов форм

Если использовать float то элемент становится блочным, это мы знаем, и к нему применяется девять правил которые управляют плавающими блоками

выравнивание блочных элементов

Главная сложность с флотами это добиться нормального вертикального выравнивания, типичный выход это вертикальные маржины или отступы:

input, select {
    width: 120px;
    float: left;
    margin-top: 0.4em;
}

Такой подход работает если вам не нужно выравнивать боксы с текстом, такие как label. Для элементов которые содержат только текст можно использовать относительное позиционироване, отступы или маргины:

label {
    float: left;
    padding-top: 0.4em;
    width: 5em;
    margin-right: 1em;
}

Другая проблема возникает когда, к примеру, кнопка имеет вертикальный размер больше чем другие элементы. Чтобы выровнять, можно пользоваться относительным позиционированием:

input[type="submit"] {
    float: left;
    width: 90px;
    position: relative;
    top: 0.4em;
}

Таким же образом можно выравнивать чекбоксы и радио кнопки. Относительное позиционирование можно использовать для выравнивания как вам нужно элемента legend.

Если пользоваться инлайновым форматированием, то есть превратить все элементы форм в инлайн блоки, то можно пользоваться свойством vertical-align для вертикального выравнивания.

label, input[type="text"] {
    vertical-align: middle;
    margin-right: 1em;
}

Хороших результатов можно добиться комбинированием vertical-align и line-height, только второе надо применять к родительскому элементу, а не к самому элементу формы. Иначе поменяется высота элемента.

.form-row {
    line-height: 1.4;
}

Эффективно указать одновременно высоту элемента:

.form-row {
    line-height: 1.8;
    height: 1.8em;
}

При инлайновом форматировании также можно использовать свойство text-align.

Странный случай File input

Случай поля ввода файла особый, это элемент который всегда должен быть видимым и узнаваемым в интерфейсе по причинам безопасности. Это подразумевает что браузеры намеренно игнорируют некоторые стили (типа видимости) для того чтобы нельзя было отступиться от дефолтных стилей браузера.

Более того, вид этого элемента по умолчанию варьируется от браузера к браузеру: некоторые отображают только одну кнопку, некоторые добавляют текстовое поле с указанием пути загружаемого файла.

Девелоперы, тем не менее, нашли способ обойти эти ограничения. Первым делом, они обворачивают элемент в контейнер:

<form action="" method="post" enctype="multipart/form-data">
    <div class="upload">
        <input type="file" name="upload"/>
    </div>
</form>

Элемент input скрывается при помощи свойства opacity, а родительский элемент оформляется как загрузчик файла.

.upload {
    width: 157px;
    height: 57px;
    background: url(upload.png) no-repeat;
    overflow: hidden;
}
.upload input {
    display: block !important;
    width: 157px !important;
    height: 57px !important;
    opacity: 0 !important;
    overflow: hidden !important;
}

Обратите внимание на !important. Это делается для того чтобы перекрыть дефолтные значения.

JS Bin

Выводы

Полностью подчинить элементы форм невозможно в связи с отсутствием деталей в спецификации CSS и из-за дефолтных стилей браузеров. Тем не менее, если следить за наработками девелоперов то можно сократить различия и добиться хорошего визуального результата.

comments powered by Disqus