Все давно знают про кроссбраузерную реализацию инлайн-блоков, но не все знают, что данная реализация не такая уж и кроссбраузерная и полная, как кажется. Что, как и почему рассмотрим на простом примере: сделаем меню, пункты которого равномерно распределены по всей ширине экрана.
Обычно в разметке меню выглядит так:
А css для этого примерно таков:
В итоге получается, что каждый пункт меню — это слово в строке (независимо от того, сколько слов внутри пункта, т.к. инлайн-блок — неделимая единица со своим контекстом форматирования) и чтобы слова растягивались на всю ширину строки нужно сделать следующее:
Но желаемого результата это не даст, т.к. в css нет значения full-justify для свойства text-align, а обычный justify растягивает расстояния между слов в строках, кроме последней, так что нам нужно вписать какое-нибудь достаточно длинной слово, которое бы переносилось на новую строку (в css3 есть text-align-last для манипуляции выравниванием последней строки, но это прокатит лишь в светлом будущем). Писать слово, конечно, не очень хороший вариант, достаточно просто сделать ещё один пункт меню и растянуть его на 100% ширины родителя (можно и меньше 100, тогда можно добиться довольно интересного эффекта):
Данный код будет одинаково хорошо работать во всех браузерах… кроме Internet Explorer 6 и 7 (кто бы сомневался). А проблема кроется в том, что такие «инлайн-блоки» в данных версиях эксплорера «слишком блочные» — они не учитывают пробельные символы вокруг себя. Наглядный пример:
В нормальных браузерах это будет выглядеть так:
В старых версиях эксплорера так:
К счастью есть решение этой проблемы и лежит оно на поверхности — надо сделать этот «инлайн-блок» более инлайновым, для это его нужно обернуть в инлайн элемент. Что получается:
Но и это не даст нужного результата, хотя всё вроде бы как надо. Проблема заключается в том, что эксплорер не считает каждый пункт единым целым и поэтому всё распадается — дело в пробельных символах закрывающей последовательности тегов. Фиксится просто:
Если вы пользуетесь шаблонизатором, то пусть эту работу сделает он (например тег spaceless в django templates или jinja).
Теперь всё выглядит хорошо и так как нужно во всех браузерах… пока мы не хотим сделать что-нибудь интересное внутри каждого пункта, пусть это будет иконка прижатая к правому краю каждого пункта:
Во всех браузерах включая старые эксплореры всё ок… кроме всех версий Оперы (кто бы сомневался). В Опере можно увидеть, что иконка не прижата к правому краю пункта, а находится левее — это банальный баг, который будет мешать жить разработчикам ещё лет 10, не меньше. Заключается он в том, что если в inline-block элементе находится не блочный элемент или не текст, происходит нарушение границ позиционирования. Фиксится это добавлением ещё одной, внутренней, блочной обёртки.
Теперь главное не включить какому-нибудь блочному элементу внутри .menu-item hasLayout в IE6, т.к. это спровоцирует «распирание» нашего инлайн-блока на всю ширину. Решить это можно задав фиксированную ширину блочному элементу (если нужна ширина по содержимому нужно задать нулевую ширину, но только для IE6).
С одной стороны получилось непросто и не совсем красиво, а с другой стороны мы получили решение, которое ведёт себя как надо и может использоваться без опаски (почти) и в других местах, например для создания своих собственных элементов управления, которые бы вели себя в контенте подобно стандартным браузерным элементам управления (чтобы изменять поведение такого элемента управления нужно всё применять к инлайн-блочной его части, например если вы захотите сделать элемент блочным или плавающим).
Ну и для закрепляющего эффекта, «формула» настоящего инлайн-блока в zen-css-подобном псевдокоде:
Может кто-то всё-таки донесёт до администрации, что нам тут нужна подсветка CSS? А то моя просьба как-то была проигнорирована.
Обычно в разметке меню выглядит так:
<ul class="menu">
<li class="menu-item">
<a href="/news">Новости</a>
</li>
<li class="menu-item">
<a href="/swen">Старости</a>
</li>
<li class="menu-item">
<a href="/profit">Всякая информация</a>
</li>
</ul>
А css для этого примерно таков:
.menu-item {
display: inline-block;
}
* html .menu-item {
display: inline;
zoom: 1;
}
*+html .menu-item {
display: inline;
zoom: 1;
}
В итоге получается, что каждый пункт меню — это слово в строке (независимо от того, сколько слов внутри пункта, т.к. инлайн-блок — неделимая единица со своим контекстом форматирования) и чтобы слова растягивались на всю ширину строки нужно сделать следующее:
.menu {
text-align: justify;
}
.menu-item {
display: inline-block;
text-align: left;
}
* html .menu-item {
display: inline;
zoom: 1;
}
*+html .menu-item {
display: inline;
zoom: 1;
}
Но желаемого результата это не даст, т.к. в css нет значения full-justify для свойства text-align, а обычный justify растягивает расстояния между слов в строках, кроме последней, так что нам нужно вписать какое-нибудь достаточно длинной слово, которое бы переносилось на новую строку (в css3 есть text-align-last для манипуляции выравниванием последней строки, но это прокатит лишь в светлом будущем). Писать слово, конечно, не очень хороший вариант, достаточно просто сделать ещё один пункт меню и растянуть его на 100% ширины родителя (можно и меньше 100, тогда можно добиться довольно интересного эффекта):
<ul class="menu">
<li class="menu-item">
<a href="/news">Новости</a>
</li>
<li class="menu-item">
<a href="/swen">Старости</a>
</li>
<li class="menu-item">
<a href="/profit">Всякая информация</a>
</li>
<li class="menu-item menu-item_sizer">
</li>
</ul>
.menu {
text-align: justify;
}
.menu-item {
display: inline-block;
text-align: left;
}
* html .menu-item {
display: inline;
zoom: 1;
}
*+html .menu-item {
display: inline;
zoom: 1;
}
.menu-item_sizer {
width: 100%;
}
Данный код будет одинаково хорошо работать во всех браузерах… кроме Internet Explorer 6 и 7 (кто бы сомневался). А проблема кроется в том, что такие «инлайн-блоки» в данных версиях эксплорера «слишком блочные» — они не учитывают пробельные символы вокруг себя. Наглядный пример:
<span class="inlineBlock">Test</span> word
В нормальных браузерах это будет выглядеть так:
Test word
В старых версиях эксплорера так:
Testword
К счастью есть решение этой проблемы и лежит оно на поверхности — надо сделать этот «инлайн-блок» более инлайновым, для это его нужно обернуть в инлайн элемент. Что получается:
<ul class="menu">
<li class="menu-item_wrap">
<div class="menu-item">
<a href="/news">Новости</a>
</div>
</li>
<li class="menu-item_wrap">
<div class="menu-item">
<a href="/swen">Старости</a>
</div>
</li>
<li class="menu-item_wrap">
<div class="menu-item">
<a href="/profit">Всякая информация</a>
</div>
</li>
<li class="menu-item_wrap menu-item_sizer">
</li>
</ul>
.menu {
text-align: justify;
}
.menu-item_wrap {
display: inline;
}
.menu-item {
display: inline-block;
text-align: left;
}
* html .menu-item {
display: inline;
zoom: 1;
}
*+html .menu-item {
display: inline;
zoom: 1;
}
.menu-item_sizer {
width: 100%;
}
Но и это не даст нужного результата, хотя всё вроде бы как надо. Проблема заключается в том, что эксплорер не считает каждый пункт единым целым и поэтому всё распадается — дело в пробельных символах закрывающей последовательности тегов. Фиксится просто:
<ul class="menu">
<li class="menu-item_wrap">
<div class="menu-item">
<a href="/news">Новости</a></div></li>
<li class="menu-item_wrap">
<div class="menu-item">
<a href="/swen">Старости</a></div></li>
<li class="menu-item_wrap">
<div class="menu-item">
<a href="/profit">Всякая информация</a></div></li>
<li class="menu-item_wrap menu-item_sizer"> </li>
</ul>
Если вы пользуетесь шаблонизатором, то пусть эту работу сделает он (например тег spaceless в django templates или jinja).
Теперь всё выглядит хорошо и так как нужно во всех браузерах… пока мы не хотим сделать что-нибудь интересное внутри каждого пункта, пусть это будет иконка прижатая к правому краю каждого пункта:
<ul class="menu">
<li class="menu-item_wrap">
<div class="menu-item">
<span class="menu-item-icon"> </span>
<a href="/news">Новости</a></div></li>
<li class="menu-item_wrap">
<div class="menu-item">
<span class="menu-item-icon"> </span>
<a href="/swen">Старости</a></div></li>
<li class="menu-item_wrap">
<div class="menu-item">
<span class="menu-item-icon"> </span>
<a href="/profit">Всякая информация</a></div></li>
<li class="menu-item_wrap menu-item_sizer"> </li>
</ul>
.menu {
text-align: justify;
}
.menu-item_wrap {
display: inline;
}
.menu-item {
background-color: Green;
display: inline-block;
padding: 5px 15px;
position: relative;
text-align: left;
}
* html .menu-item {
display: inline;
zoom: 1;
}
*+html .menu-item {
display: inline;
zoom: 1;
}
.menu-item_sizer {
width: 100%;
}
.menu-item-icon {
background-color: Red;
height: 5px;
position: absolute;
right: 0;
}
Во всех браузерах включая старые эксплореры всё ок… кроме всех версий Оперы (кто бы сомневался). В Опере можно увидеть, что иконка не прижата к правому краю пункта, а находится левее — это банальный баг, который будет мешать жить разработчикам ещё лет 10, не меньше. Заключается он в том, что если в inline-block элементе находится не блочный элемент или не текст, происходит нарушение границ позиционирования. Фиксится это добавлением ещё одной, внутренней, блочной обёртки.
<ul class="menu">
<li class="menu-item_outerWrap">
<div class="menu-item">
<div class="menu-item_innerWrap">
<span class="menu-item-icon"> </span>
<a href="/news">Новости</a></div></div></li>
<li class="menu-item_outerWrap">
<div class="menu-item">
<div class="menu-item_innerWrap">
<span class="menu-item-icon"> </span>
<a href="/swen">Старости</a></div></div></li>
<li class="menu-item_outerWrap">
<div class="menu-item">
<div class="menu-item_innerWrap">
<span class="menu-item-icon"> </span>
<a href="/profit">Всякая информация</a></div></div></li>
<li class="menu-item_outerWrap menu-item_sizer"> </li>
</ul>
.menu {
text-align: justify;
}
.menu-item_outerWrap {
display: inline;
}
.menu-item {
background-color: Green;
display: inline-block;
padding: 5px 15px;
position: relative;
text-align: left;
}
* html .menu-item {
display: inline;
zoom: 1;
}
*+html .menu-item {
display: inline;
zoom: 1;
}
.menu-item_innerWrap {
display: block;
}
.menu-item_sizer {
width: 100%;
}
.menu-item-icon {
background-color: Red;
height: 5px;
position: absolute;
right: 0;
}
Теперь главное не включить какому-нибудь блочному элементу внутри .menu-item hasLayout в IE6, т.к. это спровоцирует «распирание» нашего инлайн-блока на всю ширину. Решить это можно задав фиксированную ширину блочному элементу (если нужна ширина по содержимому нужно задать нулевую ширину, но только для IE6).
С одной стороны получилось непросто и не совсем красиво, а с другой стороны мы получили решение, которое ведёт себя как надо и может использоваться без опаски (почти) и в других местах, например для создания своих собственных элементов управления, которые бы вели себя в контенте подобно стандартным браузерным элементам управления (чтобы изменять поведение такого элемента управления нужно всё применять к инлайн-блочной его части, например если вы захотите сделать элемент блочным или плавающим).
Ну и для закрепляющего эффекта, «формула» настоящего инлайн-блока в zen-css-подобном псевдокоде:
inline>inline-block>block
Может кто-то всё-таки донесёт до администрации, что нам тут нужна подсветка CSS? А то моя просьба как-то была проигнорирована.