Как создать вертикальный аккордеон для сайта

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

HTML код аккордеона и его описание
HTML-разметка аккордеона:
<div class="accordion">
<div class="accordion__item accordion__item_show">
<div class="accordion__header">
Заголовок 1
</div>
<div class="accordion__body">
Содержимое 1
</div>
</div>
<div class="accordion__item">
<div class="accordion__header">
Заголовок 2
</div>
<div class="accordion__body">
Содержимое 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 {
margin-bottom: 0.5rem;
border-radius: 0.25rem;
box-shadow: 0 0.125rem 0.25rem rgb(0 0 0 / 15%);
}
.accordion__header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.75rem 1rem;
color: #fff;
font-weight: 500;
background-color: #0d6efd;
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
cursor: pointer;
transition: background-color 0.2s ease-out;
}
.accordion__header::after {
flex-shrink: 0;
width: 1.25rem;
height: 1.25rem;
margin-left: auto;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ffffff'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-size: 1.25rem;
content: "";
}
.accordion__item_show .accordion__header::after {
transform: rotate(-180deg);
}
.accordion__header:hover {
background-color: #0b5ed7;
}
.accordion__item_hidden .accordion__header {
border-bottom-right-radius: 0.25rem;
border-bottom-left-radius: 0.25rem;
}
.accordion__body {
padding: 0.75rem 1rem;
overflow: hidden;
background: #fff;
border-bottom-right-radius: 0.25rem;
border-bottom-left-radius: 0.25rem;
}
.accordion__item:not(.accordion__item_show) .accordion__body {
display: none;
}
Данный код выполняет стилизацию элементов аккордеона, добавляет к ним необходимые внутренние отступы, цвет текста, цвет фона и др. Но, кроме этого, он ещё определяет видимость элементов аккордеона с классом accordion-item-content
, т.е. содержимого.
По умолчанию элементы, имеющие класс accordion-item-content
не отображаются (CSS свойство display
равно значению none
). Включение отображения определённого элемента (accordion-item-content) осуществляется посредством класса show
, который необходимо добавить к его родительскому элементу (accordion-item).
JavaScript код аккордеона
Сценарий (логика) аккордеона:
class ItcAccordion {
constructor(target, config) {
this._el = typeof target === 'string' ? document.querySelector(target) : target;
const defaultConfig = {
alwaysOpen: true
};
this._config = Object.assign(defaultConfig, config);
this.addEventListener();
}
addEventListener() {
this._el.addEventListener('click', (e) => {
const elHeader = e.target.closest('.accordion__header');
if (!elHeader) {
return;
}
if (!this._config.alwaysOpen) {
const elOpenItem = this._el.querySelector('.accordion__item_show');
if (elOpenItem) {
elOpenItem !== elHeader.parentElement ? elOpenItem.classList.toggle('accordion__item_show') : null;
}
}
elHeader.parentElement.classList.toggle('accordion__item_show');
});
}
}
Сценарий JavaScript выполняет очень простые действия. Он добавляет обработчик события click
для аккордеона. Далее в зависимости от того по какому заголовку кликнули, он добавляет и (или) удаляет класс show
у необходимых(ого) элементов(а).
Инициализация элемента как аккордеон выполняется следующим образом:
new ItcAccordion(document.querySelector('.accordion'), {
alwaysOpen: false
});
Аккордеон с анимацией скольжения
Скриншот аккордеона, появление содержимого которого сопровождается CSS анимацией:

Стили аккордеона, включающие в себя анимацию (для отображения содержимого): animated-accordion.css.
JavaScript: animated-accordion.js
Вертикальное меню аккордеон
Пример настройки аккордеона в качестве вертикального меню.
Дополнительно в JavaScript сценарий добавим небольшой фрагмент кода, который будет показывать сколько подпунктов имеет каждый пункт в этом меню.

HTML структура:
<div class="accordion">
<div class="accordion__item">
<div class="accordion__header">
Заголовок 1
</div>
<div class="accordion__body">
<div class="accordion__content">
<a href="#">Пункт 1.1</a>
<a href="#">Пункт 1.2</a>
<a href="#">Пункт 1.3</a>
</div>
</div>
</div>
<div class="accordion__item">
<div class="accordion__header">
Заголовок 2
</div>
<div class="accordion__body">
<div class="accordion__content">
<a href="#">Пункт 2.1</a>
<a href="#">Пункт 2.2</a>
</div>
</div>
...
</div>
Файлы:
- CSS: menu-accordion.css;
- JavaScript: animated-accordion.js.
Многоуровневое меню аккордеон
Пример в котором рассмотрим как создать многоуровневое вертикальное меню аккордеон.

