Когда я работал над очередным улучшением сайта БигБаззи, возникла задача добавления нового режима просмотра предложений — по три штуки в ряд, более компактными блоками (было по два крупных блока в ряд):
Дизайнер хочет, чтобы блоки с ценой, статистикой продаж и картинкой были всегда выровнены по одной горизонтальной линии. Но проблема в том, что название предложения всегда произвольной длины и, соответственно, получаются блоки разной высоты.
«Классическое» решение проблемы — прописать минимальную высоту блоку с названием, чтобы угадать некую среднюю величину, выше которой вряд ли что-то появится. Но у этого способа есть два недостатка: во-первых, практика показывает, что обязательно появится название, которое не впишется в отведённое пространство и развалит весь ряд. А во-вторых: при слишком коротких названиях будут появляться неприятные дыры между заголовком и блоком с ценой.
По сути, надо было придумать, как сделать так, чтобы блоки в одном ряду имели разное выравнивание по вертикали:
Такое расположение усложняется тем, что это не единственный режим просмотра: можно переключится на более крупный, двухколоночный режим. Причём желательно по-меньше трогать 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, чтобы обладатели новых браузеров и больших мониторов могли видеть более трёх предложений в ряду, но это уже другая история. Думаю, читатели смогут найти более творческие и интересные применения этого небольшого трюка 🙂