Горизонтальное выпадающее меню

08.10.2009 12:36
artin

Данная статья предназначена для новичков в CSS, желающих научиться делать красивые меню без использования JavaScript, сохраняя при этом чистый код HTML-страниц. Я постараюсь объяснить каждое применяемое правило, объясняя промежуточные результаты. "Потрогать" меню можно здесь:

 

Начнем мы с семантической разметки. Наше меню, содержащее сразу три уровня — это простой ненумерованный список, а каждое подменю в нем — это вложенный список. Такой подход имеет ряд преимуществ:

  1. Код вашего меню занимает мало места
  2. Меню становится доступным для поисковиков и альтернативных клиентов
  3. Вы разделяете содержимое и представление, контролируя оформление только при помощи CSS

В HTML это выглядит примерно так:

<ul id="nav">
<li><a href="#null">Домой</a></li>
<li><a href="#null">Каталог</a>
<ul>
<li><a href="#null">Вся продукция</a>
<ul>
<li><a href="#null">По дате</a></li>
<li><a href="#null">Производители</a></li>
<li><a href="#null">Другое</a></li>
</ul>
</li>
</ul>
</li>
  ...
</ul>

Пусть вас не пугает вложенность списков. Главное — следить за правильностью открытия/закрытия тегов. В частности, каждый вложенный тег <ul> должен содержаться внутри тега <li>.

 

Вот что мы пока имеем: шаг 1.

 

Итак, немного стиля. Добавим несколько кусочков CSS в наш код. Создаем файл "style.css" и копируем туда всё ,что мы относим к CSS.

#nav, #nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid #000;
  background: #515151;
  float: left;
  width: 100%;
}
#nav li {
  float: left;
  position: relative;
  background-color: #003366;
  back\\ground: none;
}
#nav li ul {
  display: none;
  position: absolute;
  background-color: #003366;
  padding: 8px 0;
  width: 138px;
}

Этими тремя правилами мы сделали следующие вещи:

  1. Убрали буллеты из нашего списка — list-style:none
  2. Обнулили отступы padding и margin у элементов меню
  3. Украсили меню границей (border) и задним фоном (background). Свойство back\\ground:none служит для задания прозрачного фона во всех браузерах кроме IE 5. Обо всём этом позже
  4. Заставили каждый элемент списка <li>, встать на одну линию при помощи правила float:left
  5. Скрыли подменю 2-го и 3-го уровня, указав display:none

Когда блочные элементы имеют свойство float, они становятся «плавающими». Это позволяет выстраивать их в одну линию друг за другом. Так как все элементы списка <ul id="nav"> теперь «плавающие», то сам список «схлопывается». Это происходит из-за невозможности вычислить реальную высоту элемента, который содержит другие «плавающие» элементы.

Для борьбы с этой напастью существует несколько способов, однако они могут не работать в IE 7. Поэтому здесь лучше использовать метод  присвоения свойства float:left самому контейнеру. Это избавляет нас от «схлопывания» списка, но заставляет нижележащие элементы обтекать меню справа. Именно поэтому мы указываем ширину для всего меню width:100% — чтобы справа просто не оставалось места. Кроме того, мы могли указать свойство clear:both для элемента, следующего сразу за меню. Это заставило бы его опуститься ниже всех «плавающих» элементов.

Выражение position:absolute служит для абсолютного позиционирования подменю относительно элемента <li> верхнего уровня.

Когда мы имеем родительский элемент, позиционированный «относительно» (т. е. имеющий position:relative), все позиционированные абсолютно элементы, содержащиеся в нем, будут позиционироваться относительно родительского элемента, а не относительно всей страницы (верхнего левого угла браузера).

 

Что мы получили: шаг 2.

 

Добавим немного оформления нашим ссылкам:

