Frontender Magazine

Проблема стилизации элементов форм

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

Год за годом не достаточно детализированная спецификация заставляла веб- разработчиков экспериментировать в попытках привести представление таких элементов, как input, select, fieldset, legend и textarea в разных браузерах к «общему знаменателю». В этой статье мы рассмотрим некоторые приемы CSS, используемые веб-разработчиками для стандартизации визуального представления элементов форм.

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

Сначала в 2004, а затем и в 2007 году, Роджер Йоханссон (Roger Johansson) создал исчерпывающий набор тестов для проверки применения CSS-стилей к элементам форм. Результатом выполнения этих тестов, которые вы можете найти в его статье «К вопросу о стилизации элементов форм с помощью CSS», стал неутешительный вывод, который Йоханссон выразил следующими словами:

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

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

Модель по умолчанию

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

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

В свою очередь, элементы form и fieldset являются блочными:

fieldset, form {
    display: block;
}

Описание модели, предлагаемой спецификацией CSS по умолчанию, этим и ограничивается. Все остальные визуальные аспекты элементов форм зависят от таблицы стилей браузера, применяемой по умолчанию. Тем не менее, перечисленные правила означают следующее:

Как веб-разработчики решают эти проблемы?

Размеры

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

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

Разработчики пытались решить эту проблему, превратив эти элементы в блочные:

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

Сработало только с textarea. Стандартное решения этой проблемы заключается в использовании вместо height свойств font-size и padding.

Элементы форм не наследуют гарнитуру и кегль шрифта, поэтому первым делом необходимо указать их:

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

Пример на jsFiddle: «CSS: указание размеров элементов форм».

После определения гарнитуры можно задать padding для добавления внутренних отступов блоку элемента:

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

Для элементов input и textarea в таблицах стилей браузеров определен border. Нормализуем его:

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

Элементам input с типом button и submit браузеры добавляют дополнительный отступ. Распространенная практика их нормализации:

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

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

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, но приводит к другим результатам:

Для select, и для input c типами checkbox и radio стоит использовать только:

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

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

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

  1. Использовать float,
  2. Использовать для некоторых элементов строчно-блочную модель.

При использовании float элементы автоматически становятся блочными. Это означает, что эти элементы форм теперь подчиняются девяти правилам float-элементов.

Вертикальная сетка

Элементы форм можно выравнивать по вертикали и по горизонтали.

При использовании float основной проблемой является правильное выравнивания по вертикали относительно текущей строки. Обычно это делают используя margin или padding:

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

Этот подход работает, когда вам не нужно задавать выравнивание блоков относительно текста, например, содержимого label. В случае, если это необходимо, вы можете использовать относительное позиционирование, padding и margin для элементов, содержащих только текст:

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

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

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

Еще прием с относительным позиционированием можно использовать для input с типами checkbox и radio. Относительное позиционирование можно использовать даже для нормализации отступа слева у элемента legend внутри элемента fieldset. Единственное отличие состоит в необходимости использования свойства left вместо top.

При использовании строчной и строчно-блочной модели для вертикального выравнивания элементов вы можете использовать свойство vertical-align:

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

Бывает удобно использовать это свойство вместе с line-height. Важно отметить, что применять это свойство необходимо к родительскому элементу. Если вы примените это свойство непосредственно к элементам формы, это скажется при расчете их высоты:

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

Явное указание высоты родительского элемента эффективно также при использовании вместе с равным ему значением высоты строки:

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

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

Странные особенности элементов выбора файлов

<input type="file"/> — это особый случай. Исходя из соображений безопасности, этот тип элементов всегда должен быть видимым и узнаваемым в браузере. Это означает, что браузеры преднамеренно игнорируют некоторые стили (например, стили, относящиеся к видимости элемента) и стремятся применять представление, описанное их собственными таблицами стилей.

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

Веб-разработчики, тем не менее, быстро нашли способ преодолеть эти ограничения. Сначала они поместили поле ввода в контейнер:

<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. Это предпочтительный способ для переопределения стилей браузера по умолчанию.

Пример на jsFiddle: «CSS: стилизация поля типа „файл“».

Заключение

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

Если вы заметили ошибку, вы всегда можете отредактировать статью, создать issue или просто написать об этом Антону Немцеву в skype ravencry.

Gabriele Romanato
Сергей Смольников
Переводчик:
Сергей Смольников
Мой Круг:
http://sergey-smolnikov.moikrug.ru/
Twitter:
@smolnikov
GitHub:
smolnikov