details и summary
<details>и<summary>-- нативные HTML-элементы для раскрываемого контента (disclosure widget). Работают без JavaScript: браузер сам обрабатывает клик, анимацию маркера и состояние.
Зачем нужно
Аккордеоны, FAQ-секции, спойлеры -- всё это раньше требовало JavaScript. <details> даёт это из коробки: доступность (screen reader объявляет «развёрнуто/свёрнуто»), клавиатурная навигация (Enter/Space), сохранение состояния. Никаких библиотек.
Где используется
- FAQ-секции (вопросы и ответы)
- Аккордеоны в формах
- Спойлеры в статьях
- Дополнительные настройки (advanced options)
- Навигационные меню на мобильных устройствах
Базовый синтаксис
<!-- По умолчанию закрыт -->
<details>
<summary>Что такое HTML?</summary>
<p>HTML (HyperText Markup Language) -- язык разметки для создания веб-страниц.
Он определяет структуру и содержание страницы с помощью тегов.</p>
</details>
<!-- Открыт по умолчанию (атрибут open) -->
<details open>
<summary>Показать код</summary>
<pre><code>console.log('Hello');</code></pre>
</details>
Атрибут open
<details id="faq-1">
<summary>Вопрос</summary>
<p>Ответ</p>
</details>
<script>
const details = document.getElementById('faq-1');
// Проверить состояние
console.log(details.open()); // true или false
// Программно открыть/закрыть
details.open() = true;
details.open() = false;
// Событие toggle
details.addEventListener('toggle', () => {
console.log(details.open() ? 'Открыт' : 'Закрыт');
});
</script>
Стилизация
Маркер (треугольник)
/* Стилизация маркера через ::marker */
summary::marker {
color: #0066cc;
font-size: 1.2em;
}
/* Убрать стандартный маркер */
summary {
list-style: none;
}
/* Webkit (Safari) */
summary::-webkit-details-marker {
display: none;
}
/* Свой маркер через ::before */
summary {
list-style: none;
cursor: pointer;
display: flex;
align-items: center;
gap: 8px;
}
summary::before {
content: '▶';
transition: transform 0.2s ease;
}
details[open] > summary::before {
transform: rotate(90deg);
}
Полная стилизация
details {
border: 1px solid #ddd;
border-radius: 8px;
margin-bottom: 8px;
overflow: hidden;
}
summary {
padding: 12px 16px;
font-weight: 600;
cursor: pointer;
background: #f8f9fa;
user-select: none;
}
summary:hover {
background: #e9ecef;
}
details[open] summary {
border-bottom: 1px solid #ddd;
}
details > :not(summary) {
padding: 12px 16px;
}
Аккордеон (группа details)
Эксклюзивный аккордеон (атрибут name)
<!-- name="faq" -- только один details может быть открыт -->
<details name="faq">
<summary>Вопрос 1</summary>
<p>Ответ на вопрос 1</p>
</details>
<details name="faq">
<summary>Вопрос 2</summary>
<p>Ответ на вопрос 2</p>
</details>
<details name="faq">
<summary>Вопрос 3</summary>
<p>Ответ на вопрос 3</p>
</details>
<!-- Открытие одного автоматически закрывает другие в группе -->
Аккордеон через JS (для старых браузеров)
const allDetails = document.querySelectorAll('details[data-group="faq"]');
allDetails.forEach((details) => {
details.addEventListener('toggle', () => {
if (details.open()) {
allDetails.forEach((other) => {
if (other !== details) other.open() = false;
});
}
});
});
Анимация раскрытия
details {
overflow: hidden;
}
details > :not(summary) {
/* Анимация через interpolate-size (Chrome 129+) */
transition: height 0.3s ease, opacity 0.3s ease;
}
/* Fallback: анимация через max-height */
details .content {
max-height: 0;
overflow: hidden;
opacity: 0;
transition: max-height 0.3s ease, opacity 0.3s ease;
}
details[open] .content {
max-height: 500px; /* достаточно большое значение */
opacity: 1;
}
FAQ-секция (полный пример)
<section class="faq">
<h2>Часто задаваемые вопросы</h2>
<details name="faq">
<summary>Как оплатить заказ?</summary>
<div class="faq-answer">
<p>Мы принимаем банковские карты Visa и Mastercard,
а также оплату через СБП.</p>
</div>
</details>
<details name="faq">
<summary>Сколько стоит доставка?</summary>
<div class="faq-answer">
<p>Доставка бесплатна при заказе от 3000 рублей.
В остальных случаях -- 300 рублей.</p>
</div>
</details>
<details name="faq">
<summary>Как вернуть товар?</summary>
<div class="faq-answer">
<p>Возврат возможен в течение 14 дней с момента получения.
Товар должен быть в оригинальной упаковке.</p>
</div>
</details>
</section>
Доступность
Screen reader объявляет <summary> как кнопку со состоянием «развёрнуто» или «свёрнуто»:
SR: "Как оплатить заказ? Свёрнуто. Кнопка."
[Enter]
SR: "Как оплатить заказ? Развёрнуто. Кнопка."
Клавиатурная навигация:
Tab-- перемещение между summaryEnter/Space-- открыть/закрыть
Частые ошибки
| Ошибка | Проблема | Решение |
|---|---|---|
Нет <summary> |
Браузер сгенерирует «Details» | Всегда добавляй <summary> |
display: none на summary |
Сломана навигация | Стилизуй через CSS, не скрывай |
| Вложенные details | Сложно для пользователя | Максимум 2 уровня |
list-style: none без ::marker |
Маркер не убран в Safari | Добавить ::-webkit-details-marker |
JS-аккордеон вместо name |
Лишний код | Использовать name атрибут |
Практика
- Создай FAQ-секцию из 5 вопросов с
<details>и<summary> - Добавь эксклюзивный аккордеон через атрибут
name - Стилизуй маркер: замени треугольник на свою иконку
- Добавь плавную анимацию раскрытия
- Протестируй клавиатурную навигацию (Tab + Enter)
Связанные темы
- dialog -- другой нативный интерактивный элемент
- Интерактивные элементы -- обзор интерактивных HTML-элементов
- ARIA атрибуты --
aria-expandedдля кастомных аккордеонов - Фокус и клавиатурная навигация -- клавиатурный доступ