#nav a {
  color: #fff;
  text-decoration: none;
  display: block;
  width: 120px;
  padding: 4px 10px;
  background-color: #003366 repeat-y right;
}
#nav a:hover {
  color: #000;
   background-color: #0033FF;
}
#nav li:hover {
  background-color: #333333;
}

Первым правилом мы оформили ссылки (цвет и дизайн вы в праве выбрать сами)

  1. Каждому элементу <a> мы присвоили свойство display:block, что дало нашим ссылкам ширину и высоту
  2. Убрали подчеркивание при помощи text-decoration:none
  3. Задали ширину каждой ссылки width:120 пикселей (справедливости ради, надо сказать, что реальная ширина равна 140 (120 + 10 + 10) пикселям, так как в нее включаются и отступы padding:4px(сверху и снизу) 10px(справа и слева))

Задание ширины является необходимостью при использовании свойства float для всех элементов кроме элемента <img>.

Селектор #nav a:hover срабатывает в том случае, когда мы подводим курсор к ссылке, а #nav li:hover — когда подводим его к элементу списка. Второй случай понадобиться нам для того, чтобы в меню оставался «след» наших перемещений (мы это увидим далее).

 

Промежуточный результат: шаг 3.

 

#nav li li a {
  width: 118px;
  background: none;
}
#nav li:hover ul {
  display: block;
}

Вся магия выпадающего меню заключена в строке display:block для #nav li:hover ul. Именно она заставляет подменю «появиться» при подводе курсора к ссылке, сменяя ранее установленный режим display:none:

#nav li:hover li ul {
  display: none;
  width: 138px;
  top: -9px;
  left: 133px;
}
#nav li:hover li:hover ul {
  display: block;
}

Ширина нашего подменю равна 138 пикселям из-за того, что мы вычитаем 2 пикселя от границ с каждой стороны: 140 – 1 – 1 = 138 пикселей.

Селектор #nav li:hover li ul оказывает влияние на подменю 3-го уровня. Мы его сдвигаем влево на ширину 133 пикселя (величина чисто эмпирическая), а также немного вверх (чтобы оно оказалось на одном уровне с активной ссылкой). Теперь, при наведении мышки, наше подменю будет выскакивать справа от ссылки.

 

Выпадающее меню (пока не для IE): шаг 4.

 

Фактор IE

Жизнь многих веб-разработчиков стала бы проще если бы не было Internet Explorer. Ситуация вроде как улучшилась с выходом седьмой версии. Но в ранних версиях IE, которые использует небольшой процент пользователей, псевдокласс hover поддерживается только для элемента <a>. В нашем же случае это требуется для элемента списка <li>. Поэтому мы будем использовать простую функцию JavaScript для нужной нам реакции на подведение мышки. Итак, создаем файл, "vipad.js" и копируем туда ниже приведенный скрипт.

  jsHover = function() {
    var hEls = document.getElementById("nav").getElementsByTagName("LI");
    for (var i=0, len=hEls.length; i<len; i++) {
      hEls[i].onmouseover=function() { 
         this.className+=" jshover"; }
      hEls[i].onmouseout=function() { 
         this.className= this.className.replace("jshover", ""); }
    }
  }
  if (window.attachEvent && navigator.userAgent.indexOf ("Opera") ==-1)
       window.attachEvent("onload", jsHover);

Это позволяет «прицепить» класс jshover к любому элементу <li>, над которым проходит курсор. Эта функция работает только в Internet Explorer — для других браузеров она просто не нужна.

Теперь, чтобы меню заработало в IE, добавим к четырем уже существующим правилам по дополнительному селектору li.jshover:

#nav li:hover,
#nav li.jshover {
  ...
}
#nav li:hover ul,
#nav li.jshover ul {
  ...
}
#nav li:hover li ul,
#nav li.jshover li ul {
  ...
}
#nav li:hover li:hover ul,
#nav li.jshover li.jshover ul {
  ...
}

 

Теперь можете смотреть и в IE: шаг 5, финальный.

 

