Все давно знают про кроссбраузерную реализацию инлайн-блоков, но не все знают, что данная реализация не такая уж и кроссбраузерная и полная, как кажется. Что, как и почему рассмотрим на простом примере: сделаем меню, пункты которого равномерно распределены по всей ширине экрана.
Обычно в разметке меню выглядит так:
А 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? А то моя просьба как-то была проигнорирована.
