Нередко сейчас применяются выпадающие списки, которые позволяют уместить в пределах одного меню всю навигационную структуру сайта не в ущерб дизайну и общему целостному восприятию информации. Давайте попробуем к нашему тестовому сайту Cofemir.ru прикрутить такое меню.

Многоуровневое выпадающее меню CSS. Изучаем позиционирование

Обновляем структуру сайта

Самой большой ошибкой при создании сайта является отсутствие технического задания, где было бы прописано для разработчика все, что касается функционала, внешнего вида и структуры сайта. Именно отсутствие технического задания влечет за собой необоснованные претензии со стороны заказчика, увеличенные сроки сдачи работ, многочисленные переделки и доработки.

И нам, чтобы разработать сайт «Мир кофе» нужно было бы составить ТЗ, но мы делаем все на лету. Однако давайте представим структуру выпадающего меню.

Сейчас эта структура выглядит так:

  • Главная страница
  • Статьи
  • Контакты
  • Ссылки
  • FAQ

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

  • Главная страница (без изменений)
  • Статьи
    • Исторические факты
    • Виды кофе
    • Рецепты
  • Контакты
    • Руководство
    • Магазины
  • Ссылки
    • Наши партнеры
    • Мы в социальных сетях
    • Другие кофе-миры
  • FAQ
    • Вопросы по сайту
    • Вопросы по рецептам
    • Другие вопросы

Уже сейчас наше меню сильно расширилось и дизайнеру уже стоит задуматься о стиле выпадающих списков, а разработчику о способе реализации. Дизайну сложно научить в нашем формате, можно лишь дать несколько советов и мы опустим эту сторону медали и обернемся к разработке (будем считать, что макет дизайна нам уже предоставили). Стоило бы упомянуть и сеошника (занимается оптимизацией сайта для увеличения выдачи в поисковых системах), но так как эти люди во многом могут помешать как разработчику так и дизайнеру своими приблудами заморочками, то мы сделаем вид, что пока не готовы заниматься оптимизацией, хотя сеошник обязан принять участие в разработке технического задания.

Способы реализации выпадающего меню

  1. При помощи таблиц стилей (CSS)
  2. При помощи скриптов (JavaScripts, Flashи др.)

Сценарии очень нужны и незаменимы при создании сайтов любой сложности. Если честно, я не представляю себе сайт без скриптов. Однако, на стадии обучения скрипты стоят в конце очереди и мы будем последовательны, ведь с таблицами стилей мы уже знакомились на протяжении нескольких уроков.

Реализация выпадающего меню при помощи CSS

Выпадающее меню всегда вносит дополнительную сложность в реализации проекта и доставит немало проблем при разработке сайта, который должен корректно работать с любыми размерами дисплеев. Но не знать как оно строится сейчас неприемлемо ни в каком из случаев.

Перед программированием нужно понять всю соль выпадающего меню CSS: при наведении на определенный родительский пункт меню (пункт меню, который содержит ветвление – вложенный список) будет появляться дочернее меню. То есть некоторое событие инициирует изменение стилей дочернего меню, которое до этого было скрыто, делая его отображаемым.

При использовании скриптов с событиями работать куда проще. В таблицах стилей проще всего на первом этапе привязаться к событию наведения курсора на элемент (псевдокласс :hover). Уже дальше мы научимся обрабатывать и другие события.

Теперь нам необходимо вспомнить знания предыдущих занятий. Не обойтись без знаний блочной верстки и списков.

Для начала модифицируем код главной страницы, который относится к горизонтальному меню. Сейчас оно у нас выглядит следующим образом:

<div id="top-menu">
    <ul id="tmenu">
        <li><a href="/" title="Главная"> Главная</a></li>
        <li><a href="/articles.html" title="Статьи">Статьи</a></li>
        <li><a href="/contacts.html" title="Контакты">Контакты</a></li>
        <li><a href="/links.html" title="Ссылки">Ссылки</a></li>
        <li><a href="/faq.html" title="FAQ">FAQ</a></li>
    </ul>                    
</div>   

А нам нужно привести его к структуре, которую я сочинил выше (получил в ТЗ). Применим вложенные списки

