Создание вертикального кросс-браузерного меню без использования JavaScript — чистый CSS!
Так случилось, что срочно понадобилось сделать горизонтальное меню, причем для проекта, который нужно было сдавать вчера
Естественно, самому писать не было времени, нужно было взять что-то готовое. Я недавно прочитал статью "Всплывающее гибридное меню на CSS", поэтому взял код именно оттуда. Но не в этом дело. У подавляющего большинства меню камнем преткновения становится IE6 — а всё из-за того, что он понимает :hover только для тэга <a>. Когда-то у меня был заказчик, требовавший, чтобы всё одинаково работало с выключенным JavaScript'ом; вспомнив его, я решил попробовать сделать меню, работающее безо всякого JavaScript. Так получилось, что попутно я нашел еще один очень интресный глюк в IE6 (о нём далее), в борьбе с которым у меня получилось вертикальное меню.
Друг заметил, что смысла уродоваться не было, ибо есть whatever:hover, который применяется многими разработчиками. Для всех, кто такого же мнения, отмечу, что whatever:hover — это HTC-компонент, суть JavaScript, вследствие чего при выключенном JavaScript работать не будет. Помимо этого, whatever:hover не будет работать при динамическом построении меню. И еще его использование негативно сказывается на отклик IE при начальном рендеринге (в смысле, когда весь DOM уже загружен и наступило время выполнять deferred-скрипты и грузить картинки).
Приступим.
Разметку я взял все из той же статьи, она (разметка) имеет следующий вид:
<li>
<a href="#">Renaissance</a>
<ul>
<li><a href="#">Brunelleschi</a></li>
<li><a href="#">Alberti</a></li>
<li><a href="#">Palladio</a></li>
<li><a href="#">Michelangelo</a></li>
<li><a href="#">Bramante</a></li>
</ul>
</li>
<li>
<a href="#">Art Nouveau</a>
<ul>
<li><a href="#">Mackintosh</a></li>
<li><a href="#">Guimard</a></li>
<li><a href="#">Horta</a></li>
<li><a href="#">van de Velde</a></li>
</ul>
</li>
<li>
<a href="#">Modern</a>
<ul>
<li><a href="#">Sullivan</a></li>
<li><a href="#">Le Corbusier</a></li>
<li><a href="#">Mies</a></li>
<li><a href="#">Gropius</a></li>
<li><a href="#">Yamasaki</a></li>
</ul>
</li>
<li>
<a href="#">Postmodern</a>
<ul>
<li><a href="#">Venturi</a></li>
<li><a href="#">Eisenman</a></li>
<li><a href="#">Stern</a></li>
<li><a href="#">Graves</a></li>
<li><a href="#">Gehry</a></li>
</ul>
</li>
<li>
<a href="#">Digital</a>
<ul>
<li><a href="#">Xenakis</a></li>
<li><a href="#">Lynn</a></li>
<li><a href="#">Diller+Scofidio</a></li>
<li><a href="#">Zellner</a></li>
<li><a href="#">Hadid</a></li>
</ul>
</li>
</ul>
Начнём с браузеров, поддерживающих CSS 2.1. Таблица стилей для них будет иметь следующий вид:
height: 2em;
}
#menu, #menu ul, #menu ul li {
list-style: none;
display: block;
margin: 0;
padding: 0;
}
#menu li {
float: left;
height: 2em;
line-height: 2em;
position: relative;
}
#menu li a {
display: block;
border: 1px solid red;
vertical-align: middle;
padding: 0 .5em;
}
#menu li ul {
display: none;
position: absolute;
top: 2em;
left: 0;
margin: 1px 0 0 0;
padding: 0;
background: #FFF;
width: 100px;
}
#menu li:hover ul {
display: block;
}
#menu li ul li {
float: none;
width: 100%;
}
#menu li ul li a {
border: 1px solid red;
vertical-align: middle;
padding: 0 .5em;
}
Вся магия содержится в двух правилах:
display: none;
position: absolute;
top: 2em;
left: 0;
margin: 1px 0 0 0;
padding: 0;
background: #FFF;
width: 100px;
}
#menu li:hover ul {
display: block;
}
Первое задаёт размеры/позицию выпадающего меню; позиция вычисляется относительно родительского элемента <li>. Второе же правило показывает выпадающее меню при наведении курсора мыши на заголовок. Ничего сложного.
Презентационные стили:
margin-left: -1px;
}
#menu li ul li + li {
margin-top: -1px;
}
#menu li a {
outline: 0;
text-decoration: none;
}
#menu li:hover a, #menu li a:hover a {
background: #EEE;
}
#menu li li a, #menu li:hover li a, #menu li a:hover li a {
background: #FFF;
}
#menu li ul li:hover a, #menu li ul li a:hover {
background: #EAFBFC;
}
Первые два правила позиционируют элементы списков так, чтобы border-right (border-bottom) предыдущего элемента совпадал с border-left (border-top) следующего.
Теперь переходим к IE6. В нём не работает второе магическое правило (#menu li:hover ul), так как IE6 воспринимает :hover только на элементах <a>.
Первая мысль — закрывать для IE6 <a> не до списка, а после. Мысль хорошая, но просмотр дерева в IE Developer Toolbar показал, что IE как-то "криво" понимает код (в принципе, здесь Ишак прав: невалидный код каждый волен понимать так, как может). Следовательно, надо список "обернуть" во что-нибудь, но так, чтобы <a> нормально работал. И совершенно случайно
я вспомнил один случай, когда разгребал одну ужасную табличную вёрстку (а уровень вложенности таблиц переваливал там за 16) и открытый тэг <a> превратил всю таблицу в сплошную гиперссылку. Чем чёрт не шутит, я решил попробовать.
Код стал таким:
<a href="#">Renaissance<!--[if IE 7]><!--></a><!--<![endif]-->
<!--[if lte IE 6]><table><tbody><tr><td><![endif]-->
<ul>
<li><a href="#">Brunelleschi</a></li>
<li><a href="#">Alberti</a></li>
<li><a href="#">Palladio</a></li>
<li><a href="#">Michelangelo</a></li>
<li><a href="#">Bramante</a></li>
</ul>
<!--[if lte IE 6]></td></tr></tbody></table></a><![endif]-->
</li>
Получилось! Ишак нормально распарсил код и сгенерировал нормальное дерево:
![]()
Теперь нужно немного поколдовать, чтобы заставить всё работать как надо.
Первое, что приходит в голову — это такие вот стили:
display: block;
}
* html #menu li a:hover {
position: static;
}
* html #menu li a:hover table {
display: block;
}
* html #menu table {
position: absolute;
border-collapse: collapse;
top: 0;
left: -1px;
display: none;
}
Иными словами, мы всю магию перенесли на уровень выше (так как теперь у нас <ul> обёрнут <table>). Правило position: static в * html #menu li a:hover — это вуду, без этого не работает
(как вариант, можно задать background с цветом, отличным от transparent).
И тут начинаются проблемы. Я, конечно, всегда подозревал, что IE написан очень криво, но чтобы так криво… После нескольких наведений на меню получается такая картина:
То есть таблицы как бы нет (display: none), но место в потоке она занимает, и при этом хотя текста дочерних элементов не видно, но border остался. Нет таблицы, и в то же время есть. Чудеса.
От таких чудес невольно опускаются руки. Потратив пару часов на эксперименты, я чудом нашел рабочую комбинацию: вместо display: none/block нужно использовать visibility: visible/hidden. Не знаю, почему, но оно работает. Но всё же мне интересно, что курили разработчики, писавшие Ишака?
Страница с рабочим кросс-браузерным меню находится здесь. Никакого JavaScript, только CSS!
Update: еще одна версия вертикального меню.