Дополнительная информация

В качестве фона для подменю используется цветной фон, но можно использовать полупрозрачный PNG-файл. IE 6 не поддерживает полупрозрачность, но вы можете это исправить. Если использовать полупрозрачные картинки, цвет фона придеться убрать. Это приведет к тому, что при отключенных картинках буквы подменю становятся не видны. Выход один: задать цвет фона для #nav li, потеряв при этом полупрозрачность.

Я использую хак back\\ground:none;, чтобы принудительно задать цвет меню для IE 5. Если этого не сделать, то в этом браузере фон не отображается. Наверное это можно исправить как-то по-другому, но у меня нет желания разбираться со всеми его причудами.

Вот и всё, что я хотел представить Вам на соответствующую тему. Скопируйте выше приведенный код или скачайте его здесь. Затем вставьте код, представленный ниже, на страницы, где будет меню, между тегами <HEAD> и </HEAD>

<script type="text/javascript" src="/vipad.js"></script>
<link  rel="StyleSheet" type="text/css" href="/style.css"/>

Обязательно пропишите пути к файлам ''vipad.js'' и ''style.css'', чтобы они корректно подключились.

Если хотите иметь горизонтальное выпадающее меню покруче, чем приведенное выше, с поддержкой Javascript, можете также скачать его, без проблем, но перед этим почитайте о том как установить это меню и посмотрите как оно работает.

В общем, делайте по аналогии с тем, что уже есть, и у Вас все получится :)

 

