Когда я работал над очередным улучшением сайта БигБаззи, возникла задача добавления нового режима просмотра предложений — по три штуки в ряд, более компактными блоками (было по два крупных блока в ряд):

Дизайнер хочет, чтобы блоки с ценой, статистикой продаж и картинкой были всегда выровнены по одной горизонтальной линии. Но проблема в том, что название предложения всегда произвольной длины и, соответственно, получаются блоки разной высоты.
«Классическое» решение проблемы — прописать минимальную высоту блоку с названием, чтобы угадать некую среднюю величину, выше которой вряд ли что-то появится. Но у этого способа есть два недостатка: во-первых, практика показывает, что обязательно появится название, которое не впишется в отведённое пространство и развалит весь ряд. А во-вторых: при слишком коротких названиях будут появляться неприятные дыры между заголовком и блоком с ценой.
По сути, надо было придумать, как сделать так, чтобы блоки в одном ряду имели разное выравнивание по вертикали:

Такое расположение усложняется тем, что это не единственный режим просмотра: можно переключится на более крупный, двухколоночный режим. Причём желательно по-меньше трогать DOM-дерево — не делать специальных обёрток вокруг трёх или двух блоков, чтобы потом скриптом их перестраивать. Идеальный вариант — просто менять класс у контейнера и отдать всё изменение структуры на откуп CSS.
Как ни странно, но решение задачи нашлось, причём довольно элегантное.
Обычно такие последовательности блоков делаются самым очевидным образом: через float-элементы. Но этот способ нынче не в моде: все правильные ребята уже давно прочитали статью в блоге Мозиллы о том, как делать их через display: inline-block;.
А что будет, если поставить рядом блоки разной высоты?
<style type="text/css">
.wrap, .h, .f {
display: inline-block;
}
.h {
background: red;
height: 100px;
padding: 0 10px;
}
.f {
background: blue;
height: 20px;
padding: 0 10px;
color: #fff;
}
</style>
<span class="wrap">
<span class="h">header</span>
<span class="f">footer</span>
<span class="h">header</span>
<span class="f">footer</span>
</span>
Получим вот такой результат:

По умолчанию у всех блоков vertical-align: baseline, то есть вертикальное выравнивание по базовой линии (в данном случае, если проще — по последней строке текста). Если указать для .h{ vertical-align: top; } и для .f { vertical-align: bottom; }, то получим довольно интересное решение:

Блоки выровнены именно так, как нужно. Убеждаемся в правильности решения, изменив высоту одного из блоков:

Дальше всё просто: у шапки и подвала одинаковая и вполне определённая ширина, поэтому прописываем её каждому блоку, а подвал убираем из потока с помощью отрицательного margin’a:

Чтобы семантически объединить шапку и подвал, можно использовать любой элемент с display: inline. Итоговая версия доступна на тестовой странице.
Самое интересное, что этот код работает даже в IE6. Помним, что inline-block в этом браузере эмулируется с помощью display: inline и волшебного hasLayout, например, так: display: inline; zoom: 1;.
В этом решении важно помнить следующее:
- Шапка и подвал в примере пересекаются, поэтому шапке нужно снизу давать отступ и подтягивать подвал любым доступным способом.
- Между элементами конструкции не должно быть переводов строк и пробелов, иначе блоки визуально будут разделены.
В данном случае мне очень помогло то, что у подвала вполне предсказуемая высота, поэтому у шапки был добавлен снизу большой фиксированный отступ, чтобы блоки не перекрывались. Это решение полностью решило проблему и отображения, и переключения режимов. Можно пойти дальше и подключить CSS3 Media Queries, чтобы обладатели новых браузеров и больших мониторов могли видеть более трёх предложений в ряду, но это уже другая история. Думаю, читатели смогут найти более творческие и интересные применения этого небольшого трюка 🙂
