Создание раскрывающихся меню…
На предыдущем уроке мы создали горизонтальное меню навигации на базе списков. Теперь возведем наше горизонтальное меню на следующий уровень - добавим раскрывающиеся меню.
Раскрывающиеся меню на базе CSS не будут работать в браузере Internet Explorer для Mac. Тем не менее, я покажу, как использовать CSS и создать работающее меню и для этого браузера.
На этом уроке мы предположим, что каждому пункту нашего
горизонтального меню соответствует определенная страница. Нам просто
потребуется указать URL вместо символов # в теге href каждой ссылки.
|
Разметка раскрывающихся меню… |
Для разметки раскрывающихся меню нам потребуется вложить список раскрывающихся вариантов в пункт списка горизонтального меню.
На (рис. 1) показано готовое меню, чтобы было понятно, что мы пытаемся создать.
|
(рис. 1) Вот наше готовое раскрывающиеся(выпадающее) меню.
|
Ниже приведен полный код для меню с четырьмя пунктами, каждый из которых содержит раскрывающиеся варианты.
Код: |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=windows-1251">
<title>Раскрывающееся меню | Горизонтальные компоненты навигации на базе списков</title>
<style>
<!--
body {
margin : 0;
padding : 10px;
font-family: Verdana, Tahoma, arial, geneva, Helvetica, sans-serif;
behavior: url(csshover.htc);
background-color: #ffffff;
}
/* Горизонтальное меню */
div#menunav {
width: 100%; /* задаем ширину для div */
float: left; /* добавляем список в div */
border-top: 1px solid #000000; /* рисуем линию поверх div */
border-bottom: 1px solid #000000; /* рисуем линию снизу div */
font-size: 11px; /* задаем размер шрифта */
background-color: #b3b3b3; /* фоновый цвет div */
padding: 0 0 0 30px; /* отступ ul от края контейнера */
}
div#menunav ul {
margin: 0px;
padding: 0px;
}
* html div#menunav ul {
float: left; /* заставляет ul вместить все li */
border-left: 1px solid #000000; /* добавляет левую вертикальную черту к ul */
margin-left: 15px; /* IE удваивает заданное значение */
}
div#menunav li {
float: left; /* располагаем список по горизонтали */
position: relative; /* контекст позиционирования для раскрывающегося меню с абсолютным позиционированием */
list-style-type: none; /* удаляем маркеры */
background-color: #ffebc6; /* задаем фоновый цвет элементов меню */
border-right: 1px solid #000000; /* создаем разделительные линии между элементами li */
}
div#menunav li:first-child {
border-left: 1px solid #000000; /* первая вертикальная линия в меню */
}
div#menunav a {
display: block; /* пункты вложенного меню выделяются при наведении указателя */
text-decoration: none; /* удаляем подчеркивание ссылок */
padding: 0px 10px 0px 10px; /* создаем пространство с обеих сторон текста пункта меню */
color: #006699; /* задаем цвет шрифта */
}
div#menunav a:hover {
color: #ff3333;
}
div#menunav li:hover {
background-color: #ffffff; /* задает фон пунктов списка */
}
/* Раскрывающееся меню */
div#menunav ul li ul {
margin: 0px;
position: absolute; /* размещает выпадающий ul относительно родительского li */
left: -1px; /* выравнивает раскрывающееся меню */
width: 10em;
}
div#menunav ul li ul li {
width: 100%; /* элементы списка заполняют контейнер (ul) */
border-left: 1px solid #000000; /* три стороны каждого пункта раскрывающегося меню */
border-bottom: 1px solid #000000;
border-right: 1px solid #000000;
}
div#menunav ul li ul li:first-child {
border-top: 1px solid #000000; /* верхний край раскрывающегося меню */
}
body div#menunav ul li ul {
display: none;
}
div#menunav ul li:hover ul, div#menunav ul li ul:hover {
display: block;
}
* html div#menunav ul li ul { /* добавляет верхнюю границу раскрывающегося меню для IE */
border-top: 1px solid #000000;
border-left: 0рх; /* устраняет наследование границ ul раскрывающимся меню */
}
-->
</style>
</head>
<body>
<div id="menunav">
<ul>
<li><a href="#">раздел №1</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>
<li><a href="#">раздел №2</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>
<li><a href="#">раздел №3</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>
<li><a href="#">раздел №4</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>
</div>
</body>
</html>
|
Следует отметить несколько моментов, связанных с этим кодом:
-
Ни один элемент <ul> или <li> не использует идентификаторы или классы. Единственным отличием этого списка от обычного вложенного является содержащий <div> с идентификатором menunav, позволяющий применять нужные CSS-правила к целевому списку.
-
Этот код схож с разметкой горизонтального меню из предыдущего урока,
но здесь добавлен список второго уровня, вложенный в каждый пункт меню.
Очень важно правильно вложить список - необходимо поместить весь
вложенный список от <ul> до </ul> внутрь пункта родительского списка, непосредственно перед закрывающим тегом </li> пункта списка.
-
Значения href просто заменены на #, в реальном мире необходимо заменить # фактической ссылкой на имеющуюся страницу.
Давайте начнем с простых вещей. Вместо того чтобы сразу работать с
полным кодом разметки, приведенным ранее, начнем с горизонтального меню,
в котором список второго уровня добавлен только к первому пункту. Затем
вы по аналогии сможете добавить все вложенные меню для остальных
пунктов.
Вот код: |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=windows-1251">
<title>Раскрывающееся меню | Горизонтальные компоненты навигации на базе списков</title>
<style>
<!--
body {
margin : 0;
padding : 10px;
font-family: Verdana, Tahoma, arial, geneva, Helvetica, sans-serif;
behavior: url(csshover.htc);
background-color: #ffffff;
}
div#menunav {
width: 100%; /* задаем ширину для div */
float: left; /* добавляем список в div */
border-top: 1px solid #000000; /* рисуем линию поверх div */
border-bottom: 1px solid #000000; /* рисуем линию снизу div */
font-size: 11px; /* задаем размер шрифта */
background-color: #b3b3b3; /* фоновый цвет div */
padding: 0 0 0 30px; /* отступ ul от края контейнера */
}
div#menunav ul {
margin: 0px;
padding: 0px;
}
* html div#menunav ul {
float: left; /* заставляет ul вместить все li */
border-left: 1px solid #000000; /* добавляет левую вертикальную черту к ul */
margin-left: 15px; /* IE удваивает заданное значение */
}
* html div#menunav a {
display: block; /* IE 5 и 5.5 принимает заданный отступ */
}
div#menunav li {
float: left; /* располагаем список по горизонтали */
list-style-type: none; /* удаляем маркеры */
background-color: #ffebc6; /* задаем фоновый цвет элементов меню */
border-right: 1px solid #000000; /* создаем разделительные линии между элементами li */
}
div#menunav li:first-child {
border-left: 1px solid #000000; /* первая вертикальная линия в меню */
}
div#menunav a {
text-decoration: none; /* удаляем подчеркивание ссылок */
padding: 0px 10px 0px 10px; /* создаем пространство с обеих сторон текста пункта меню */
color: #006699; /* задаем цвет шрифта */
}
div#menunav a:hover {
color: #ff3333;
}
div#menunav li:hover {
background-color: #ffffff; /* задает фон пунктов списка */
}
-->
</style>
</head>
<body>
<div id="menunav">
<ul>
<li><a href="#">раздел №1</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>
<li><a href="#">раздел №2</a></li>
<li><a href="#">раздел №3</a></li>
<li><a href="#">раздел №4</a></li>
</ul>
</div>
</body>
</html>
|
Давайте теперь взглянем на (рис. 2).
|
(рис. 2) Подменю пока не раскрывается, а наследует стиль родительского списка.
|
Необходимо добавить стили к раскрывающемуся меню, чтобы привести его в
норму. Вместо добавления класса или идентификатора к подменю, мы можем
использовать селектор специально для этого списка.
Например, селектор ul li ul {...CSS правила...} предназначается только для элемента <ul>, содержащегося внутри элемента <li> родительского списка - как раз то, что нам нужно.
Как видно в следующем фрагменте кода, всего три простых объявления CSS помогут достичь нужного результата.
Код: |
/* Раскрывающееся меню */
div#menunav ul li ul {
margin: 0px; /* запрещает наследование временного поля ul из горизонтального меню */
width: 10em; /* задает ширину меню - в сочетании с шириной И в 100% дает нам вертикальное меню */
}
div#menunav ul li ul li {
width: 100%; /* заполняет контейнер списка (ul) элементами списка */
}
|
Результат показан на (рис. 3).
|
(рис. 3) Меню начинает обретать форму.
|
Если мы зададим ширину <ul> вложенного списка и затем заставим элементы <li>
внутри него занимать 100% ширины, они образуют вертикальное меню. Без
этого короткие слова будут располагаться на одной строке, и ширина
каждого пункта будет разной.
Теперь необходимо правильно расположить раскрывающееся меню относительно родительского. Для этого зададим дочернему меню абсолютное позиционирование, а родительскому - относительное. В то же время мы применим стили для создания границ раскрывающегося меню.
Вот необходимый код: |
/* Горизонтальное меню */
div#menunav li {
float: left; /* располагаем список по горизонтали */
position: relative; /* контекст позиционирования для раскрывающегося меню с абсолютным позиционированием */
list-style-type: none; /* удаляем маркеры */
background-color: #ffebc6; /* задаем фоновый цвет элементов меню */
border-right: 1px solid #000000; /* создаем разделительные линии между элементами li */
}
/* Раскрывающееся меню */
div#menunav ul li ul {
margin: 0px;
position: absolute; /* размещает выпадающий ul относительно родительского li */
left: -1px; /* выравнивает раскрывающееся меню */
width: 10em;
}
div#menunav ul li ul li {
width: 100%; /* элементы списка заполняют контейнер (ul) */
border-left: 1px solid #000000; /* три стороны каждого пункта раскрывающегося меню */
border-bottom: 1px solid #000000;
border-right: 1px solid #000000;
}
div#menunav ul li ul li:first-child {
border-top: 1px solid #000000; /* верхний край раскрывающегося меню */
}
|
Теперь давайте взглянем на (рис. 4).
|
(рис. 4) Наше раскрывающееся меню почти готово.
|
Обратите внимание, что раскрывающееся меню на 1(один)
пиксел смещено вправо, так как оно выравнивается по элементу списка, а
не по его границе, но так как контекстом позиционирования теперь
является родительский элемент, достаточно задать небольшой сдвиг, чтобы
поставить меню на место:
Код: |
/* Раскрывающееся меню */
div#menunav ul li ul {
margin: 0px;
position: absolute; /* размещает выпадающий ul относительно родительского li */
left: -1px; /* выравнивает раскрывающееся меню */
width: 10em;
}
|
Посмотрите на (рис. 5).
|
(рис. 5) Раскрывающееся меню размещено точно под родительским пунктом.
|
За исключением таких проблем с отображением меню в Internet Explorer, как отсутствующая верхняя граница и наследуемая от предыдущего трюка левая граница <ul>,
раскрывающееся меню готово и мы можем обратить внимание на то, как
сделать его видимым только при наведении указателя мыши на родительский
пункт меню.
В горизонтальном меню при наведении указателя мыши на пункт его
внешний вид изменяется. Для раскрывающегося меню нужно, чтобы в этом
случае открывалось вложенное меню. Достичь этой цели нам поможет
исключительно простой селектор.
Вначале, спрячем раскрывающееся меню, когда указатель мыши на него не наведен:
Код: |
/* Раскрывающееся меню */
body div#menunav ul li ul {
display: none;
}
|
Это свойство наследуемо, поэтому все элементы списка вложенного меню
также будут невидны. Затем мы заставим меню появляться при наведении
указателя мыши:
Код: |
/* Раскрывающееся меню */
div#menunav ul li:hover ul {
display:block;
}
|
Этот селектор указывает, что раскрывающийся список <ul> должен отображаться только тогда, когда на родительский пункт списка <li> наведен указатель мыши.
Однако мы хотим, чтобы меню оставалось видимым и когда мы смещаем
указатель с пункта родительского меню и двигаем им по раскрывшемуся
меню.
Для этого сгруппируем второй селектор с объявлением display:block следующим образом:
Код: |
/* Раскрывающееся меню */
div#menunav ul li:hover ul, div#menunav ul li ul:hover {
display: block;
}
|
Теперь меню отображается при наведении на родительский пункт и на само вложенное меню (рис. 6).
|
(рис. 6) При наведении на родительский пункт появляется дочернее меню, позволяющее сделать выбор.
|
Теперь добавим трюк для Internet Explorer:
Код: |
/* Раскрывающееся меню */
* html div#menunav ul li ul { /* добавляет верхнюю границу раскрывающегося меню для IE */
border-top: 1px solid #000000;
border-left: 0рх; /* устраняет наследование границ ul раскрывающимся меню */
}
|
Теперь Internet Explorer отображает раскрывающееся
меню так же, как и другие браузеры. Возможно, вы обратили внимание, что
текст этого меню выделяется только при наведении указателя на сам текст.
Для устранения этого недостатка нам потребуется сделать блочными элементами все родительские ссылки:
Код: |
/* Горизонтальное меню */
div#menunav a {
display: block; /* пункты вложенного меню выделяются при наведении указателя */
text-decoration: none; /* удаляем подчеркивание ссылок */
padding: 0px 10px 0px 10px; /* создаем пространство с обеих сторон текста пункта меню */
color: #006699; /* задаем цвет шрифта */
}
|
Наше меню приняло вид, представленный на (рис. 7).
|
(рис. 7) Теперь ссылки выделяются при наведении указателя мыши на пункт меню.
|
Сделав это, мы можем удалить трюк для Internet Explorer из примера с горизонтальным меню, делающий ссылки меню блочными. Новый код подходит для всех браузеров.
Нужно удалить из кода строку:
Код: |
/* Горизонтальное меню */
* html div#menunav a {
display: block; /* IE 5 и 5.5 принимает заданный отступ */
}
|
Итак, в нашем распоряжении есть раскрывающееся меню, созданное «с нуля» и без использования JavaScript.
Если текст в пункте меню переносится на вторую строку, он отображается также с отступом и не касается границы ячейки.