[...] Ars Longa, Vita Brevis Март 23, 2008 « Кросс-браузерное одноуровневое вертикальное меню без … [...]
[...] тэг <object> (нечто подобное было сделано в статье “Кросс-браузерное одноуровневое вертикальное меню без JavaScript”) <!–[if gt IE 8]><!–> <object [...]
[...] браузерам (об этом можно прочитать в статье “Кросс-браузерное одноуровневое вертикальное меню без …”), поэтому я сразу привожу разметку, которая подойдёт [...]
спасибо, в закладки
хмм, или кнопка закладок работает не так как я ожидал (никогда ее не использовал), или она просто не работает
ни урл, ни тайтл, ни описание не передаются по кнопке
bersy, честно говоря, я тоже никогда этой кнопкой не пользовался и, как следствие, не обращал внимание.
Я поправил код плагина, теперь вроде как работает (хотя странно, я использовал тот же код, что и все остальные). Приношу извинения за неудобства.
да, теперь порядок
раньше пользовался пару раз только addthis.com, там все было ОК, правдо наверное это для рунета не очень удобно
еще мои куки не запомнились, нужно заново вводить ник и мэил, мне в общем не трудно, но не все такие терпеливые
Bersy, а Вы зарегистрируйтесь
Тогда система вас запомнит.
В любом случае, я поищу плагины, позволяющие запоминать информацию, введённую пользователем.
Здравствуйте.
Я решил передрать Ваше меню и исследовать его попутно, но у меня ничего не выходит(( Особенно в IE6
Вот код который я наодил/передрал из вашей статьи:
height: 2em;
}
#menu, #menu ul, #menu ul li {
list-style: none;
display: block;
margin: 0;
padding: 0;
}
#menu li {
float: left;
height: 2em;
line-height: 2em;
position: relative;
}
#menu li a {
display: block;
border: 1px solid red;
vertical-align: middle;
padding: 0 .5em;
}
#menu li ul {
display: none;
position: absolute;
top: 2em;
left: 0;
margin: 1px 0 0 0;
padding: 0;
background: #FFF;
width: 100px;
}
#menu li:hover ul {
display: block;
}
#menu li ul li {
float: none;
width: 100%;
}
#menu li ul li a {
border: 1px solid red;
vertical-align: middle;
padding: 0 .5em;
}
#menu > li + li {
margin-left: -1px;
}
#menu li ul li + li {
margin-top: -1px;
}
#menu li a {
outline: 0;
text-decoration: none;
}
#menu li:hover a, #menu li a:hover a {
background: #EEE;
}
#menu li li a, #menu li:hover li a, #menu li a:hover li a {
background: #FFF;
}
#menu li ul li:hover a, #menu li ul li a:hover {
background: #EAFBFC;
}
* html #menu li ul {
display: block;
}
* html #menu li a:hover {
position: static;
}
* html #menu li a:hover table {
display: block;
}
* html #menu table {
position: absolute;
border-collapse: collapse;
top: 0;
left: -1px;
display: none;
}
<!--[if lte IE 6]><![endif]-->
<a href="#" rel="nofollow">Brunelleschi</a>
<a href="#" rel="nofollow">Alberti</a>
<a href="#" rel="nofollow">Palladio</a>
<a href="#" rel="nofollow">Michelangelo</a>
<a href="#" rel="nofollow">Bramante</a>
<!--[if lte IE 6]></a><![endif]-->
<a href="#" rel="nofollow">Art Nouveau<!--[if IE 7]><!--></a><!--
<!--[if lte IE 6]><![endif]-->
<a href="#" rel="nofollow">Mackintosh</a>
<a href="#" rel="nofollow">Guimard</a>
<a href="#" rel="nofollow">Horta</a>
<a href="#" rel="nofollow">van de Velde</a>
<!--[if lte IE 6]></a><![endif]-->
<a href="#" rel="nofollow">Modern<!--[if IE 7]><!--></a><!--
<!--[if lte IE 6]><![endif]-->
<a href="#" rel="nofollow">Sullivan</a>
<a href="#" rel="nofollow">Le Corbusier</a>
<a href="#" rel="nofollow">Mies</a>
<a href="#" rel="nofollow">Gropius</a>
<a href="#" rel="nofollow">Yamasaki</a>
<!--[if lte IE 6]></a><![endif]-->
<a href="#" rel="nofollow">Postmodern<!--[if IE 7]><!--></a><!--
<!--[if lte IE 6]><![endif]-->
<a href="#" rel="nofollow">Venturi</a>
<a href="#" rel="nofollow">Eisenman</a>
<a href="#" rel="nofollow">Stern</a>
<a href="#" rel="nofollow">Graves</a>
<a href="#" rel="nofollow">Gehry</a>
<!--[if lte IE 6]></a><![endif]-->
<a href="#" rel="nofollow">Digital<!--[if IE 7]><!--></a><!--
<!--[if lte IE 6]><![endif]-->
<a href="#" rel="nofollow">Xenakis</a>
<a href="#" rel="nofollow">Lynn</a>
<a href="#" rel="nofollow">Diller+Scofidio</a>
<a href="#" rel="nofollow">Zellner</a>
<a href="#" rel="nofollow">Hadid</a>
<!--[if lte IE 6]></a><![endif]-->
Прошу прощения за беспокоство. Буду очень рад если скажете что я сделал не так.
Leo, всё очень просто: во-первых, Вы потеряли список, который передаёт структуру меню
Во-вторых, с комментариями что-то явно не так (при включённой подсветке синтаксиса это ясно видно).
Сейчас я поправлю Ваш код и выложу его.
Leo, вот исправленная версия: http://static2.sjinks.org.ua:8080/test/menu/leo.html