( 4 Голосов ) 
  • wanderlog

    2010-02-05 11:37:22

    Спасибо, постараюсь применить!

  • night_madness

    2010-03-04 09:26:34

    СПАСИБО РАБОТАЕТ!!!! СУПЕР!!! Взял шаблон с Javascript.

  • х3как

    2010-03-25 23:32:05

    спасибо большое

  • reper

    2010-07-22 17:59:40

    Хорошо!!! Терь я знаю как работает меню. Полезная статья, положу её в закладки как руководство

  • Roleft

    2010-08-05 07:41:36

    Приличное меню, главное работает на html и css. Всё простенько со вкусом. Сейчас многие сайты используют такие меню!

  • Самуил

    2010-08-05 07:53:02

    Прикольная менюшка!

  • runi

    2010-10-25 07:11:02

    Это как шаблон всех горизонтальных выпадающих меню. Если нужно его модифицировать, необходимо добавить библиотеку jQuery и пару строк javascript.

  • PSYHORROR

    2010-12-27 19:42:27

    Я в зажницу послал это CSS и скачал js меню:D

  • Роман

    2011-02-23 11:22:03

    Спасибо большое! Моё почтение.

  • pl

    2011-04-05 11:49:36

    Пригодится.
    Но вот выделять тот пункт меню в котором находишься к сожалению тут не описано.
    для кого эт интересно я нашел тут
    http://phpcss.ru/

  • incognito

    2011-06-08 11:06:32

    Админ, подскажи пожалуйста почему это меню(синее) не отображается в IE(любой версии)??
    Вроде и всё сделал правильно. :)
    Вместо меню в IE прямоугольник, в 2-3 раза выше чем высота меню в любом другом браузере))

  • Ирина

    2011-07-09 12:54:41

    Подскажите пожалуйста, почему вкладки меню не отображаются в IE( даже 8 серии). У меня просто самая первая линия появляется и когда наводишь на пункты меню, то ничего не появляется.

  • Сергей

    2011-11-22 17:33:27

    Спасибо немного доработал и сделал посвоему!

  • Александр

    2011-12-23 10:14:45

    Спасибо! А как поменять цвет шрифта?

  • admin

    2011-12-24 07:12:49

    Александр, цвет шрифта можно поменять в файле css. Селектор #nav a свойство color

  • Виталий

    2012-04-15 00:48:11

    Подскажите пожалуйста, как сделать, чтоб у меня это меню вверх выпадало? И шаг увеличить, между пунктами...

  • admin

    2012-04-15 18:23:24

    Виталий, через CSS наверное. Разберитесь в том как работает меню, кто за что отвечает, поэкспериментируйте, для начала попробуйте в селекторе #nav li ul {} добавить свойство top:-44px; (это чтобы меню вверх выпадало)

  • Вииталий

    2012-04-15 23:30:19

    Дело в том, что свойство top в данном селекторе понимает все пункты меню на одинаковую высоту, а у меня в каждой строке разное количество водменю, и меню снизу ограниченной рамкой страницы, т.е мне нельзя, чтобы вниз сильно выходили пункты. Часть текста:
    <table border="0" cellspacing="0" cellpadding="0" width="950">
    <!-- таблица дополнительной навигации -->
    <tr> <td width="31"></td>
    <td width="111"=> <ul id="nav">
    <li><a href="#">0</a>
    <ul> <li><a href="#">1</a></li>
    <li><a href="#">2</a></li>
    <li><a href="#">3</a></li>
    <li><a href="#">4</a></li></ul></li> </ul></td>
    <td width="111"><ul id="nav">
    <li><a href="#">0</a>
    <ul> <li><a href="#">1</a></li>
    <li><a href="#">2</a></li>
    <li><a href="#">3</a></li></ul></li> </ul></td>
    <td width="111"><ul id="nav">
    <li><a href="#">0</a>
    <ul> <li><a href="#">1</a></li>
    <li><a href="#">2</a></li>
    <li><a href="#">3</a></li>
    <li><a href="#">4</a></li>
    <li><a href="#">5</a></li>
    <li><a href="#">6</a></li></ul></li> </ul></td>
    <td width="111"><ul id="nav">
    <li><a href="#">0</a>
    <ul> <li><a href="#">1</a></li>
    <li><a href="#">2</a></li>
    <li><a href="#">3</a></li>
    <li><a href="#">4</a></li>
    <li><a href="#">5</a></li>
    <li><a href="#">6</a></li>
    <li><a href="#">7</a></li></ul></li> </ul></td>
    <td width="111"><ul id="nav">
    <li><a href="#">0</a>
    <ul> <li><a href="#">1</a></li>
    <li><a href="#">2</a></li>
    <li><a href="#">3</a></li></ul></li> </ul></td>
    <td width="111"><ul id="nav">
    <li><a href="#">0</a>
    <ul> <li><a href="#">1</a></li>
    <li><a href="#">2</a></li>
    <li><a href="#">3</a></li>
    <li><a href="#">4</a></li>
    <li><a href="#">5</a></li>
    <li><a href="#">6</a></li>
    <li><a href="#">7</a></li></ul></li> </ul></td>
    <td width="111"><ul id="nav">
    <li><a href="#">0</a>
    <ul> <li><a href="#">1</a></li>
    <li><a href="#">2</a></li>
    <li><a href="#">3</a></li>
    <li><a href="#">4</a></li>
    <li><a href="#">5</a></li>
    <li><a href="#">6</a></li></ul></li> </ul></td>
    <td width="111"><ul id="nav">
    <li><a href="#">0</a>
    <ul> <li><a href="#">1</a></li>
    <li><a href="#">2</a></li>
    <li><a href="#">3</a></li>
    <li><a href="#">4</a></li></ul></li> </ul></td>
    <td width="31"></td> </tr>
    </table>

  • admin

    2012-04-16 12:52:53

    Вииталий, Попробуйте каждому пункту меню присвоить уникальный класс. Например,
    <li class="home">1<li>
    <li class="catalog">2 <ul>...</ul><li>
    <li class="download">3 <ul>...</ul><li>
    И присвоить каждому определённое значение top
    #nav li.catalog ul {top:-144px;}
    #nav li.download ul {top:-80px;}

Captcha
Обновить