Архив за Апрель 2011

  • Список блоков с разным вертикальным выравниванием

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

    example

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

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

    По сути, надо было придумать, как сделать так, чтобы блоки в одном ряду имели разное выравнивание по вертикали:

    scheme

    Такое расположение усложняется тем, что это не единственный режим просмотра: можно переключится на более крупный, двухколоночный режим. Причём желательно по-меньше трогать 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>
    

    Получим вот такой результат:

    ss1

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

    ss2

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

    ss3

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

    ss4

    Чтобы семантически объединить шапку и подвал, можно использовать любой элемент с display: inline. Итоговая версия доступна на тестовой странице.

    Самое интересное, что этот код работает даже в IE6. Помним, что inline-block в этом браузере эмулируется с помощью display: inline и волшебного hasLayout, например, так: display: inline; zoom: 1;.

    В этом решении важно помнить следующее:

    1. Шапка и подвал в примере пересекаются, поэтому шапке нужно снизу давать отступ и подтягивать подвал любым доступным способом.
    2. Между элементами конструкции не должно быть переводов строк и пробелов, иначе блоки визуально будут разделены.

    В данном случае мне очень помогло то, что у подвала вполне предсказуемая высота, поэтому у шапки был добавлен снизу большой фиксированный отступ, чтобы блоки не перекрывались. Это решение полностью решило проблему и отображения, и переключения режимов. Можно пойти дальше и подключить CSS3 Media Queries, чтобы обладатели новых браузеров и больших мониторов могли видеть более трёх предложений в ряду, но это уже другая история. Думаю, читатели смогут найти более творческие и интересные применения этого небольшого трюка 🙂