Горизонтальное меню на основе списка

Горизонтальное меню на основе списка

В этом уроке рассмотрим создание адаптивного меню, на основе списка. Для desktop версии меню будет горизонтальным, для мобильной вертикальным. Раскрытие самого меню и пунктов в мобильной версии через JQuery, все остальное - HTML и CSS. И поскольку сайт на чистом HTML сейчас большая редкость, добавим получение пунктов меню из БД, используя PHP. Здесь решил показать весь процесс превращения данных из таблицы БД в меню сайта.

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

Таблица будет называться "menu". Столбцы: menu_id (уникальный порядковый номер), name (название пункта меню), link (ссылка), parent (родитель)

menu_idnamelinkparent
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;}
}

Результат

Для просмотра мобильной версии уменьшите размер окна, или посмотрите с телефона

Сказать $пасибо

Комментарии ()