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

Как сделать выпадающее меню с двумя уровнями вложения

Разметка горизонтального многоуровневого меню базируется на css-позиционировании. Всем элементам списка li задается относительное позиционирование, а выпадающему меню ul любого уровня — абсолютное позиционирование.

По умолчанию ширина выпадающего меню равна ширине элемента списка, в который оно вложено. Чтобы изменить ширину, нужно её задать при помощи свойства width, например, .submenu {width: 300px;}.

Выпадающее меню первого уровня вложения не требует задания смещения, абсолютное позиционирование делает его высоту равной нулю, чтобы не оставлять пустое место под элементом списка. Для меню второго уровня задаётся смещение относительно левой и верхней границы элемента списка ul {left: 100%; top: 0;}

1. Выпадающее раскладывающееся многоуровневое меню

See the Pen ozvvyp by Elena (@html5book) on CodePen.

Выпадающее меню скрывается с помощью .submenu {visibility: hidden; opacity: 0;}, показывается li:hover > .submenu {visibility: visible; opacity: 1;}.

<nav>
  <ul class="topmenu">
    <li><a href="" class="active">Главная<span class="fa fa-angle-down"></span></a>
      <ul class="submenu">
        <li><a href="">меню второго уровня</a></li>
        <li><a href="">меню второго уровня<span class="fa fa-angle-down"></span></a>
          <ul class="submenu">
            <li><a href="">меню третьего уровня</a></li>
            <li><a href="">меню третьего уровня</a></li>
            <li><a href="">меню третьего уровня</a></li>
          </ul>
        </li>
        <li><a href="">меню второго уровня</a></li>
      </ul>
    </li>
    <li><a href="">Компания</a></li>
    <li><a href="">Блог</a></li>
    <li><a href="">Контакты</a></li>
  </ul>
