Максимум веб информации Создать акаунт

Адаптивное горизонтальное многоуровневое меню для CMS DLE: пошаговое руководство с кодом

21 окт 2026
Дизайн и графика
6
0
Адаптивное горизонтальное многоуровневое меню для CMS DLE: пошаговое руководство с кодом

DLE (DataLife Engine) по-прежнему живёт на тысячах сайтов, и один из самых частых запросов его владельцев — сделать нормальное выпадающее меню: горизонтальное, многоуровневое и, главное, удобное на телефоне.

Стандартные способы ограничены, поэтому соберём меню с нуля: HTML-каркас, CSS-стили на флексах, немного jаvascript для мобильной версии и корректная интеграция с шаблоном DLE. Всё, что ниже — рабочий код, который можно вставить в свой шаблон и доработать под дизайн.

Что будем делать

Цель — трёхуровневое горизонтальное меню:

  • первый уровень — основные разделы сайта;
  • второй и третий уровни — выпадающие списки при наведении (на десктопе) или раскрытии по тапу (на мобильных);
  • на ширине до 992 пикселей меню сворачивается в «бургер», а вложенные уровни раскрываются аккордеоном;
  • пункты меню задаются вручную или подтягиваются из категорий DLE.

Подход не зависит от версии движка (актуально для DLE 13–21) и не требует плагинов.

Шаг 1. HTML-структура меню

Открываем файл шаблона templates/ваш_шаблон/main.tpl и в нужном месте (обычно внутри шапки) размещаем разметку:

<nav class="top-menu">
  <button class="menu-toggle" aria-label="Открыть меню" aria-expanded="false">
    <span></span><span></span><span></span>
  </button>

  <ul class="menu">
    <li><a href="/">Главная</a></li>
    <li class="has-sub">
      <a href="/novosti/">Новости</a>
      <ul class="submenu">
        <li><a href="/novosti/mir/">В мире</a></li>
        <li><a href="/novosti/sport/">Спорт</a></li>
        <li class="has-sub">
          <a href="/novosti/tehnologii/">Технологии</a>
          <ul class="submenu">
            <li><a href="/novosti/tehnologii/gadzhety/">Гаджеты</a></li>
            <li><a href="/novosti/tehnologii/soft/">Софт</a></li>
          </ul>
        </li>
      </ul>
    </li>
    <li><a href="/statji/">Статьи</a></li>
    <li><a href="/forum/">Форум</a></li>
    <li><a href="/kontakty.html">Контакты</a></li>
  </ul>
</nav>

Логика простая: пункт с вложенным списком получает класс has-sub, а вложенные списки — общий класс submenu. Именно на этих классах будет держаться вся стилизация и поведение.

Шаг 2. CSS: десктопная версия

Добавляем стили в файл templates/ваш_шаблон/css/style.css (или в отдельный menu.css, который подключим в main.tpl).

/* ===== Контейнер меню ===== */
.top-menu {
  position: relative;
  background: #1e2a38;
}

.menu {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  margin: 0;
  padding: 0;
}

.menu > li {
  position: relative;
}

.menu a {
  display: block;
  padding: 14px 20px;
  color: #fff;
  text-decoration: none;
  font: 15px/1.2 Arial, sans-serif;
  transition: background .2s;
}

.menu a:hover,
.menu > li.active > a {
  background: #2e4156;
}

/* ===== Выпадающие уровни ===== */
.submenu {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 200px;
  list-style: none;
  margin: 0;
  padding: 0;
  background: #2e4156;
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: .25s ease;
  z-index: 100;
}

/* второй уровень раскрывается вниз, третий — вбок */
.has-sub:hover > .submenu,
.has-sub.open > .submenu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.submenu .submenu {
  top: 0;
  left: 100%;
  transform: translateX(10px);
}

.submenu a {
  padding: 12px 18px;
  border-bottom: 1px solid rgba(255,255,255,.06);
}

/* стрелка у пунктов с подменю */
.has-sub > a::after {
  content: "";
  display: inline-block;
  margin-left: 8px;
  border: 5px solid transparent;
  border-top-color: #fff;
  vertical-align: middle;
}

/* ===== Бургер скрыт на десктопе ===== */
.menu-toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  padding: 14px;
  background: none;
  border: 0;
  cursor: pointer;
}

.menu-toggle span {
  width: 26px;
  height: 2px;
  background: #fff;
  transition: .3s;
}

Обратите внимание на приём с visibility и opacity вместо display: none — он даёт плавную анимацию появления и не «роняет» меню при резком уводе курсора.

Шаг 3. CSS: мобильная версия

В конец того же файла добавляем медиазапрос — на узких экранах меню перестраивается в вертикальный аккордеон:

@media (max-width: 992px) {
  .menu-toggle {
    display: flex;
  }

  .menu {
    display: none;
    flex-direction: column;
    width: 100%;
  }

  .top-menu.open .menu {
    display: flex;
  }

  /* подменю больше не абсолютные — встают в поток */
  .submenu {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    display: none;
    background: #263545;
  }

  .has-sub.open > .submenu {
    display: block;
  }

  .submenu .submenu {
    background: #1e2a38;
  }

  /* анимация бургера в крестик */
  .top-menu.open .menu-toggle span:nth-child(1) {
    transform: translateY(7px) rotate(45deg);
  }
  .top-menu.open .menu-toggle span:nth-child(2) {
    opacity: 0;
  }
  .top-menu.open .menu-toggle span:nth-child(3) {
    transform: translateY(-7px) rotate(-45deg);
  }
}

