Аккордеон — список заголовков, каждый раскрывается вниз. Табы — ряд вкладок, из которых видна одна. Задача общая: показать сразу столько, сколько человек может охватить взглядом. Но делаются они по-разному, и аккордеон — редкий случай, когда писать вообще ничего не нужно.

Что из двух брать

Когда какой блок уместен
Блок Когда подходит Сколько кода
Аккордеон Вопросы и ответы, подробности, которые нужны не всем. Открыто может быть несколько разделов сразу Нисколько: готовые теги
Табы Равнозначные варианты одного и того же: цены для трёх тарифов, код для трёх языков Около двадцати строк

Прятать важное нельзя

Всё, что закрыто, для половины читателей не существует: они не щёлкают. Под аккордеон уходят подробности, а не суть. И поиск браузера по странице (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
  • На узком экране вместо ряда вкладок работает аккордеон