</nav>
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,600&subset=latin,cyrillic);
*{box-sizing: border-box;}
body {
  margin: 0;
  font-family: 'Open Sans', sans-serif;
}
nav {background: #413F3C;}
nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
nav ul:after {
  content: "";
  display: table;
  clear: both;
}
nav a {
  text-decoration: none;
  display: block;
  transition: .3s linear;
}
.topmenu > li {
  float: left;
  position: relative;
  border-left: 1px solid black;
}
.topmenu > li:first-child {border-left: 0;}
.topmenu > li > a {  
  padding: 20px 30px;
  font-size: 12px;
  text-transform: uppercase;
  color: #FEFDFD;
  letter-spacing: 2px;
}
.topmenu > li > a.active, 
.submenu a:hover {color: #ddbe86;}
.topmenu .fa, 
.submenu .fa {
  margin-left: 5px;
  color: inherit;
}
.submenu {
  position: absolute;
  z-index: 5;
  min-width: 200px;
  background: white;
  border-top: 1px solid #CBCBCC;
  border-left: 1px solid #CBCBCC;
  border-right: 1px solid #CBCBCC;
  visibility: hidden;
  opacity: 0; 
  transform-origin: 0% 0%;
  transform: rotateX(-90deg);
  transition: .3s linear;  
}
.submenu li {position: relative;}
.submenu li a {
  color: #282828;
  padding: 10px 20px;
  font-size: 13px;
  border-bottom: 1px solid #CBCBCC;
}
.submenu .submenu {
  position: absolute;
  left: 100%;
  top: -1px;
  transition: .3s linear;
}
nav li:hover > .submenu {
  transform: rotateX(0deg);
  visibility: visible;
  opacity: 1;
}

2. «Подъезжающее» выпадающее меню

See the Pen VKkkxX by Elena (@html5book) on CodePen.

Смещаем подменю .submenu {transform: translateY(10px);} по горизонтали, скрываем его при помощи visibility: hidden; opacity: 0;. При наведении на элемент списка меню становится видимым и перемещается вверх на 10px. Для отображения галочки не забудьте подключить FontAwesome.

<nav>
  <ul class="topmenu">
    <li><a href="" class="active">Главная</a>
      <ul class="submenu">
        <li><a href="">меню второго уровня</a></li>
        <li><a href="" class="submenu-link">меню второго уровня</a>
          <ul class="submenu">
            <li><a href="">меню третьего уровня</a></li>
            <li><a href="">меню третьего уровня</a></li>
            <li><a href="">меню третьего уровня</a></li>
          </ul>
        </li>
        <li><a href="">меню второго уровня</a></li>
      </ul>
    </li>
    <li><a href="">Компания</a></li>
    <li><a href="">Блог</a></li>
    <li><a href="">Контакты</a></li>
  </ul>
</nav>
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,600&subset=latin,cyrillic);
*{box-sizing: border-box;}
body {
  margin: 0; 
  background: #f7f9fe;
  font-family: 'Open Sans', sans-serif;
}
nav {
  background: white;
  box-shadow: 0 2px 0 0 #ECF1F2;
  border-top: 1px solid #ECF1F2;
  text-align: center;
}
nav a {
  text-decoration: none;
  display: block;
  transition: .3s linear;
}
nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.topmenu > li {
  display: inline-block;
  position: relative;
  margin-right: -4px;
  border-left: 1px solid #ECF1F2;
}
.topmenu > li:last-child {border-right: 1px solid #ECF1F2;}
.topmenu > li > a {
  font-weight: bold;
  padding: 20px 30px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 2px;
  color: #1c1c1c;
}
.active:after, .submenu-link:after {
  content: "\f107";
  font-family: "FontAwesome";
  color: inherit;
  margin-left: 10px;
}
.topmenu .active, .topmenu > li > a:hover, .submenu li a:hover {color: #ddbe86;}
.submenu {
  position: absolute;
  left: -1px;
  z-index: 5;
  width: 240px;
  border-bottom: 1px solid #ECF1F2;
  visibility: hidden;
  opacity: 0;  
  transform: translateY(10px);
  transition: .3s ease-in-out;
}
.submenu li {position: relative;}
.submenu a {
  background: white;
  border-top: 1px solid #ECF1F2;
  border-right: 1px solid #ECF1F2;
  border-left: 1px solid #ECF1F2;
  color: #1c1c1c;
  text-align: left;
  font-size: 14px;
  letter-spacing: 1px;
  padding: 10px 20px;
}
.submenu .submenu {
  position: absolute;
  top: 0;
  left: calc(100% - 1px);
  left: -webkit-calc(100% - 1px);
}
nav li:hover > .submenu {
  visibility: visible;
  opacity: 1;
  transform: translateY(0px);
}
  • Создание Сайтов

    Хорошее меню. Надо попробовать подключить его к вордпрессу. Там с этим всегда проблема. А то у меня на случай, если клиенту понадобится многоуровневая модель, и нет ничего.

    • Разметка универсальная, поэтому если посмотреть классы или id элементов меню шаблона, а потом подключить к ним соответствующие стили, то проблем быть не должно

      • Создание Сайтов

        Пока еще не придумал, как в ссылку на вордпресс прописать span …

      • Создание Сайтов

        Скопировал код. Попробовал и увидел, что внизу всех 3 блоков торчат рога.

      • Создание Сайтов

        P.S. там у меня стили были к спискам выше прописаны. Поэтому рога торчали. Убрал.

        • Да, это распространённая проблема, когда на элементы действуют унаследованные стили. Я поэтому все примеры и делаю во встроенном редакторе, чтобы был чистый пример, работающий.

  • Mihail

    от куда пустое пространство между .menu > li ???

    • вы про это пространство?

      • Mihail

        я о том пространстве которое появляется между инлайн элементами .main > li (которое образовывается в следствии переноса строки или пробела после тегов)
        проблему можно решить float: left + очистка через псевдокласс на родителе (правда появляется друга проблема это центрирование) , или в html коде убрать пробелы и переносы

        • я вас поняла. на самом деле не всегда требуется убирать это пространство.

      • Mihail
      • Mihail

        в ваших примерах этого не заметно так как у вас только одна сторона border и фон родителя сливается с фоном элемента

        • хотя их можно убрать, чтобы расстояния слева и справа выглядели одинаковыми, раз уж есть визуальный разделитель. при display:inline-block можно использовать отрицательный margin, как вариант.

      • Mihail

        хотя проблема с центрированием решается тоже просто c display: inline-block; text-align: center; vertical-align: top; (что бы убрать хвосты).
        http://plnkr.co/edit/FSECnWHH1QsuGWphVnUw?p=preview

        • приятно видеть таких подкованных читателей на своём сайте ))
          а ещё можно сделать всё очень красиво и без костылей с помощью модели flexbox. правда до сих пор отпугивает отсутствие поддержки со стороны старых браузеров. но и эту проблему можно решить с помощью библиотеки Modernizr. когда она обнаруживает свойство, не поддерживаемое тем или иным браузером, она добавляет элементам специальные стили, которые мы прописываем на такой случай. то есть просто меняет стили один на другой.

  • Павел Иванов

    как сложно (: надеюсь я научусь делать это

    • Пробуйте, если что-то не поймёте — спрашивайте, так быстрее разберётесь.

  • игорь куренков

    Здравствуйте. Подскажите, пожалуйста, в чем отличие табов от двухуровневого меню? У меня на сайте меню сделано с помощью табов. Нашел вашу статью и хочу реализовать меню трехуровневое, так как мне нужны категории третьего уровня еще? Это скажется на продвижении?

    • Здравствуйте. Табы — это вкладки, они работают по принципу страниц браузера, когда мы открываем их в новой вкладке. В случае табов переход осуществляется не по урл, а по якорю. Обычно вкладки используют для компактного размещения какой-либо связанной информации, но не для навигации по сайту. Можно сказать, что табы — это локальная навигация в пределах одной страницы. Поэтому в вашем случае нужно делать многоуровневое меню.
      Для поисковых роботов можно сделать sitemap с отображением всей иерархии.
      Чтобы не запутаться с разметкой, сначала сделайте три отдельных меню ul, а потом вложите в нужные элементы списка li.

  • Pavel T.

    Подскажите, как сделать, чтобы вкладки были отцентрованы, заранее спасибо.

    • Если вы имеете ввиду, как центрировать выпадающее меню относительно верхнего пункта меню, то нужно высчитать величину смещения следующим образом: смотрите ширину элемента списка (право

      • Pavel T.

        Я имею ввиду расположить меню 1 уровня по середине страницы, сейчас вкладки располагаются слева

        • Второй пример расположен по середине. Для первого добавьте

          .menu {display: table; margin: 0 auto}
  • Создание Сайтов

    Взял последнее меню для вордпресс и столкнулся с таким казусом:
    .active:after, .submenu-link:after {
    content: «f107»;
    font-family: «FontAwesome»;
    color: inherit;
    margin-left: 10px;
    }

    Стрелочка выпадает вниз, не хочет сидеть как здесь. Прописывал для а — там сидит хорошо, но тогда, блин, во всех пунктах субменю она выставляется.

    • Ничего не могу сказать, не видя разметки и стилей страницы.

      • Создание Сайтов

        Вот разметка с суб-меню.

        Каталог

        ПетоМикс

        Проблема в том, что у ссылок на вордпресс нет классов в меню. И я еще не нашел способа, адаптировать иконки под меню. они все время выпадают. Вписывать абсолютным позиционированием не вариант.

        • Зачем мне разметка подменю? Я не могу гадать, в чём там дело. Посмотрите, как реализовано такое меню на готовом шаблоне http://themes.magniumthemes.com/?theme=hmwp

          • Создание Сайтов

            Отлично! Извечная проблема решена: li.has-children > a::after

          • Пожалуйста!

          • zic x

            Елена, подскажите пожалуйста. я человек в этом новый… куда вставляется CSS КОД???

          • Можно на html-странице внутрь тегов <style></style> в разделе <head></head> или во внешнюю таблицу стилей style.css. Подробнее читайте здесь https://html5book.ru/osnovy-css/.

  • Aleksey Gorbunov

    Здравствуйте. А как расположить один из списков, например «Контакты» справа?

    • Здравствуйте. Посмотрите пример https://codepen.io/html5book/pen/dvJeWN.
      1) убираем text-align: center; для nav
      2) .menu > li делаем плавающими по левому краю float: left;, а .menu > li:last-child — плавающим по правому краю float: right
      3) добавляем очистку потока ul:after

  • Бил Гейтс

    Добрый вечер, подскажите пожалуйста. Для чего добавляется к псевдоэлемент :after? В коде:
    nav ul:after {
    content: «»;
    display: table;
    clear: both;
    Как я понимаю он применяет указанные свойства элементам внутри него? Я правильно понимаю? Ведь свойство content пустое, тогда..

    • Здравствуйте. Этот приём очищает поток для контейнера. Внутри списка ul элементы списка плавающие li {float: left;}, следовательно список не видит их высоту, потому что свойство float нарушает нормальный поток документа, когда блочные элементы следуют друг за другом, а мы располагаем их в линию. И если для ul задать фоновую заливку, то она не будет видна. Подробнее про проблемы позиционирования вы можете прочитать в уроке https://html5book.ru/css-position/#part6.

      • evg1401

        Подскажите пожалуйста еще один нюанс? В предпоследнем стиле css указаны селекторы .submenu .submenu {

        }
        Почему-то дважды для одного и того же класса. С какой целью это делается, если не ошибка? Никак не могу догадаться.

        • Так мы стилизуем второе выпадающее меню — меню третьего уровня. У нас есть стили для верхнего меню .topmenu и общие стили для всех выпадающих меню .submenu.

  • Александр

    Здравствуйте. Битый час уже мучаюсь никак не получается решить одну проблему.
    Я хочу сделать так что бы подменю было горизонтальным а не вертикальным и что бы разделы автоматически переносились на новую строку по определенной ширине блока.
    Помогите пожалуйста 🙂

    • Скиньте код на почту или ссылку на кодепен или что-то подобное.

      • Александр

        https://codepen.io/anon/pen/XgeyvG вот
        основных категорий будет где то 5 а вот вложенный список будет варьироваться но суть одна вложенный должен быть горизонтальным и ограниченным по ширине

        • Посмотрите пример https://codepen.io/html5book/pen/owGJQZ. Ширина выпадающего меню будет равна ширине верхнего меню. Если нужно сделать ее определенного размера, вместо right:0 пишете width: 500px например.

          • Александр

            спасибо кажется мне это подходит ) только есть один нюанс, на сайте есть другие меню и у них слетели стили после установки этой менюшки. Думаю тут надо либо дивами либо классами все расставлять

          • Я не задавала классы специально, потому что у вас они могут быть свои.

          • Александр

            да конечно. я попробую сам сделать, если не получится приду к вам за помощью) спасибо

          • Александр

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

          • В подвале сайта указана почта.

  • Игорь Пупкин

    Приветствую!
    Наверное вам не интересно отвечать на вопросы «чайника», однако, возможно вы найдете свободную минутку.
    В представленном вами примере многоуровневого меню,
    1) При добавлении рамки меню первого уровня (border-top: 1px solid #CBCBCC; border-left: 1px solid #CBCBCC; border-right: 1px solid #CBCBCC; border-bottom: 1px solid #CBCBCC;) рамка первого элемента («Главная») не видна.
    (пока писал — нашел где: .topmenu > li:first-child {border-left: 1;} — вопрос снимается)
    2) Как сделать чтобы при наведение мыши на первое слово меню первого уровня менялся цвет (как у остальных элементов меню)
    Если я правильно понял здесь определяется цвет буковок основного меню после наведения мышью
    .topmenu > li > a:hover {color: #4682B4;}

    .topmenu > li > a {
    padding: 10px 50px;/*позиционирование строк основного меню сверху-снизу и справа-слева*/
    font-size: 12px;
    text-transform: capitalize;
    color: #0000FF; /* А здесь определяется цвет буковок основного меню*/
    letter-spacing: 2px;
    }
    В общем я запутался.

    P.S. меню второго и третьего уровня каким-то непостижимым для меня образом color: inherit; — наследуют цвет #4682B4;, а при наведение мышью цвет #0000FF;
    То есть получается все шиворот на выворот — в меню первого уровня цвет буковок #0000FF; а при наведение мыши #4682B4;
    А в меню второго и третьего уровня цвет буковок #4682B4; а при наведение мыши #0000FF;
    Я прошу прощения за полную некомпетентность, — как это можно исправить?

    Вот весь код вашего меню (с моими пометками и чуть изменил под свою задачу)

    *{box-sizing: border-box;}
    body {
    margin: 10px 100px 0px 100px;/*вообще-то это поля в следующей последовательности: верх право низ лево*/
    background: #00FFFF; /*цвет всего листа — аналог в HTML*/
    font-family: Calibri; /*не меняется*/
    font-size: 12px; /*не меняется*/

    }
    nav {background: none} /*цвет основного меню*/
    nav ul {
    margin: 0px;
    padding-left: 0px;
    list-style: none;
    }
    nav ul:after {
    content: «»;
    display: table;
    clear: both;
    }
    nav a {
    text-decoration: none;
    display: block;
    transition: .3s linear;/*анимация буковок меню первого уровня меню*/
    }
    .topmenu > li {
    float: left;
    position: relative;
    border-top: 1px solid #CBCBCC;/*окантовка строк меню первого*/
    border-left: 1px solid #CBCBCC;
    border-right: 1px solid #CBCBCC;
    border-bottom: 1px solid #CBCBCC;
    }
    .topmenu > li:first-child {border-left: 1;/*ширина (и наличие) левого бордера самого левого элемента главного меню*/}
    .topmenu > li > a:hover {color: #4682B4;}/*цвет буковок основного меню после наведения мышью*/
    .topmenu > li > a {
    padding: 10px 50px;/*позиционирование строк основного меню сверху-снизу и справа-слева*/
    font-size: 12px;
    text-transform: capitalize;/*первые буквы заглавные*/
    color: #0000FF; /*цвет буковок основного меню*/
    letter-spacing: 2px;/*расстояние между буковками*/
    }
    .topmenu > li > a.active,
    .submenu a:hover {color: #0000FF;}/*цвет буковок первого слова основного меню*/
    .topmenu .fa,
    .submenu .fa {
    margin-left: 5px;
    color: inherit; /*наследует цвет от родительского элемента*/
    }
    .submenu {
    position: absolute;
    z-index: 5;
    min-width: 200px;
    background: none;/*цвет второго и третьего уровня*/
    border-top: 1px solid #CBCBCC;/*окантовка строк меню второго и третьего уровня*/
    border-left: 1px solid #CBCBCC;
    border-right: 1px solid #CBCBCC;
    visibility: hidden;
    opacity: 0;
    transform-origin: 0% 0%;
    transform: rotateX(-90deg);
    transition: .3s linear;/*анимация буковок меню второго уровня меню*/
    }
    .submenu li {position: relative;}
    .submenu li a {
    color: #4682B4;/*цвет буковок основного меню после наведения мышью*/
    padding: 10px 20px;
    font-size: 13px;
    border-bottom: 1px solid #CBCBCC;
    }
    .submenu .submenu {
    position: absolute;
    left: 100%;
    top: -1px;
    transition: .3s linear;/*анимация буковок меню третьего уровня меню*/
    }
    nav li:hover > .submenu {
    transform: rotateX(0deg);
    visibility: visible;
    opacity: 1;
    }

    • Смогу ответить вам через несколько дней, если вас устроит.

      • Игорь Пупкин

        Конечно!
        Когда у вас будет время и желание.
        Важен конечный результат.
        Спасибо, что время уделили.

    • Посмотрите пример https://codepen.io/html5book/pen/owaqEK, добавила некоторые комментарии. Способов задать рамку для меню может быть несколько, в этом примере я показала другой вариант. Если что-то непонятно — спрашивайте.

  • Ed Sheeran

    Добрый день! После установки меню, объясните дураку 2 дня не могу додуматься, надо все содержимое остальное прикрепить к низу странице, то есть убрать «висящий подвал» и ни чего не выходит? куда копать?
    .content-bg {
    width: 1024px; /* Ширина макета */
    margin: auto; /* Выравнивание по центру */
    padding: 20px 10px;/* Поля */
    min-height: 100%;
    text-align: justify; /* Выравнивание по ширине */
    background-color: aliceblue;
    }

  • daDast

    Подскажите пожалуйста это плагин позволяет вставлять код из codePen? если нет то как такое же реализовать? и как сделать кнопку которая копирует в буфер обмена кусок кода из блока с этим кодом?