<div id="top-menu">
    <ul id="tmenu">
        <li><a href="/" title="Главная"> Главная</a></li>
        <li><a href="/articles.html" title="Статьи">Статьи</a>
            <ul>
                <li><a href="#" title="Исторические факты">Исторические факты</a></li>
                <li><a href="#" title="Виды кофе">Виды кофе</a></li>
                <li><a href="#" title="Рецепты">Рецепты</a></li>
            </ul>
    </ul>
        </li>
        <li><a href="/contacts.html" title="Контакты">Контакты</a>
            <ul>
                <li><a href="#" title="Руководство">Руководство</a></li>
                <li><a href="#" title="Магазины">Магазины</a></li>
            </ul>
        </li>
        <li><a href="/links.html" title="Ссылки">Ссылки</a>
            <ul>
                <li><a href="#" title="Наши партнеры">Наши партнеры</a></li>
                <li><a href="#" title="Мы в социальных сетях">Мы в социальных сетях</a></li>
                <li><a href="#" title="Другие кофе-миры">Другие кофе-миры</a></li>
            </ul>
        </li>
        <li><a href="/faq.html" title="FAQ">FAQ</a>
            <ul>
                <li><a href="#" title="Вопросы по сайту">Вопросы по сайту</a></li>
                <li><a href="#" title="Вопросы по рецептам">Вопросы по рецептам</a></li>
                <li><a href="#" title="Другие вопросы">Другие вопросы</a></li>
            </ul>
        </li>
    </ul>                    
</div>

Многоуровневое выпадающее меню CSS

Получилось ужасно, но этого бояться не стоит и надо разбираться в причинах такого поведения – обратимся к firebug. В процессе создания сайтов у вас нередко будут появляться казусы и похлеще, а когда кода будет не один десяток тысяч строк, ориентироваться в нем станет гораздо сложнее.

Многоуровневое выпадающее меню CSS

Проблему у себя я нашел сразу – задублировал закрывающий тег </ul> и тем самым закрыл список главного меню сразу после пункта статьи.

Многоуровневое выпадающее меню CSS

Теперь уже лучше, но выглядит пока далеко от идеала, и настало время изучить новые свойства CSS и их атрибуты.

Речь идет прежде всего о свойстве display. Спрячу его описание, взятое с сайта htmlbook, под спойлер.

Нам же сейчас интересны значения свойства block и none. Применим их для отображения и скрытия блоков выпадающего меню. И в первую очередь нужно скрыть все вложенные списки. Для этого воспользуемся наследованием, то есть обратимся к вложенным элементам родительского меню.

Идентификатор родительского меню называется #tmenu, значит следующая запись позволит скрыть все сложенные ненумерованные списки внутри блока с этим идентификатором:

#tmenu li ul{     /*Для всех блоков вложенных ненумерованных списков*/
    display:none; /*Выключаем отображение*/
}

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

#tmenu li:hover ul{  /*Для всех блоков вложенных ненумерованных списков при активации*/
    display:block;   /*Включаем отображение*/
}

Мы уже проходили псевдоклассы и один из них :hover, который определяет стиль элемента при наведении на него курсора мыши, но при этом элемент еще не активирован, иными словами кнопка мыши не нажата. При разборе кода вы должны выяснить, что применится свойство (display:block;) для ненумерованного списка (ul), входящего в любой активный пункт (li:hover) списка с идентификатором #tmenu.

Примените эти изменения.

Многоуровневое выпадающее меню CSS

Выпадающее меню уже получилось, вот только оно сдвигает весь контент вниз, так как раздвигает границы родительского элемента.

Позиционирование блоков

Следующее свойство CSS, которое нам необходимо – position. При помощи этого свойства мы установим способ позиционирования элемента относительно окна браузера или других объектов на странице. Под спойлером снова описание свойства

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

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

Такого расположения нам поможет достичь значение absolute свойства position. Давайте пробовать. Добавьте свойство это свойство следующим образом модифицируя код:

#tmenu li ul{           /*Для всех блоков вложенных ненумерованных списков*/
    display:none;       /*Выключаем отображение*/
    position:absolute;  /*Позиционируем абсолютно*/
}

