Аккордеон — список заголовков, каждый раскрывается вниз. Табы — ряд вкладок, из которых видна одна. Задача общая: показать сразу столько, сколько человек может охватить взглядом. Но делаются они по-разному, и аккордеон — редкий случай, когда писать вообще ничего не нужно.
Что из двух брать
| Блок | Когда подходит | Сколько кода |
|---|---|---|
| Аккордеон | Вопросы и ответы, подробности, которые нужны не всем. Открыто может быть несколько разделов сразу | Нисколько: готовые теги |
| Табы | Равнозначные варианты одного и того же: цены для трёх тарифов, код для трёх языков | Около двадцати строк |
Прятать важное нельзя
Всё, что закрыто, для половины читателей не существует: они не щёлкают. Под аккордеон уходят подробности, а не суть. И поиск браузера по странице (Ctrl + F) в закрытых блоках не работает — это ещё одна причина не прятать то, что ищут.
Аккордеон: два тега и ничего больше
Теги <details> и <summary>
дают раскрывающийся блок сами. Браузер берёт на себя щелчок,
Enter и Пробел, состояние для программ чтения экрана
и треугольник-указатель.
<details class="accordion__item">
<summary class="accordion__head">Сколько стоит сделать сайт самому</summary>
<div class="accordion__body">
<p>Домен — около 200 рублей в год, хостинг — от 150 рублей в месяц.</p>
</div>
</details>
<!-- открыт при загрузке страницы -->
<details class="accordion__item" open> … </details>
Скрипт нужен ровно в одном случае: если требуется, чтобы
открытым оставался только один раздел. Тогда при открытии
одного <details> у остальных снимается
атрибут open — это четыре строки.
Треугольник можно нарисовать свой
Стандартный указатель убирается правилом
summary { list-style: none } — и рядом
рисуется свой значок. Только не убирайте его совсем:
закрытый блок должен быть виден как закрытый, иначе
заголовок читается как обычный текст.
Табы: три связи между кнопкой и панелью
У табов готового тега нет, и почти вся работа — не в переключении, а в атрибутах. Кнопка вкладки и её панель связываются тремя нитями, и каждая нужна программе чтения экрана.
<div class="tabs">
<div class="tabs__list" role="tablist" aria-label="Способы установки">
<button class="tabs__tab" type="button" role="tab"
id="tab-win" aria-controls="panel-win" aria-selected="true">
Windows
</button>
<button class="tabs__tab" type="button" role="tab"
id="tab-mac" aria-controls="panel-mac" aria-selected="false" tabindex="-1">
macOS
</button>
</div>
<div class="tabs__panel" role="tabpanel" id="panel-win" aria-labelledby="tab-win">…</div>
<div class="tabs__panel" role="tabpanel" id="panel-mac" aria-labelledby="tab-mac" hidden>…</div>
</div>
Странный на вид tabindex="-1" у неактивных
вкладок — это не ошибка, а правило. В ряду вкладок Tab
не ходит: он попадает на активную вкладку и следующим
нажатием уходит дальше по странице, а между вкладками
переключаются стрелками. Так устроены табы во всех
операционных системах.
function select(tab) {
tabs.forEach((t) => {
const on = t === tab;
t.setAttribute('aria-selected', String(on));
t.tabIndex = on ? 0 : -1; // в обходе только активная
document.getElementById(t.getAttribute('aria-controls')).hidden = !on;
});
tab.focus();
}
list.addEventListener('keydown', (event) => {
const i = tabs.indexOf(document.activeElement);
if (event.key === 'ArrowRight') select(tabs[(i + 1) % tabs.length]);
if (event.key === 'ArrowLeft') select(tabs[(i - 1 + tabs.length) % tabs.length]);
});
Что попросить у нейросети
Напиши скрипт табов на чистом JavaScript, без библиотек.
Разметка: контейнер с role="tablist", внутри
кнопки с role="tab", у каждой
aria-controls с номером панели; панели
с role="tabpanel", неактивные скрыты
атрибутом hidden.
Нужно: щелчок переключает вкладку; стрелки влево-вправо
переходят к соседней и зацикливаются; Home и End — первая
и последняя; в обходе по Tab участвует только активная
вкладка, остальным ставится tabindex="-1".
Скрипт должен находить все группы табов на странице и работать с каждой отдельно. На узком экране табы должны превращаться в аккордеон — подскажи, как это сделать честно, не ломая атрибуты. Комментарии по-русски.
Про переключение стрелкой. Есть два принятых поведения: вкладка открывается сразу при переходе стрелкой или только по Enter. Первое удобнее, если панели лёгкие; второе — если в панели что-то грузится. Я сделал первое, оно привычнее.
Про превращение в аккордеон. Честного
способа сделать это одним CSS нет: у табов и аккордеона
разные роли и разные атрибуты, а роль нельзя поменять
стилями. Работающий путь — пересобирать разметку скриптом
при смене ширины, отслеживая её через
matchMedia.
Но проще так не делать. На узком экране
надёжнее сразу выводить аккордеон на
details, а табы показывать с 768 пикселей.
Меньше кода, нечему разъезжаться, и работает без
JavaScript. Пересборка разметки при каждом повороте
телефона — источник ошибок, а выигрыш нулевой.
В Evolution CMS: содержимое вкладок из чанков
Разметка табов в шаблоне остаётся как есть — меняется только то, что внутри панелей. Если вкладки одни и те же на всём сайте, каждая панель становится чанком, и редактор правит текст, не видя ни атрибутов, ни скриптов.
<div class="tabs__panel" role="tabpanel" id="panel-win" aria-labelledby="tab-win">
{{ustanovkaWindows}}
</div>
Для блока «Вопросы и ответы» удобнее другое: вопросы —
ресурсы в отдельной папке, а DocLister собирает
из них аккордеон по чанку. Тогда новый вопрос добавляется
созданием страницы, а не правкой шаблона. Заодно к такому
блоку легко добавить микроразметку FAQPage,
и вопросы попадут прямо в поисковую выдачу.
Частые ошибки
| Ошибка | Чем плохо | Как правильно |
|---|---|---|
Аккордеон на div и скрипте |
Двадцать строк кода вместо готового тега, и без клавиатуры | details и summary |
Вкладки — ссылки или div |
Диктор не понимает, что это переключатель | button с role="tab" |
| Все вкладки в обходе по Tab | Десять вкладок — десять лишних остановок | В обходе активная, между вкладками — стрелки |
Панель спрятана через opacity |
Невидимый текст читается диктором и ищется поиском | Атрибут hidden |
| Под аккордеоном главный текст страницы | Половина читателей его не откроет и не найдёт поиском | Прятать подробности, а не суть |
Что должно получиться
- Аккордеон работает без JavaScript: щелчок, Enter и Пробел раскрывают раздел
- Вкладки переключаются щелчком и стрелками, Home и End работают
- В обходе по Tab одна вкладка, а не весь ряд
-
У активной вкладки
aria-selected="true", у её панели снятhidden - На узком экране вместо ряда вкладок работает аккордеон