Разрешите представить вам перевод статьи «Cross-Browser Inline-Block», написанной Райном Доэрти холодным февралем 2009 года. В статье рассказывается о верстке элементов списка с установкой для свойства display значения inline-block. Статья об этом, а также о трудностях, возникающих в процессе достижения результата и о методах их «лечения».
Inline-block, заманчивое значение для свойства display, которое обещает очень много, а выполняет совсем мало. Очень часто я получал PSD-файлы, подобные этому:
Обычно такой способ отображения не вызывает проблем. Фиксированная ширина, фиксированная высота,float: left и готово. Если бы не одно, но! Дизайн должен отображаться корректно при любом количестве содержимого. В нашем случае, если в одном из блоков окажется чуть больше данных, то он «сломает» всю сетку.
Так как первый элемент выше следующих, пятый становится не под ним, как нам того хотелось бы, а «обтекает» по правому краю. В общем, нам необходима эластичность таблицы, но в правильной, семантичной верстке.
Начнем с простого примера, где у пунктов списка для свойства display установлено значение inline-block:
<ul>
<li>
<h4>This is awesome</h4>
<img src="http://farm4.static.flickr.com/3623/3279671785_d1f2e665b6_s.jpg"
alt="lobster" width="75" height="75"/>
</li>
...
<ul>
<style>
li {
width: 200px;
min-height: 250px;
border: 1px solid #000;
display: inline-block;
margin: 5px;
}
</style>
Результат выглядит корректно в Firefox 3, Safari 3 и в Opera:
Кажется, будто что-то не так с вертикальным выравниванием. Говоря по правде, никаких ошибок нет, это как раз корректное поведение браузера, но совсем не тот результат, которого мы бы хотели.
А происходит здесь следующее, базовая линия (baseline) каждого элемента <li> выравнивается с базовой линией родительского элемента <ul>. Вы спросите, что такое базовая линия? Лучше один раз увидеть, чем сто раз услышать:
Базовая линия на рисунке выше обозначена линией, идущей через основание символов. Значением по-умолчанию для свойства vertical-align у inline и inline-block элементов является baseline. Это значит, что базовая линия элементов выравнивается с базовой линией родителя. На рисунке ниже представлен пример такого выравнивания:
Как видите, каждая базовая линия блоков на рисунке выше выравнена по базовой линии текста «This is the baseline», который не является элементом <li>. Это просто текстовый узел, находящийся непосредственно в <ul>, помещенный туда в качестве индикатора расположения базовой линии элемента <ul>.
Получить желаемый изначально вариант выравнивания довольно просто, достаточно для свойства vertical-align указать значение top и получить в результате отличную сетку:
Вот только это не работает в Firefox 2, IE 6 и 7:
Для начала займемся Firefox 2.
Firefox 2 не поддерживает значение inline-block, зато отлично понимает специфичное для Мозиллы значение -moz-inline-stack для свойства display. Оно приводит к результатам, подобным действиюinline-block. Когда мы добавляем его перед display: inline-block, то Firefox 2 игнорирует вышеуказанное, так как не понимает его, и использует -moz-inline-stack. Другие браузеры используют inline-block, игнорируя непонятное для них -moz-inline-stack.
<style>
li {
width: 200px;
min-height: 250px;
border: 1px solid #000;
display: -moz-inline-stack;
display: inline-block;
vertical-align: top;
margin: 5px;
}
</style>
К сожалению, это вызывает небольшой баг:
Честно, я не знаю, что является его причиной. К счастью, лечится он довольно просто обертыванием всего содержимого элемента <li> дополнительным <div>.
<li>
<div>
<h4>This is awesome</h4>
<img src="http://farm4.static.flickr.com/3623/3279671785_d1f2e665b6_s.jpg"
alt="lobster" width="75" height="75"/>
</div>
</li>
Теперь перейдем к IE 7. Он тоже не поддерживает inline-block, но мы можем использовать трюк, благодаря которому элементы <li> будут выводиться на экран так, будто используют значение inline-block. Как? Будем использовать hasLayout, волшебное свойство IE, делающее доступными многие манипуляции. Вы не можете явно указать для элемента hasLayout: true или сделать это каким-либо подобным простым образом, однако можете запустить механизм, указав zoom: 1.
Технически элементы с hasLayout, установленным в значение true сами отвечают за рендеринг самих себя и дочерних элементов. Объедините это с min-height и width, и получите результат, очень близкий к display: block. Это как магический порошок, заставляющий исчезать все появляющиеся при отображении проблемы.
Когда мы добавим zoom: 1 и *display: inline (звездочка является хаком для IE 6 и IE 7) для элементов<li>, то научим IE 7 отображать их совсем как inline-block:
<style>
li {
width: 200px;
min-height: 250px;
border: 1px solid #000;
display: -moz-inline-stack;
display: inline-block;
vertical-align: top;
margin: 5px;
zoom: 1;
*display: inline;
}
</style>
Почти готово. Остался лишь IE 6:
IE 6 не поддерживает min-height, но взамен мы можем использовать его неверное обращение к свойствуheight. Установим для _height (обратите внимание на подчеркивание спереди) значение в 250pxи получим все элементы <li> с нужной высотой. Если же содержимое превысит указанную величину, то просто растянет свой контейнер. Все остальные браузеры проигнорируют _height.
Финальный CSS и HTML выглядит так:
<style>
li {
width: 200px;
min-height: 250px;
border: 1px solid #000;
display: -moz-inline-stack;
display: inline-block;
vertical-align: top;
margin: 5px;
zoom: 1;
*display: inline;
_height: 250px;
}
</style>
<li>
<div>
<h4>This is awesome</h4>
<img src="http://farm4.static.flickr.com/3623/3279671785_d1f2e665b6_s.jpg"
alt="lobster" width="75" height="75"/>
</div>
</li>