Многоуровневое выпадающее меню CSS

Выпадающее меню уже получилось, просто пока оно выглядит очень криво и все потому, что у нас некоторые свойства применились от родительских элементов. Измените файл стилей (только комментарии не пишите, их я сделал для вашего понимания):

#tmenu li ul li{       /*Для всех элементов вложенных списков*/
    float:none;        /*Убираем выравнивание*/
    width:200px;       /*Устанавливаем ширину элементов */
}
#tmenu li ul li a{     /*Для всех ссылок внутри элементов вложенных списков*/
    line-height:25px;  /*Устанавливаем межстрочный интервал*/
}
#tmenu li ul{           /*Для всех блоков вложенных ненумерованных списков*/
    display:none;       /*Выключаем отображение*/
    position:absolute;  /*Позиционируем абсолютно*/
    background-color:#4d2001;   /*Устанавливаем фон*/
    list-style:none;    /*Отключаем маркеры*/
    padding:0;          /*Отключаем внутренние отступы*/
}
#tmenu li:hover ul{    /*Для всех блоков вложенных ненумерованных списков при активации*/
    display:block;   /*Включаем отображение*/
}

Обратите внимание, что я добавил и что изменил. В итоге у вас должно быть меню как на скриншоте. Уже дальше его можно украшать и изменять как душе угодно, лишь бы вам нравилось.

Многоуровневое выпадающее меню

Чтобы добить тему выпадающих списков до конца, я предлагаю освоить выпадающие списки третьего уровня. Для этого структуру меню я еще слегка расширю:

  • Главная страница (без изменений)
  • Статьи
    • Исторические факты
    • Виды кофе
    • Рецепты
  • Контакты
    • Руководство
      • Генеральный директор
      • Исполнительный директор
      • Тетя Галя
    • Магазины
      • Череповец
      • Сочи
      • Мусохранск
  • Ссылки
    • Наши партнеры
    • Мы в социальных сетях
    • Другие кофе-миры
  • FAQ
    • Вопросы по сайту
    • Вопросы по рецептам
    • Другие вопросы

Следовательно, модифицируем и главное меню

<ul id="tmenu">
    <li><a href="/" title="Главная"> Главная</a></li>
    <li><a href="/articles.html" title="Статьи">Статьи</a>
        <ul>
            <li><a href="#" title="Исторические факты">Исторические факты</a></li>
            <li><a href="#" title="Виды кофе">Виды кофе</a></li>
            <li><a href="#" title="Рецепты">Рецепты</a></li>
        </ul>
    </li>
    <li><a href="/contacts.html" title="Контакты">Контакты</a>
        <ul>
            <li><a href="#" title="Руководство">Руководство</a>
                <ul>
                    <li><a href="#" title="Генеральный директор">Генеральный директор</a></li>
                    <li><a href="#" title="Исполнительный директор">Исполнительный директор</a></li>
                    <li><a href="#" title="Тетя Галя">Тетя Галя</a></li>
                </ul>
            </li>
            <li><a href="#" title="Магазины">Магазины</a>
                <ul>
                    <li><a href="#" title="Череповец">Череповец</a></li>
                    <li><a href="#" title="Сочи">Сочи</a></li>
                    <li><a href="#" title="Мусохранск">Мусохранск</a></li>
                </ul>
            </li>
        </ul>
    </li>
    <li><a href="/links.html" title="Ссылки">Ссылки</a>
        <ul>
            <li><a href="#" title="Наши партнеры">Наши партнеры</a></li>
            <li><a href="#" title="Мы в социальных сетях">Мы в социальных сетях</a></li>
            <li><a href="#" title="Другие кофе-миры">Другие кофе-миры</a></li>
        </ul>
    </li>
    <li><a href="/faq.html" title="FAQ">FAQ</a>
        <ul>
            <li><a href="#" title="Вопросы по сайту">Вопросы по сайту</a></li>
            <li><a href="#" title="Вопросы по рецептам">Вопросы по рецептам</a></li>
            <li><a href="#" title="Другие вопросы">Другие вопросы</a></li>
        </ul>
    </li>
