Аккордеон (Accordion)
Серия разворачивающихся / сворачивающихся панелей контента.

Основные данные
Основной ресурс откуда взята информация - https://ebay.gitbook.io/mindpatterns/disclosure/accordion
Каждая панель аккордеона отделена интерактивным заголовком панели, которую в любой момент можно открыть.
Часто используется в боковых панелях и меню навигации для постепенного раскрытия ссылок и фильтров.
Хорошая статья с примерами настройки и применения <details>
: https://habr.com/ru/post/477520/
Очень много примеров <details>
использования с кодом: https://freefrontend.com/html-details-summary-css/
Терминология
accordion: шаблон в целом, состоящий из следующих частей
panel: каждая панель в аккордеоне - это виджет раскрытия деталей
header: заголовок, который отображает интерактивную сводку содержимого панели
heading: заголовок, который находится внутри элемента и отражает суть панели
auto-collapse: свойство аккордеона, при котором автоматически сворачиваются открытые панели при открытии новой панели
Лучшая практика
Каждый заголовок (header) находится в естественном индексе табуляции. Этот естественный tabindex нельзя удалять или изменять.
По умолчанию все панели могут быть в открытом, развернутом состоянии.
При желании аккордеон может быть ограничен отображением только одной панели содержимого за раз (т.е. открытие панели закроет любую другую открытую панель). Это называется автоматически сворачивающимся аккордеоном.
Интерактивный дизайн
Управление клавиатурой
Нажатие клавиши TAB
должно перемещать фокус клавиатуры с одного заголовка на другой. Он также будет перемещать фокус через любые интерактивные элементы внутри открытых панелей.
Точно так же нажатие клавиш SHIFT-TAB
перемещает фокус назад по заголовкам и содержимому интерактивной панели.
Нажатие клавиши ПРОБЕЛ
или ВВОД
в заголовке с фокусом клавиатуры должно открывать панель. Для автоматического сворачивания аккордеонов любая другая открытая панель должна закрываться.
Screenreader
Виртуальный курсор должен иметь возможность перемещаться от одного заголовка к другому.
С виртуальным курсором на заголовке, он должен иметь возможность открывать панель с помощью имитации события щелчка. Для аккордеонов с автоматическим сворачиванием любая другая открытая панель должна закрываться, но об этом не следует объявлять.
Код
В шаблоне «аккордеон» активно используется тег "details" HTML. Старые браузеры, включая IE11 и Edge, изначально не поддерживают тег сведений, поэтому требуют полифилла.
При использовании details нет возможности анимировать открытие
HTML-элемент <details>
используется для раскрытия скрытой (дополнительной) информации.
Виджет раскрытия обычно представлен на экране с использованием небольшого треугольника, который поворачивается, чтобы показать состояние открытия / закрытия, с меткой рядом с треугольником. Если первый дочерний элемент элемента <details>
является <summary>
, содержимое элемента <summary>
используется в качестве метки для виджета раскрытия.
<ul class="accordion" role="list" aria-roledescription="accordion">
<li>
<details class="accordion__details" open>
<summary><h4>Buying</h4></summary>
<ul>
<li><a href="http://www.ebay.com">Purchases</a></li>
<li><a href="http://www.ebay.com">Bids/Offers</a></li>
<li><a href="http://www.ebay.com">Didn't Win</a></li>
</ul>
</details>
</li>
<li>
<details class="accordion__details">
<summary><h4>Selling</h4></summary>
<ul>
<li><a href="http://www.ebay.com">Sold</a></li>
<li><a href="http://www.ebay.com">Bids/Offers</a></li>
<li><a href="http://www.ebay.com">Didn't Swell</a></li>
</ul>
</details>
</li>
</ul>
Обратите внимание, что в некоторых браузерах роль неявного списка удаляется, когда применяется CSS list-style-type: none, поэтому мы применили role = list в нашей разметке, чтобы гарантировать явную роль.
CSS
Для смены стандартного треугольника раскрытия:
summary { list-style-image: url(right-arrow.svg); }
summary::-webkit-details-marker { background: url(right-arrow.svg); color: transparent; }
Анимация раскрытия:
details[open] summary ~ * {
animation: sweep .5s ease-in-out;
}
@keyframes sweep {
0% {opacity: 0; margin-left: -10px}
100% {opacity: 1; margin-left: 0px}
}
JavaScript
Тэг details
требует polyfill для браузеров которые не поддерживают его нативно.
Код для загрузки полифила только для ие:
<script type="text/javascript">
if(/MSIE \d|Trident.*rv:/.test(navigator.userAgent))
document.write('<script src="somescript.js"><\/script>');
</script>
Основной код указан выше и служит для того, что бы закрывать открытую вкладку при выборе новой.
Код (с возможность анимации)
<ul class="services__list" role="list" aria-roledescription="accordion">
<li class="services__details">
<button class="btn services__summary" aria-expanded="false">
<h3 class="services__header">Заголовок</h3>
<span class="services__icon"></span>
</button>
<div class="services__content" aria-hidden="true">
<p class="services__text">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Praesentium, quod.</p>
</div>
</li>
<li class="services__details">
<button class="btn services__summary" aria-expanded="false">
<h3 class="services__header">Заголовок</h3>
<span class="services__icon"></span>
</button>
<div class="services__content" aria-hidden="true">
<p class="services__text">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Praesentium, quod.</p>
</div>
</li>
</ul>
&__content {
opacity: 0;
max-height: 0;
will-change: max-height;
overflow: hidden;
transition: opacity, max-height 0.3s ease-out;
box-sizing: content-box;
}
&__content[aria-hidden="false"]{
opacity: 1;
padding: 10px 10px;
}
/**
* Аккордеон с анимацией (через button)
* el - класс аккордеона
* closeAll - определят, требуется ли закрывать остальные вкладки при открытии
*/
class AccordionBtn {
constructor(el, closeAll = false) {
this.accrdion = document.querySelector(el);
this.closeAll = closeAll;
if (!this.accrdion) {
console.error(`Не найден аккордеон - ${el}!`);
return;
}
this.init();
}
init() {
this.accItmesBtns = this.accrdion.querySelectorAll("button[aria-expanded]");
if (!this.accItmesBtns) console.error("Не найдены кнопки содержащие аттрибут aria-expanded");
this.accItmesBtns.forEach((itemBtn) => {
itemBtn.addEventListener("click", (e) => {
const btn = e.currentTarget;
const openBtn = btn.getAttribute("aria-expanded") === "true" ? true : false;
if (this.closeAll) {
this.showOne(btn);
}
const context = btn.nextElementSibling;
if (!context || !context.hasAttribute("aria-hidden")) console.error("Не найден блок с контентом содержащий аттрибут aria-hidden");
const openContext = context.getAttribute("aria-hidden") === "true" ? true : false;
const heightContext = context.style.maxHeight === "" || context.style.maxHeight === "0px" ? context.scrollHeight : 0;
btn.setAttribute("aria-expanded", !openBtn);
context.setAttribute("aria-hidden", !openContext);
context.style.maxHeight = heightContext + "px";
});
});
}
showOne(btn) {
this.accItmesBtns.forEach((itemBtn) => {
if (itemBtn !== btn) {
itemBtn.setAttribute("aria-expanded", "false");
if (itemBtn.nextElementSibling.hasAttribute("aria-hidden")) {
itemBtn.nextElementSibling.setAttribute("aria-hidden", "true");
itemBtn.nextElementSibling.style.maxHeight = "0px";
}
}
});
}
}
ARIA
aria-roledescription: определяет удобочитаемое, локализованное для автора описание роли элемента. В данном случае «аккордеон».
Last updated
Was this helpful?