Раскрывающийся блок через details и summary
Оберните содержимое в <details> и поставьте первым <summary>. Summary остается видимой; все остальное скрыто, пока читатель по ней не кликнет:
Кликните по вопросу, чтобы открыть его, и еще раз, чтобы закрыть. Браузер добавляет треугольный маркер, делает summary доступной для фокуса, переключает ее по Enter или Space и сообщает программам чтения с экрана, развернута она или свернута. JavaScript здесь не участвует.
Если не указать <summary>, браузер покажет вместо нее подпись по умолчанию («Details» на английском).
Открыт по умолчанию
Логический атрибут open показывает содержимое с самого начала. Браузер добавляет и удаляет open, когда читатель переключает блок, поэтому за него же удобно цепляться в стилях:
У открытого блока синяя рамка от details[open]. Откройте «Returns», и он тоже станет синим; открытыми одновременно могут быть оба.
Аккордеон: открыт только один
Дайте нескольким элементам <details> одинаковый name, и они станут исключающей группой: открытие одного закрывает остальные. Раньше для этого требовался JavaScript, а теперь в современных Chrome, Edge, Firefox и Safari хватает одного атрибута:
Откройте второй вопрос, и первый закроется. Уберите атрибуты name, и они снова будут открываться независимо. Исключающий аккордеон скрывает содержимое, которое читатель может захотеть сравнить, поэтому используйте его, когда разделы это альтернативы, а обычные <details>, когда людям может понадобиться открыть несколько.
Оформление маркера
Треугольник это маркер списка у summary. list-style: none его убирает (правило ::-webkit-details-marker нужно для Safari), а псевдоэлемент может нарисовать собственный индикатор:
Плюс поворачивается на 45 градусов и превращается в крестик, когда раздел открывается. Сохраняйте видимый стиль фокуса, как обводку :focus-visible здесь: когда стандартный маркер убран, пользователи клавиатуры ориентируются по рамке фокуса.
Событие toggle и свойство open
JavaScript может читать и задавать details.open, а событие toggle срабатывает после каждого изменения, чем бы оно ни было вызвано: кликом, клавишей или скриптом:
«Expand all» задает open обоим, а журнал показывает последнее событие toggle. Событие не всплывает, поэтому слушайте его у каждого <details>, а не у родителя.
Что можно положить в summary
Summary содержит текст, строчные элементы или заголовок, если название раздела должно входить в структуру страницы:
<details>
<summary><h3>Refund policy</h3></summary>
<p>...</p>
</details>
Избегайте ссылок, кнопок и полей формы внутри <summary>: summary сама уже элемент управления, поэтому элемент управления внутри нее легко пропустить или задеть по ошибке, а программы чтения с экрана плохо объявляют вложенные элементы управления. Интерактивное содержимое ставьте в тело <details>.
Частые ошибки
- Переключатель из
<div>и JavaScript.<details>уже обрабатывает клики, клавиши и состояние для программ чтения с экрана. Когда действительно нужен свой переключатель, используйте кнопку сaria-expanded. <summary>не на первом месте. Она должна быть первым дочерним элементом<details>.- Маркер скрыт без замены. Дайте читателям какой-то знак, что summary раскрывается, например плюс, как выше.
- Скрытие содержимого через
display. Переключайтеopen; CSS, который принудительно показывает или скрывает содержимое, конфликтует с состоянием браузера. - Исключающие группы для содержимого, которое сравнивают. Используйте
name, только когда один открытый раздел за раз имеет смысл.
Часто задаваемые вопросы
Что делают details и summary в HTML?
<details> создает раскрывающийся виджет: раздел, который можно открыть и закрыть. Его первый дочерний элемент, <summary>, это всегда видимая подпись; клик по ней (или Enter либо Space, когда она в фокусе) показывает или скрывает все остальное внутри <details>.
Как сделать details открытым по умолчанию?
Добавьте логический атрибут open: <details open>. Браузер добавляет и удаляет этот атрибут, когда пользователь переключает блок, поэтому CSS может оформлять details[open].
Как сделать аккордеон, где открыт только один раздел?
Дайте всем <details> в группе одинаковый атрибут name, например name="faq". Открытие одного закрывает остальные в этой группе, без JavaScript.
Как убрать или изменить стрелку у summary?
Задайте summary значение list-style: none и добавьте summary::-webkit-details-marker { display: none; } для Safari. Затем нарисуйте свой индикатор, например через summary::after, и меняйте его через details[open] summary::after.
Можно ли узнать, когда details открывается?
Да. Слушайте событие toggle у элемента <details> и читайте его свойство open. Присваивание details.open = true в JavaScript открывает его.