В этом уроке рассмотрим создание адаптивного меню, на основе списка. Для desktop версии меню будет горизонтальным, для мобильной вертикальным. Раскрытие самого меню и пунктов в мобильной версии через JQuery, все остальное - HTML и CSS. И поскольку сайт на чистом HTML сейчас большая редкость, добавим получение пунктов меню из БД, используя PHP. Здесь решил показать весь процесс превращения данных из таблицы БД в меню сайта.
Все пункты меню изначально представлю в виде таблицы, подобно тому, как они хранятся в MySql.
Таблица будет называться "menu". Столбцы: menu_id (уникальный порядковый номер), name (название пункта меню), link (ссылка), parent (родитель)
menu_id | name | link | parent |
0 | Пункт 1 | # | 0 |
1 | Пункт 2 | # | 0 |
2 | Пункт 3 | # | 0 |
3 | Пункт 4 | # | 0 |
4 | Подпункт 1 | # | 1 |
5 | Подпункт 2 | # | 1 |
6 | Подпункт 3 | # | 1 |
7 | Подпункт 4 | # | 3 |
8 | Подпункт 5 | # | 3 |
9 | Подпункт 6 | # | 3 |
10 | Подпункт 7 | # | 3 |
11 | Подпункт 8 | # | 3 |
А теперь займемся выводом.
PHP. Получение пунктов, подготовка к выводу в шаблон
Т.к. цель - получить меню на сайте, а не научится работать с БД MySQL, здесь немного упрощу, иначе нужно будет начинать с подключения к MySQL и оттуда двигаться дальше, а учитывая что здесь могут быть варианты, рискую запутать.
Для начала запрос к БД для получения пунктов, который будет находится в функции getMenu($parent) {}. Именно к фунции с таким именем будем дальше обращаться, функция будет получать родителя в переменной "$parent" и возвращать массив с пунктами. Модель, MySQL запрос:
SELECT * FROM menu WHERE `parent` = '" . (int)$parent . "'
Получаем не сразу все возможные пункты, а по родителю, т.е. сначала корневые, затем перебираем их и для каждого корневого получаем подпункты. Это выглядит так (контроллер):
$menu = array();//для начала объявим переменную с пустым массивом, на случай если в таблице ничего не найдется.
$q_menu = getMenu(0); //получаем массив с корневыми пунктами и затем перебираем его
foreach ($q_menu as $menu_item) {
$childs = array(); //пустой массив с подпунктами, опять же на случай, если таковых нет.
$q_childs = getMenu($menu_item['menu_id']);//Получаем подпункты для текущего пункта меню. Здесь текущий пункт - родитель. Перебираем их.
foreach ($q_childs as $child_item) {
//формируем массив с подпунктами
$childs[] = array(
'menu_id' => $child_item['menu_id'],
'name' => $child_item['name'],
'link' => $child_item['link']
);
}
//Теперь формируем массив с корневыми пунктами, включающий массивы подпунктом (многомерный массив всего меню)
$menu[] = array(
'menu_id' => $child_item['menu_id'],
'name' => $child_item['name'],
'link' => $child_item['link'],
'childs' => $childs
);
}
Теперь можно переходить к выводу в шаблон
HTML. Вывод в шаблоне. И немного PHP
Для начала вывод с помощью PHP
<span class="menu-toggle"><img src="images/menu/menu40.png" alt="Показать меню" /></span><nav id="top-menu" class="top-menu">
<ul class="parent">
<?php foreach ($menu as $menu_item) { ?>
<?php if ($menu_item['childs']) { ?>
<li><a href="<?php echo $menu_item['link']; ?>"><?php echo $menu_item['name']; ?></a>
<span class="togg"></span>
<div class="child">
<ul>
<?php foreach ($menu_item['childs'] as $child_item) { ?>
<li><a href="<?php echo $child_item['link']; ?>"><?php echo $child_item['name']; ?></a></li>
<?php } ?>
</ul>
</div>
</li>
<?php } else { ?>
<li><a href="<?php echo $menu_item['link']; ?>"><?php echo $menu_item['name']; ?></a></li>
<?php } ?>
<?php } ?>
</ul>
</nav>
В результате получим вот такой HTML:
<span class="menu-toggle"><img src="images/menu/menu40.png" alt="Показать меню" /></span><nav id="top-menu" class="top-menu">
<ul class="parent">
<li><a href="#">Пункт 1</a>
<span class="togg"></span>
<div class="child">
<ul>
<li><a href="#">Подпункт 1</a></li>
<li><a href="#">Подпункт 2</a></li>
<li><a href="#">Подпункт 3</a></li>
</ul>
</div>
</li>
<li><a href="#">Пункт 2</a></li>
<li><a href="#">Пункт 3</a>
<span class="togg"></span>
<div class="child">
<ul>
<li><a href="#">Подпункт 4</a></li>
<li><a href="#">Подпункт 5</a></li>
<li><a href="#">Подпункт 6</a></li>
<li><a href="#">Подпункт 7</a></li>
<li><a href="#">Подпункт 8</a></li>
</ul>
</div>
</li>
<li><a href="#">Пункт 4</a></li>
</ul>
</nav>
Тепеерь займемся оформлением и для начала напишем небольшой скрипт для раскрытия меню, проверим что меню скрывается и раскрывается, затем CSS.
Оформление JS и CSS
Скрипт jQuery открытия/закрытия меню:
$(".menu-toggle").click(function () {
$('#top-menu').toggle().toggleClass('open');
$('body').toggleClass('menuopen')
});
/*Для раскрытия внутренних пунктов*/
$('.togg').click(function () {
$(this).toggleClass('active').next().toggle().toggleClass('open');
});
Добавление класса "menuopen" для body нужно, что бы фиксировать страницу при раскрытии меню в мобильной версии (прокручиваться должно только меню, а не вся страница).
Без применения каких-либо стилей элементы меню будут расположены друг под другом, все подпункты раскрыты, соответственно необходимо добавить некоторые CSS стили.
.menu-toggle {display:none;}
.top-menu ul {list-style-type: none;padding-left: 0px;margin: 0px;}
.top-menu ul li {position: relative;}
.top-menu .child {display: none;}
.top-menu .child ul {background: rgba(255, 255, 255, 0.9);min-width: 220px;box-shadow: 0px 0px 5px #a7a7a7;}
.top-menu a {display: block;padding: 5px 15px;}
.top-menu .togg {position: absolute;bottom: -8px;left: 50%;margin-left: -2px;}
.top-menu .togg:before {border-top: 4px solid #f44242;border-left: 4px solid transparent;border-right: 4px solid transparent;content: '';display: block;}
.top-menu .togg.active, .top-menu li:hover > .togg {transform: rotate(180deg);}
/*Добавим плавный переход для некоторых элементов*/
.togg, a, ul {transition: all 0.5s ease 0s;-moz-transition: all 0.5s ease 0s;-webkit-transition: all 0.5s ease 0s;-o-transition: all 0.5s ease 0s;}
@media (min-width: 1200px) {
/*Некоторые свойства будут работать только при показе меню, для десктопа.*/
/*Делаем горизонтальным*/
.top-menu .parent > li {float: left;}
/*Показываем подпункты по наведению (В мобильной версии будет по клику)*/
.top-menu li:hover .child {display: block}
.top-menu ul:after {display:block;content:'';clear:both;}
.top-menu .child {position: absolute;top: 100%;left: 0px;padding-top: 10px;}
/*Выделение цветом при наведении*/
.top-menu li:hover > a {color: #d60400}
}
@media (max-width: 1199px) {
/*Покажем кнопку и спрячем меню*/
.menu-toggle {display:block;position:absolute;right:0px;top:0px;}
.top-menu {display:none;}
/*Зафиксируем страницу при раскрытом меню*/
body.menuopen {width: 100%;height: 100%;overflow: hidden;}
/*Подпункты раскрываются по клику на span, что бы было меньше шансов попасть по ссылке, не будем делать ее на всю ширину*/
.top-menu a {display:inline-block;}
/*Выделение цветом активного пункта*/
.primermenu .top-menu li:hover a {color: #d60400}
.top-menu ul li {border-bottom: 1px dotted #ccc}
.top-menu .togg {height: 30px;width: 30px;top: 3px;border: 1px solid #5e5e5e;bottom: auto;right: 10px;left: auto;margin-left: 0px;padding: 10px 5px;box-sizing: border-box;border-radius: 30px;}
.top-menu .togg:before {border-top: 10px solid #ec3437;border-left: 9px solid transparent;border-right: 9px solid transparent;}
}
Результат
Для просмотра мобильной версии уменьшите размер окна, или посмотрите с телефона