Шаг 4. jаvascript: раскрытие на мобильных

Файл templates/ваш_шаблон/js/menu.js:

document.addEventListener('DOMContentLoaded', function () {
  var nav = document.querySelector('.top-menu');
  if (!nav) return;

  // открыть/закрыть бургер
  nav.querySelector('.menu-toggle').addEventListener('click', function () {
    var open = nav.classList.toggle('open');
    this.setAttribute('aria-expanded', open);
  });

  // раскрытие подменю по тапу
  nav.querySelectorAll('.has-sub > a').forEach(function (link) {
    link.addEventListener('click', function (e) {
      if (window.innerWidth <= 992) {
        e.preventDefault();
        var li = link.parentElement;
        var isOpen = li.classList.contains('open');

        // закрываем соседние пункты — так аккордеон аккуратнее
        li.parentElement.querySelectorAll('.has-sub.open').forEach(function (el) {
          el.classList.remove('open');
        });

        if (!isOpen) li.classList.add('open');
      }
    });
  });

  // при переходе на десктоп сбрасываем раскрытия
  window.addEventListener('resize', function () {
    if (window.innerWidth > 992) {
      nav.classList.remove('open');
      nav.querySelectorAll('.has-sub.open').forEach(function (el) {
        el.classList.remove('open');
      });
    }
  });
});

Подключаем скрипт в main.tpl перед закрывающим </body>:

<script src="{THEME}/js/menu.js"></script>

Тег {THEME} DLE автоматически подставит путь до текущего шаблона — переопределять ничего не нужно. То же самое работает для CSS, если вынесете стили в отдельный файл:

<link rel="stylesheet" href="{THEME}/css/menu.css">

Шаг 5. Интеграция с DLE: два способа наполнения меню

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

Способ 2 — автогенерация из категорий. DLE умеет строить меню категорий тегом:

{catmenu template="catmenu" cache="yes"}

Движок возьмёт файл templates/ваш_шаблон/catmenu.tpl и построит дерево категорий. Чтобы вписать его в нашу структуру, содержимое catmenu.tpl может выглядеть так:

<li class="has-sub [active]active[/active]">
  <a href="{url}">{name}</a>
  {sub-menu}
</li>

Тег {sub-menu} DLE заменит на вложенный <ul> с подкатегориями. Здесь есть нюанс: класс has-sub тегом не управляется, поэтому если нужно строгое поведение «стрелка только там, где есть подменю», проще отдать стилям — или использовать комбинированный подход: первый уровень статичный, вложенные уровни — через {catmenu}.

Также не забывайте про подсветку текущего раздела: в шаблонах пунктов доступны теги [active] … [/active], а в статичном меню активный пункт можно пометить классом active вручную и стилизовать через правило .menu > li.active > a, которое уже есть в CSS выше.

Шаг 6. SEO-нюансы меню

Меню — это навигация, а не место для перелинковки на всё подряд, поэтому несколько правил, которые реально влияют на индексацию:

  • оставляйте разметку семантичной: контейнер <nav>, списки <ul>, никаких <div>-имитаций;
  • не прячьте важные разделы глубже второго уровня — ссылочная ценность с каждым уровнем падает;
  • избегайте дублей: не ставьте в меню две ссылки на один URL под разными названиями;
  • текст ссылки должен отражать содержимое страницы («Новости технологий», а не «Раздел 3»);
  • выпадающие уровни на десктопе делайте раскрываемыми при наведении, но не скрывайте их display: none навсегда — поисковики индексируют ссылки из выпадающих меню, если те присутствуют в разметке.
Типичные ошибки при интеграции
  • Меню «прыгает» при наведении. Причина — у вложенного .submenu не задан z-index, и его перекрывает контент. Проверьте, что у родителей стоит position: relative, а у подменю — z-index: 100.
  • Подменю уходит за край экрана. Если пункт с выпадашкой стоит у правого края, раскрывайте её влево: добавьте класс .open-left с правилом .open-left > .submenu { left: auto; right: 0; }.
  • На мобильных по тапу сразу срабатывает переход по ссылке. Наш скрипт перехватывает клики только на родительских пунктах с подменю — обычные пункты работают как ссылки, это правильно. Если родительский раздел тоже должен вести на страницу, дублируйте его первым пунктом подменю («Все новости»).
  • Меню не наследует стили темы. Убедитесь, что подключение menu.css стоит ниже основного файла стилей, иначе специфичность может переопределить правила.

Стоит обратить внимание на один нюанс !!!

Если у Вас в шаблоне уже есть похожие классы, например:  .submenu  has-sub то придется их переименовать во всех стилях и html.

Например:  .submenu2    has-sub2 соответственно в стилях должно быть так: 

.submenu2 {
position: static;
opacity: 1;
visibility: visible;
transform: none;
display: none;
background: #263545;
}
Подписка на публикацию новости
Поблагодарили: 0
Пока никто не поблагодарил
Комментарии
Минимальная длина комментария — 50 знаков. Комментарии модерируются.
Мы используем файлы cookie
Сайт (WEB-MAXS.RU) использует файлы cookies и сервисы сбора технических данных посетителей (данные об IP-адресе, местоположении и др.) для обеспечения работоспособности и улучшения качества обслуживания. Продолжая использовать наш сайт, вы автоматически соглашаетесь с использованием данных технологий.
Лучшие предложения для Вашего Wordpress сайта!

Может быть интересно!

Лучшие предложения для Вашего Wordpress сайта!

Выбирайте то,
что действительно нужно!