Статья, в которой рассмотрим процесс создания вертикального аккордеона для сайта с использованием CSS и JavaScript (без jQuery).
Процесс создания аккордеона
Процесс разработки вертикального аккордеона будет состоять из:
- создания HTML разметки;
- описания его внешнего вида с помощью CSS;
- написания логики на JavaScript.
Дизайн аккордеона (скриншот):

HTML код аккордеона и его описание
HTML-разметка аккордеона:
<div id="accordion" class="accordion"> <div class="accordion-item show"> <div class="accordion-item-header"> Заголовок 1 </div> <div class="accordion-item-content"> Контент 1... </div> </div> <div class="accordion-item"> <div class="accordion-item-header"> Заголовок 2 </div> <div class="accordion-item-content"> Контент 2... </div> </div> ... </div>
Аккордеон (accordion) состоит из элементов (accordion-item). Каждый элемент в свою очередь включает в себя заголовок (accordion-item-header) и содержимое (accordion-item-content).
Состояние элемента (accordion-item) в аккордеоне определяется с помощью класса show
. Если данный класс присутствует, то содержимое элемента (accordion-item-content) показывается. В противном случае оно скрыто.
Переключение состояния элемента (accordion-item) осуществляется посредством нажатия на заголовок (accordion-item-header).
CSS код аккордеона
Стили аккордеона:
.accordion-item-header { padding: 10px 15px; background: #ed5565; color: #fff; cursor: pointer; } .accordion-item-content { background: #383838; color: #fff; display: none; } .accordion-item.show .accordion-item-content { padding: 10px 15px; display: block; } .accordion-item.show .accordion-item-header { background: #da4453; color: #fff; }
Данный код выполняет стилизацию элементов аккордеона, добавляет к ним необходимые внутренние отступы, цвет текста, цвет фона и др. Но, кроме этого, он ещё определяет видимость элементов аккордеона с классом accordion-item-content
, т.е. содержимого.
По умолчанию элементы, имеющие класс accordion-item-content
не отображаются (CSS свойство display
равно значению none
). Включение отображения определённого элемента (accordion-item-content) осуществляется посредством класса show
, который необходимо добавить к его родительскому элементу (accordion-item).
JavaScript код аккордеона
Сценарий (логика) аккордеона:
var accordion = (function (element) { var _getItem = function (elements, className) { // функция для получения элемента с указанным классом var element = undefined; elements.forEach(function (item) { if (item.classList.contains(className)) { element = item; } }); return element; }; return function () { var _mainElement = {}, // .accordion _items = {}, // .accordion-item _contents = {}; // .accordion-item-content var _actionClick = function (e) { if (!e.target.classList.contains('accordion-item-header')) { // прекращаем выполнение функции если кликнули не по заголовку return; } e.preventDefault(); // отменям стандартное действие // получаем необходимые данные var header = e.target, item = header.parentElement, itemActive = _getItem(_items, 'show'); if (itemActive === undefined) { // добавляем класс show к элементу (в зависимости от выбранного заголовка) item.classList.add('show'); } else { // удаляем класс show у ткущего элемента itemActive.classList.remove('show'); // если следующая вкладка не равна активной if (itemActive !== item) { // добавляем класс show к элементу (в зависимости от выбранного заголовка) item.classList.add('show'); } } }, _setupListeners = function () { // добавим к элементу аккордиона обработчик события click _mainElement.addEventListener('click', _actionClick); }; return { init: function (element) { _mainElement = (typeof element === 'string' ? document.querySelector(element) : element); _items = _mainElement.querySelectorAll('.accordion-item'); _setupListeners(); } } } })();
Сценарий JavaScript выполняет очень простые действия. Он добавляет обработчик события click
для аккордеона. Далее в зависимости от того по какому заголовку кликнули, он добавляет и (или) удаляет класс show
у необходимых(ого) элементов(а).
Инициализация элемента как аккордеон выполняется следующим образом:
// инициализируем элемент с id="accordion" как аккордеон var accordion1 = accordion(); accordion1.init('#accordion');
Аккордеон, заголовки которого отделены друг от друга
Скриншот аккордеона, элементы которого отделены друг от друга с помощью отступа:

CSS, добавляющий к элементам аккордеона отступы снизу (margin-bottom
):
.accordion-item { margin-bottom: .25rem; } .accordion-item:last-child { margin-bottom: 0; }
Аккордеон с анимацией появления
Скриншот аккордеона, появление содержимого которого сопровождается CSS анимацией:

Стили аккордеона, включающие в себя анимацию (для отображения содержимого):
.accordion { border-bottom: 1px solid #ddd; } .accordion-item { border-top: 1px solid #ddd; border-left: 1px solid #ddd; border-right: 1px solid #ddd; } .accordion-item-header { padding: 10px 15px; background: #a4b4bf; color: #fff; cursor: pointer; } .accordion-item-content { background: #fff; transition: opacity .4s ease; visibility: hidden; height: 0; opacity: 0; } .accordion-item.show .accordion-item-content { padding: 10px 15px; visibility: visible; height: auto; opacity: 1; } .accordion-item.show .accordion-item-header { background: #3498db; color: #fff; border-bottom: 1px solid #ddd; }
Вертикальное меню аккордеон
Пример настройки аккордеона в качестве вертикального меню.
Дополнительно в JavaScript сценарий добавим небольшой фрагмент кода, который будет показывать сколько подпунктов имеет каждый пункт в этом меню.

CSS и JavaScript:
<style> /* CSS */ .accordion-item { margin-bottom: 1px; } .accordion-item:last-child { margin-bottom: 0; } .accordion-item-header { padding: 10px 10px 10px 20px; background: #4d5159; color: rgba(255, 255, 255, .8); cursor: pointer; text-transform: uppercase; font-family: sans-serif; position: relative; } .accordion-item.show .accordion-item-header, .accordion-item-header:hover, .accordion-item-header:focus { background: #3b3e44; } .accordion-item-header::before { content: ""; position: absolute; top: 0; left: 0; bottom: 0; width: 10px; background: rgba(255, 255, 255, .5); } .accordion-item-content { display: none; } .accordion-item.show .accordion-item-content { display: block; } .accordion-subitems { list-style-type: none; margin: 0; padding: 0; } .accordion-subitem>a { padding: 10px 10px 10px 20px; background: #ebeaec; color: #333; cursor: pointer; text-transform: uppercase; font-family: sans-serif; position: relative; margin-top: 1px; display: block; text-decoration: none; } .accordion-subitem>a::before { content: ""; position: absolute; top: 0; left: 0; bottom: 0; width: 10px; background: rgba(255, 255, 255, .5); } .accordion-subitem.active>a { background: #d4d3d5; pointer-events: none; } .accordion-subitem a:hover, .accordion-subitem a:focus { background: #d4d3d5; } .accordion-item-header-count { position: absolute; top: 50%; right: 10px; width: 24px; height: 24px; transform: translateY(-50%); text-align: center; background: rgba(255, 255, 255, .8); color: #000; line-height: 24px; border-radius: 12px; } </style> <!-- HTML --> <div id="accordion" class="accordion"> <div class="accordion-item"> <div class="accordion-item-header"> Заголовок 1 </div> <div class="accordion-item-content"> <ul class="accordion-subitems"> <li class="accordion-subitem"> <a href="#">Пункт 1.1</a> </li> <li class="accordion-subitem active"> <a href="#">Пункт 1.2</a> </li> <li class="accordion-subitem"> <a href="#">Пункт 1.3</a> </li> ... </ul> </div> </div> ... </div> <script> // JavaScript var accordion = (function (element) { var _getItem = function (elements, className) { // функция для получения элемента с указанным классом var element = undefined; elements.forEach(function (item) { if (item.classList.contains(className)) { element = item; } }); return element; }; return function () { var _mainElement = {}, // .accordion _items = {}, // .accordion-item _contents = {}; // .accordion-item-content var _addItemHeaderCount = function () { // количество подпунктов в пункте var headers = _mainElement.querySelectorAll('.accordion-item-header'); headers.forEach(function (header) { var countElement = document.createElement('div'); countElement.className = 'accordion-item-header-count'; countElement.textContent = header.parentElement.querySelectorAll('.accordion-subitem').length; header.appendChild(countElement); }); }, _actionClick = function (e) { if (!e.target.classList.contains('accordion-item-header')) { // прекращаем выполнение функции если кликнули не по заголовку return; } e.preventDefault(); // отменям стандартное действие // получаем необходимые данные var header = e.target, item = header.parentElement, itemActive = _getItem(_items, 'show'); if (itemActive === undefined) { // добавляем класс show к элементу (в зависимости от выбранного заголовка) item.classList.add('show'); } else { // удаляем класс show у ткущего элемента itemActive.classList.remove('show'); // если следующая вкладка не равна активной if (itemActive !== item) { // добавляем класс show к элементу (в зависимости от выбранного заголовка) item.classList.add('show'); } } }, _setupListeners = function () { // добавим к элементу аккордиона обработчик события click _mainElement.addEventListener('click', _actionClick); }; return { init: function (element) { _mainElement = (typeof element === 'string' ? document.querySelector(element) : element); _items = _mainElement.querySelectorAll('.accordion-item'); _addItemHeaderCount(); _setupListeners(); } } } })(); var accordion1 = accordion(); accordion1.init('#accordion'); </script>
Многоуровневое вертикальное меню аккордеон
Пример в котором рассмотрим как создать многоуровневое вертикальное меню аккордеон.

HTML, CSS и JavaScript код многоуровневого меню:
<style> .accordion { padding-left: 0; } .accordion-item { margin-bottom: 2px; } .accordion-item:last-child { margin-bottom: 0; } .accordion-item-header { padding: 10px 15px 10px 35px; background: #2e7d32; color: #fff; cursor: pointer; position: relative; } .accordion-item-header::before { display: inline-block; content: ""; position: absolute; border-top: 8px solid currentColor; border-right: 8px solid transparent; border-bottom: 0; border-left: 8px solid transparent; top: 50%; margin-top: -4px; left: 12px; } .accordion-item-header::after { display: inline-block; content: ""; position: absolute; border-top: 8px solid #2e7d32; border-right: 8px solid transparent; border-bottom: 0; border-left: 8px solid transparent; top: 50%; margin-top: -6px; left: 12px; } .accordion-item-content { background: #dcedc8; color: #1b5e20; display: none; list-style-type: none; } .accordion-item.show > .accordion-item-content { padding: 10px 15px; display: block; } .accordion-item.show > ul.accordion-item-content { padding-top: 0; padding-bottom: 0; padding-right: 0; background: #fff; } .accordion-item.show > .accordion-item-header { background: #4caf50; color: #fff; margin-bottom: 2px; } .accordion-item.show > .accordion-item-header::before { transform: rotate(-90deg); } .accordion-item.show > .accordion-item-header::after { transform: rotate(-90deg); margin-top: -4px; left: 10px; border-top-color: #4caf50; } .accordion-item-header:focus, .accordion-item-header:hover, .accordion-item.show > .accordion-item-header:focus, .accordion-item.show > .accordion-item-header:hover { background: #1B5E20; } .accordion-item-header:focus::after, .accordion-item-header:hover::after, .accordion-item.show > .accordion-item-header:focus::before, .accordion-item.show > .accordion-item-header:hover::after { border-top-color: #1B5E20; } </style> ... <ul id="accordion" class="accordion" style="max-width: 400px; margin: 0 auto;"> <li class="accordion-item show"> <div class="accordion-item-header"> Заголовок 1 </div> <ul class="accordion-item-content"> <li class="accordion-item"> <div class="accordion-item-header"> Заголовок 1.1 </div> <div class="accordion-item-content" style="height: 200px;"> Контент 1.1... </div> </li> <li class="accordion-item"> <div class="accordion-item-header"> Заголовок 1.2 </div> <div class="accordion-item-content" style="height: 200px;"> Контент 1.2... </div> </li> <li class="accordion-item"> <div class="accordion-item-header"> Заголовок 1.3 </div> <div class="accordion-item-content" style="height: 200px;"> Контент 1.3... </div> </li> </ul> </li> <li class="accordion-item"> <div class="accordion-item-header"> Заголовок 2 </div> <div class="accordion-item-content" style="height: 200px;"> Контент 2... </div> </li> <li class="accordion-item"> <div class="accordion-item-header"> Заголовок 3 </div> <div class="accordion-item-content" style="height: 200px;"> Контент 3... </div> </li> <li class="accordion-item"> <div class="accordion-item-header"> Заголовок 4 </div> <ul class="accordion-item-content"> <li class="accordion-item"> <div class="accordion-item-header"> Заголовок 4.1 </div> <div class="accordion-item-content" style="height: 200px;"> Контент 4.1... </div> </li> <li class="accordion-item"> <div class="accordion-item-header"> Заголовок 4.2 </div> <div class="accordion-item-content" style="height: 200px;"> Контент 4.2... </div> </li> </ul> </li> </ul> <script> var accordion = (function (element) { var _getActiveItems = function (elements) { // функция для получения элементов с указанным классом var items = []; elements.forEach(function (item) { if (item.classList.contains('show')) { items.push(item); } }); return items; }; return function () { var _mainElement = {}, // .accordion _items = {}, // .accordion-item _contents = {}; // .accordion-item-content var _actionClick = function (e) { if (!e.target.classList.contains('accordion-item-header')) { // прекращаем выполнение функции если кликнули не по заголовку return; } e.preventDefault(); // Отменям стандартное действие // получаем необходимые данные var header = e.target, item = header.parentElement, activeItems = _getActiveItems(_items); if (!activeItems.length) { // добавляем класс show к элементу (в зависимости от выбранного заголовка) item.classList.add('show'); } else { // удаляем класс show activeItems.forEach(function (activeItem) { if (!activeItem.contains(item)) { activeItem.classList.remove('show'); } }); item.classList.toggle('show'); } }, _setupListeners = function () { // добавим к элементу аккордиона обработчик события click _mainElement.addEventListener('click', _actionClick); }; return { init: function (element) { _mainElement = (typeof element === 'string' ? document.querySelector(element) : element); _items = _mainElement.querySelectorAll('.accordion-item'); _setupListeners(); } } } })(); var accordion1 = accordion(); accordion1.init('#accordion'); </script>
единственный недостаток — Инициализация элемента как аккордеон к каждому экземпляру var accordion2 = accordion(); accordion2.init('#accordion-2');
Если возможно — допишите универсальный код.
1) Есть аккордеон меню взятое с вашего сайта codepen.io/man129/pen/MWeLdwz пункты в нем получились достаточно длинными (10 Пунктов) itchief.ru/assets/uploadify/7/8/4/784dc229800b3f940e7dfda4ec9967b3.jpg и при просмотре этого меню например с телефона, меню занимает большую часть экрана.И если для главной страницы (index.html) можно и нужно все так оставить, то для других это не подходит т.к много контента.) Можно ли сделать чтобы за место этих пунктов при просмотре с телефона, была например одна кнопка «Меню» по центру, при клике на которую открывалось само МЕНЮ? (например вот так itchief.ru/assets/uploadify/c/3/2/c327dec0545f4779e4aeb8a9b7fc1b8a.jpg)? Либо есть какой-нибудь другой, простой и эффективный способ? Не понимаю как это реализовать…
Спасибо Вам!)
Эту задачу можно решить так (открыть пример):
.accordion-item-header-count {
position: absolute;
top: 50%;
right: 10px;
width: 24px;
height: 24px;
transform: translateY(-50%);
text-align: center;
background: rgba(255, 255, 255, .8);
color: #000;
line-height: 24px;
border-radius: 12px;
Вы просто забыли html код аккордеона обернуть в элемент:
Ссылка: codepen.io/itchief/pen/VwjwNEO
codepen.io/man129/pen/YzWKZBw
На сайте имеется статья про абсолютный путь в PHP. Изучите её внимательно, и у вас всё получится.
Подскажите как можно решить эту проблему, пытаюсь создать многостраничный сайт, в нем постоянно на всех страницах будет одинаковое меню и и подвал.Собственно чтобы не вносить изменения в меню на каждой странице решил познакомиться с php. и так возникла проблема.)
Как сделать так, чтобы php работал, в случае когда к примеру есть пункт в меню Contact.php и тд ( а таких файлов штук 30) они находится в другой папке, т.е не рядом с nav.php(навигация сайта) и index.php.К примеру я перехожу с навигации в contact.php просто указывая пусть road/contact.php (так и указан путь в nav.php) и когда я уже на этой странице еще раз выбираю пункт в меню contact.php то вылезает ошибка что путь неправильный… Поскольку относительно contact.php путь до файла будет проще, просто contact.php.....? Как правильно все сделать в этом случае? Понимаю тяжело для понимания, но все же…
Спасибо!
КАТАЛОГ ТОВАРОВ
-Раздел каталога 1
--Подраздел каталога 1
--Подраздел каталога 1
-Раздел каталога 2
--Подраздел каталога 2
--Подраздел каталога 2
Как усовершенствовать?
1. JavaScript сценарий как в тексте статьи — itchief.ru/examples/lab.php?topic=javascript&file=accordion-5
2. Переработанный JavaScript сценарий (на прототипах) — itchief.ru/examples/lab.php?topic=javascript&file=accordion-4
Т.е разместить в принципе в две колонки не проблема, с помощью row и col-sm можно, но работает при этом он не так как надо. Например, в одной колонке 5 блоков и в другой 5 блоков, при открытии например блока с левой стороны, открывается блок и в правой колонке, что в принципе не так. Как сделать чтобы открытие вкладки в одной колонке, не влияло на соседнюю колонку. Вот пример как должно работать — Аккордеон в две колонки, но там один скрипт и ничего более