Xiper

Блоки равной высоты в строке

Автор: Евгений Рыжков Дата публикации:

Задача

Сделать блоки одинаковой высоты, находящиеся в одной строке. Высота блоков зависит от содержимого.

блоки равной высоты в строке

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

Решение

Каждая строка будет обернута контейнером. Этот контейнер по высоте будет равен высоте самого высокого блока в строке (используем особенность блочных элементов растягиваться по высоте с учетом содержимого.). Каждый блок в строке будет иметь дополнительный элемент для оформления своего родителя. Этот дополнительный элемент будет иметь ширину равную родителю, высоту 100% и абсолютное позиционирование. Чтобы высота была равна самому высокому блоку в строке, позиционируем декоративные элементы относительно блока-строки. Для более чистого и семантического кода, в качестве декоративных элементов использую псевдо элементы.

Если объяснения не очень понятны, то пример кода должен все прояснить:

<div class="row">
	<div class="item">
		содержимое
	</div>
	<div class="item">
		содержимое
	</div>
	<div class="item">
		содержимое
	</div>
</div>
<div class="row">
	<div class="item">
		содержимое
	</div>
	<div class="item">
		 содержимое
	</div>
	<div class="item">
		содержимое
	</div>
</div>
.row {
	position: relative; /* родитель растягивается по высоте согласно самому высокому дочернему блоку. позиционировать рамки нужно относительно его */
	width: 600px;
	margin-top: 20px;
	float: left;
}
.item {
	float: left; /* сделал флоатами чтобы меньше проблем было с позиционированием рамок */
	width: 150px;
	padding: 5px;
	margin-left: 20px;
}
.item:after {
	content: "";
	display: block;
	width: 160px; /* ширина рамки равна ширине блока-колонки */
	height: 100%; /* высота = высоте родителя = высоте самого высокого блока-колонки */
	border: 1px solid #0000FF; /* тут может быть любой декор для колонок */
	-webkit-box-shadow: 0 0 5px #0000FF;
	-moz-box-shadow: 0 0 5px #0000FF;
	box-shadow: 0 0 5px #0000FF;
	position: absolute;
	top: 0;
	left: 20px; /* учитываем отступ слева элемента .item */
	z-index: -1; /* чтобы был доступен контент элемента .item */ 
}
/* позиционируем остальные рамки с учетом размеров колонок и отступов между ними */
.item+.item:after {
	left: 200px;
}
.item+.item+.item:after {
	left: 380px;
}

Для IE7-8 подключаем дополнительные стили:

.item {
	z-index: expression(runtimeStyle.zIndex = 1, insertAdjacentHTML("afterBegin", "<div class="itemDecor"></div>"));
}
.itemDecor {
	width: 160px;
	height: 100%;
	border: 1px solid #0000FF;
	background: #fff;
	box-shadow: 0 0 5px #0000FF;
	behavior: url(pie.htc);
	position: absolute;
	top: 0;
	left: 20px;
	z-index: -1;
}
.item+.item .itemDecor {
	left: 200px;
}
.item+.item+.item .itemDecor {
	left: 380px;
}

Смотреть демо пример. Проверено в:

  • IE 7-9
  • Firefox 6
  • 11.11
  • Safari 5
  • Chrome

Заметка 1

За идею благодарим vlad.

Заметка 2

Т.к. IE8 не поддерживает свойство box-shadow, используем PIE. А так как PIE не срабатывает для псевдо элементов, пришлось перевести IE8 в режим эмуляции IE7.

Недостатки

  1. более новый IE8 заставляем работать как IE7. Вообще эта проблема — частный случай. Обойти ее можно по разному. Например, добавлять декоративные блоки динамически, или вставлять пустые теги сразу в код;
  2. программисту придется вычислять каждый три элемента и оборачивать их в контейнер;
  3. не подойдет для резиновых дизайнов, где в строке может разное число блоков в зависимости от ширины экрана;
  4. блоки выравниваются только визуально, что тоже подходит не для каждой задачи.

Более универсальный вариант

exessqd подсказал более универсальный вариант: вместо того чтобы просчитывать позиции для каждого декоративного элемента с использованием CSS селектора «+», можно переложить расчеты отступа слева на плечи браузера: если у абсолютно позиционируемого элемента задано left: auto и right: autо, браузер значение left: auto заменяется расстоянием от левого края блока с позиционированием до края левого поля гипотетического блока, который мог бы быть первым блоком элемента, если его свойство "position" было бы "static". Т.к. left: auto — значение по умолчанию, его можно вообще не писать:

.row {
	position: relative; 
	width: 600px;
	margin-top: 20px;
	float: left;
}
.item {
	float: left; 
	width: 150px;
	padding: 5px;
	margin-left: 20px;
}
.item:after {
	content: "";
	display: block;
	width: 160px; 
	height: 100%; 
	border: 1px solid #0000FF;
	-webkit-box-shadow: 0 0 5px #0000FF;
	-moz-box-shadow: 0 0 5px #0000FF;
	box-shadow: 0 0 5px #0000FF;
	position: absolute;
	top: -1px;
	margin-left: -6px; /* корректируем позицию декора с учетом padding */
	z-index: -1;
}

Для IE проводим аналогичное изменение в коде:

.item {
	z-index: expression(runtimeStyle.zIndex = 1, insertAdjacentHTML('afterBegin', '
')); } .itemDecor { width: 160px; height: 100%; border: 1px solid #0000FF; background: #fff; box-shadow: 0 0 5px #0000FF; behavior: url(pie.htc); position: absolute; top: -1px; margin-left: -6px; z-index: -1; }

Демо пример.

По теме