</ul>

Если вы посмотрите сейчас на сайт, что увидите странную картину (отображаются списки разной глубины и наслаиваются друг на друга) – дело тут опять же в наследовании. Вложенные списки всех уровней открываются по одному событию. Следует их разделить. К тому же на список третьего уровня действует позиционирование, которое здесь не применимо, так как нам нужно открывать все вложенные списки третьего и ниже уровней справа от родительского элемента.

Пора познакомиться с позиционированием поближе. Есть еще два свойства, позволяющих расположить абсолютные блоки в любом месте экрана. Это свойства left и top, задающие отступы от левого и верхнего края родительского элемента.

У нас ширина блоков равна 200px и фиксирована, значит мы может на 200px сдвинуть меню вправо, прибавив с лева 200px. Добавим ниже код:

#tmenu li ul li ul,   /*Для всех блоков вложенных списков третьего и ниже уровней */
#tmenu  li:hover ul li ul{   /*А также для них же, но при условии активации списка второго уровня*/        
    display:none;       /*Выключаем отображение*/
    position:absolute;  /*Позиционируем абсолютно*/
    left:200px;     /*сдвигаем все меню вправо на 200px*/
}
#tmenu li ul li:hover ul{     /*Для всех блоков вложенных списков третьего и ниже уровней при активации*/
    display:block;   /*Включаем отображение*/
}

Многоуровневое выпадающее меню CSS

Вышло уже лучше, но вот только низко опущено меню третьего уровня. Это означает, что свойство выравнивания работает неправильно и его нужно указать.Добавим строчку с отступом:

#tmenu li ul li ul,           /*Для всех блоков вложенных списков третьего и ниже уровней */
#tmenu  li:hover ul li ul{    /*А также для них же, но при условии активации списка второго уровня*/        
    display:none;       /*Выключаем отображение*/
    position:absolute;  /*Позиционируем абсолютно*/
    left:200px;         /*сдвигаем все меню вправо на 200px*/
    top:0;              /*Прижимаем к верхнему краю род. элемента, указав 0*/
}

Однако, это не помогло, и мы зашли в тупик. Я вас в него вел намеренно, так как нужно учиться искать ошибки. Для поиска этой ошибки нужно вернуться в самые истоки к описанию значений свойства position. Там сказано, что абсолютное позиционирование будет правильно работать относительно родительского элемента, если свойство position родительского элемента задано как fixed, relative или absolute. То есть в нашем случае нужно было в самом начале указать для всех элементов списка <li> значение relative. Дополним код в свойствах элементов списка верхнего уровня.

#tmenu li{/*для всех элементов списка всех уровней*/
    float:left; /*выравнивание по левому краю*/
    width:100px;    /*ширина 100px*/
    position:relative; /*Устанавливаем тип позиционирования*/
}

Многоуровневое выпадающее меню CSS

Вот теперь все заработало как надо.

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

Как всегда, выкладываю рабочий проект для скачивания.

Добавить комментарий

Защитный код

Введите код с картинки в текстовое поле

Комментарии   

Саней
0 # Саней 27.02.2015 00:40
Как сделать так, чтобы выпадающий список выпадал не с места родительской вкладки, а начала строки. (т.е. прижать все выпадающие списки к левому краю страницы) ?
Ответить | Ответить с цитатой | Цитировать
 Алексей
+3 # Алексей 05.05.2015 21:56
Вот специально зарегился. Урок ужасный. Ничего не написано как ты спозиционировал li первого уровня по горизонтали. Я знаю как это все строится, но новички ничего не поймут. И смысл тогда таких уроков?
Ответить | Ответить с цитатой | Цитировать
Юрий Деменский
+4 # Юрий Деменский 06.05.2015 11:44
Алексей, благодарю за тщательное изучение материала этой статьи, однако, построение горизонтального меню описано в прошлой статье seoskop.ru/.../... . Уроки преемственны. Виноват, что нет ссылки на прошлую статью, исправлюсь. Все статьи оттестированы на племяннике - он справился с данными уроками без сторонней помощи.
Ответить | Ответить с цитатой | Цитировать