Box-sizing: переключаем блочную модель

Автор: Александр Головко и Татьяна Шкабко Дата публикации: 22.10.2010

Как известно, в IE6 размеры блока считаются не так как в остальных баузерах и включают в себя не только контентную часть элемента, но и внутренние отступы с границами (см. статью Блочная модель в IE6). Но иногда такой подсчет будет весьма кстати!

Задача

Сделать, чтобы блок растягивался на 50% ширины родителя и при этом имел внутренние отступы padding и границу border.

Решение 1. Стандартное — обертка.

Добавляем дополнительный контейнер-обертку. Задаем ему ширину 50% родителя. Самому блоку задаем внутренние отступы и границы (не задавая ширину). Таким образом внутренний блок займет все доступное пространство обертки без учета внутренних отступов и границ. При изменении размеров внутренних отступов и границ, размер внешнего блока меняться не будет.

Этот блок имеет размеры не зависящие от внутренних отступов
.wrap{
	width: 50%;
}
.element{
	padding: 10px;
	border: 5px;
}

Главный недостаток метода — дополнительный контейнер.

Решение 2. Для блока с абсолютным позиционированием.

Для блоков с position: absolute можно использовать прием описанный в статье Два в одном: позиция + размеры. Код будет таким:

Этот блок имеет размеры не зависящие от внутренних отступов
.parent{
	position: relative;
}
.element{
	position: absolute;
	left:0px;
	right:50%;
	padding: 10px;
	border: 5px;
}
* html .element{
	width: expression( parentNode.offsetWidth - 0 + 'px');
}

Преимущество — обошлись без контейнера.

Недостки — способ работает только для блоков спозиционированных абсолютно, используется expression.

Решение 3. Прогрессивное.

Как ты, конечно, догадался, речь идет о CSS3. А точнее, о CSS3 свойстве box-sizing. Это свойство позволяет переключаться между разными блочными моделями.

Это свойство по умолчанию имеет значение content-box и размеры элемента не включают внутренние отступы и границы (такая блочная модель по умолчанию принята во всех современных браузерах кроме IE6). При изменении значения на border-box размеры блока рассчитываются так как в IE6, т.е. содержат в себе внутренние отступы и границы элемента.

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

.element {
	box-sizing: border-box;
}

Но это только в теории! А на практике эту строчку поймут только Opera 7+ и IE8+. Для других популярных браузеров придется использовать это свойство с вендорными префиксами: -moz-box-sizing для Firefox 1+ и -webkit-box-sizing для Safari 3+ и Chrome.

Итого для нашего блока получим:

.element {
	width:50%;
	padding: 10px;
	border: 5px;
	-moz-box-sizing: border-box; /*Firefox 1+*/
	-webkit-box-sizing: border-box; /*Safari 3+, Chrome 1+*/
	box-sizing: border-box; /*Opera 7+, IE8+*/
}

IE6 свойство box-sizing, естественно, не поймет, но в нашем случае это и не нужно! Ведь в режиме Quirks Mode у него размеры элемента по умолчанию включают отcупы и границы.

Для IE7 (и IE6 в режиме Almost Standards Mode) все-таки придется использовать костыль — например, такой expression:

.element {
z-index: expression( /* оптимизированный expression, который сработает только при загрузке страницы */
runtimeStyle.zIndex = 1,
runtimeStyle.width = parentNode.offsetWidth/2 - 40 + 'px');}
}

В боевых условиях expression выносим в отдельный css файл, подключаемый с помощью условных комментариев.

Демо пример.

Проверено в:

Выводы

Если тебя не пугает expression для IE7, можно использовать box-sizing для решения подобных задач. Это позволит избавится от лишнего контейнера в HTML файле. Хотя, конечно, для резиновых сайтов использование такого expression вариант неудачный — оптимизированный expression сработает только один раз при загрузке докуманта, а неоптимизированный может порядочно тормозить.

Материалы