HTML, CSS и JavaScript код многоуровневого меню:
<div class="accordion">
<div class="accordion__item">
<div class="accordion__header">
Заголовок 1
</div>
<div class="accordion__body">
<div class="accordion__content">
<a href="#">Пункт 1.1</a>
<div class="accordion__item">
<div class="accordion__header">
Пункт 1.2
</div>
<div class="accordion__body">
<div class="accordion__content">
<a href="#">Пункт 1.2.1</a>
<a href="#">Пункт 1.2.2</a>
<div class="accordion__item">
<div class="accordion__header">
Пункт 1.2.3
</div>
<div class="accordion__body">
<div class="accordion__content">
<a href="#">Пункт 1.2.3.1</a>
<a href="#">Пункт 1.2.3.2</a>
<a href="#">Пункт 1.2.3.3</a>
</div>
</div>
</div>
<a href="#">Пункт 1.2.4</a>
<a href="#">Пункт 1.2.5</a>
</div>
</div>
</div>
<a href="#">Пункт 1.3</a>
</div>
</div>
</div>
...
</div>
Файлы:
- CSS: multilevel-accordion.css;
- JavaScript: animated-accordion.js.
Подскажите пожалуйста, как сделать, чтобы по умолчанию, была открыта только верхняя вкладка аккордеона?
Сейчас они все сразу открыты.
Очень интересна Ваша разработка «Многоуровневое вертикальное меню аккордеон».
А можно ли сделать так, чтобы изначально меню не было видно, но на странице была ссылка «Меню», по клику на которую меню бы появлялось ниже этой ссылки? А если кликнуть на «Меню» еще раз, или на пространство вне развернутого меню, оно бы закрывалось.
И очень важно, чтобы раскрывшееся меню ложилось поверх имеющегося текста страницы.
Возможно такое?
Замените этот код на следующий:
lana-caps.ru/opt
Снова нужна ваша помощь!..) В процессе работы представленного меню возникла след. проблема.
Когда впервые заходишь на сайт пункты меню не нажимаются и ни каким образом не раскрываются. Если я обновляю страницу, то все начинает работать как надо (начинают раскрываться пункты). Происходит не каждый раз, а через раз… Помогите пожалуйста победить эту проблему!) Вот сам сайт, где происходит этот баг.
Вот ссылка на полный код js ---> codepen.io/man129/pen/LYjJNZR
Фото проблемы в консоли --->
itchief.ru/assets/uploadify/b/7/7/b77bbf88d5f0ed976ece28d9c8cf24b5.png
itchief.ru/assets/uploadify/5/f/9/5f9e7f1b09eb1d1e6d859017fcd1ebd9.png
Спасибо! =)
Использую представленное аккордеон меню ---> codepen.io/man129/pen/GRmBXvy, само меню работает отлично. Но в при уменьшении окна браузера пункты меню начинаю как бы "слипаться", т.е margin, как бы сходит на нет (пример в фото ниже), в не зависимости от браузера. Не могли бы вы подсказать из-за чего так происходит ну или показать как это можно исправить?)
Спасибо! =)
itchief.ru/assets/uploadify/4/2/c/42cab2abd7dcdbaafab790341d61ab81.jpg
Размеры, которые мы устанавливаем в CSS являются виртуальными, не зависящимися от экрана. Например, 1px в CSS может занимать как один физический пиксель, так и четыре (на Retina дисплеях). Физический пиксель — это самый мелкий элемент дисплея.
Когда изменяешь масштаб в браузере, например, устанавливаешь его на 90%, то 1 пиксель в CSS должен как-то отобразиться на экране. Он же не может занять часть физического пикселя. Браузер это процесс рассчитывает и получается, что в одних местах он занимает 1 физический пиксель, а в других ничего.
Как вариант, это установить больший размер:
единственный недостаток — Инициализация элемента как аккордеон к каждому экземпляру 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)? Либо есть какой-нибудь другой, простой и эффективный способ? Не понимаю как это реализовать…
Спасибо Вам!)
Эту задачу можно решить так (открыть пример):
codepen.io/itchief/pen/xxEKJVy
Но, в очередной раз возник вопрос, реально ли в этом примере сделать так, чтобы для главной страницы меню не сворачивалось в одну кнопку «Меню», а оставалось раскрытым, а для других оставить так как есть (в свернутом варианте). Ни как не могу придумать как это реализовать в вашем примере. Может вы сможете помочь — показать, как это реализовать с минимальным ущербом?
Если можно, то просто добавьте класс show на главной странице:
Если у вас шаблон одинаковый и просто добавить класс не получится, то тогда можно так:
Задача для главной страницы сделать так (другие оставить без изменения), чтобы на крупных разрешениях меню осталось неизменным, а именно таким ( itchief.ru/assets/uploadify/9/f/b/9fbecc7cc846489633ed0758426c423c.jpg ). А при мобильном просмотре (с 991px) в данный момент оно такое ( itchief.ru/assets/uploadify/3/5/f/35f31ea58e7759ccab86db51bf71fc34.jpg ) т.е есть кнопка «Меню» и оно свернуто. Сделать так чтобы были видны пункты, а именно -> itchief.ru/assets/uploadify/9/7/6/9761921b0c950ce250657d1b095bac04.jpg.
P.S Как вы и сказали добавил div, но все пункты стали развернуты на большых экранах ( itchief.ru/assets/uploadify/1/4/2/1422517978099d46f983adf007d0a70a.jpg ) и не изменными на маленьких ( itchief.ru/assets/uploadify/3/5/f/35f31ea58e7759ccab86db51bf71fc34.jpg ). Добавлял таким способом: Просто обернув все меню в div class=«accordion-item show».
Java код вообще не сработал… По идее просто вставил его в конце кода и тишина. В меню я ни чего не менял, все как вы мне подсказали так и оставил. По факту как у вас на codepen.io/itchief/pen/xxEKJVy так и у меня.
Если возможно это реализовать очень прошу помогите!) Заранее Благодарю! =)
Уже практически рад, что так работает, но чтобы вообще классно было, можете подсказать, сильно ли тяжело будет эту кнопку «Меню убрать», либо же сделать ее не активной для главной страницы? Если вам будет не тяжело сможете показать?
Реально, очень мне помагаете, Спасибо вам за это!)
itchief.ru/assets/uploadify/2/a/6/2a661f525b1b0792143efcc985d8f34e.jpg
Можно просто добавить в стили главной страницы:
После этого в CSS уже можно вставлять стили, которые будут применяться для главной страницы, т.к. на других такого класса нет:
.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 блоков, при открытии например блока с левой стороны, открывается блок и в правой колонке, что в принципе не так. Как сделать чтобы открытие вкладки в одной колонке, не влияло на соседнюю колонку. Вот пример как должно работать — Аккордеон в две колонки, но там один скрипт и ничего более