Блоки равной высоты в строке
Дата публикации: 15.09.2011
Задача
Сделать блоки одинаковой высоты, находящиеся в одной строке. Высота блоков зависит от содержимого.
Для решения этой задачи можно воспользоваться одним из старых методов выравнивания по высоте колонок. Но тут рассмотрим еще один вариант, который в некоторых случаях удобнее, чем остальные.
Решение
Каждая строка будет обернута контейнером. Этот контейнер по высоте будет равен высоте самого высокого блока в строке (используем особенность блочных элементов растягиваться по высоте с учетом содержимого.). Каждый блок в строке будет иметь дополнительный элемент для оформления своего родителя. Этот дополнительный элемент будет иметь ширину равную родителю, высоту 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.
Недостатки
- более новый IE8 заставляем работать как IE7. Вообще эта проблема — частный случай. Обойти ее можно по разному. Например, добавлять декоративные блоки динамически, или вставлять пустые теги сразу в код;
- программисту придется вычислять каждый три элемента и оборачивать их в контейнер;
- не подойдет для резиновых дизайнов, где в строке может разное число блоков в зависимости от ширины экрана;
- блоки выравниваются только визуально, что тоже подходит не для каждой задачи.
Более универсальный вариант
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; }