---
title: "Как сделать аккордеон на HTML и CSS без JavaScript: элемент details"
description: "Как сделать аккордеон на HTML и CSS без JavaScript: элемент details, атрибут name для одного открытого пункта, своя стрелка, плавное раскрытие и поддержка браузеров."
url: https://penlab.space/blog/ru/accordion-details-html-css
language: ru
section: "Статьи"
published: 2026-10-12T15:56:43Z
updated: 2026-10-12T15:56:43Z
translation: https://penlab.space/blog/accordion-details-html-css
---

# Как сделать аккордеон на HTML и CSS без JavaScript: элемент details

Аккордеон собирается на элементе details: пункты раскрывает браузер, а атрибут name оставляет открытым один. Показываем код, свою стрелку, плавное раскрытие на CSS и поддержку браузеров.

Аккордеон на HTML и CSS делается без JavaScript на элементе `details`: заголовок пункта лежит в `summary`, скрытый текст идёт следом, а раскрывает пункт сам браузер. Чтобы одновременно оставался открытым только один пункт, всем `details` группы задаём одинаковый атрибут `name` (Chrome и Edge 120, Firefox 130, Safari 17.2). Плавное раскрытие добавляет CSS с `::details-content`, но высоту `auto` анимируют пока только Chrome и Edge: в остальных браузерах пункт раскрывается сразу.

## Коротко

- Пункт аккордеона - это `details` с `summary` первым ребёнком. Клик по `summary` открывает и закрывает пункт, скрипт не нужен.
- Пункт открыт, пока у `details` есть атрибут `open`. Другие пункты он не трогает.
- Одинаковый `name` у нескольких `details` собирает их в группу: открытие одного закрывает другой. Группа не требует, чтобы один пункт был открыт всегда: по клику на открытый пункт его можно закрыть.
- Стандартную стрелку убираем через `list-style: none` и `::-webkit-details-marker`, свою рисуем в `::after` у `summary`.
- Пункт управляется с клавиатуры: на `summary` переходим клавишей Tab, открываем и закрываем клавишами Enter и Пробел. Мы проверили это в Chrome 154.
- Плавное раскрытие даёт `::details-content` (Chrome и Edge 131, Firefox 143, Safari 18.4) вместе с `interpolate-size`, которое понимают только Chrome и Edge. Без него аккордеон работает так же, но без анимации.

## Как сделать аккордеон на details

Аккордеон - это список пунктов, у каждого есть заголовок, а текст под ним скрыт, пока пункт не открыт. В HTML такой пункт уже есть: элемент `details` скрывает всё содержимое, кроме `summary`, и показывает его после клика по заголовку.

```html
<details>
  <summary>Что такое аккордеон?</summary>
  <p>Список пунктов, у каждого заголовок и скрытый текст.</p>
</details>

<details>
  <summary>Нужен ли JavaScript?</summary>
  <p>Нет, пункты раскрывает сам браузер.</p>
</details>
```

`summary` ставим первым ребёнком `details`. Если его не будет, браузер подставит свою подпись, обычно «Details». Всё остальное внутри `details` - обычная разметка: абзацы, списки, ссылки, формы.

Пункт открыт, пока у `details` стоит булев атрибут `open`. Чтобы пункт был открыт при загрузке страницы, пишем `<details open>`. Браузер сам добавляет и убирает этот атрибут, когда пользователь кликает по заголовку. Чтобы закрыть пункт в разметке, атрибут убираем целиком: запись `open="false"` пункт откроет, потому что у булева атрибута значение не читается.

О каждом переключении сообщает событие `toggle`. Оно приходит после смены состояния, и если состояние поменялось несколько раз до отправки, события склеиваются в одно. Для аккордеона на чистом HTML событие не требуется, оно нужно, когда на открытие пункта должен реагировать наш код: например, подгружать данные.

Пример ниже показывает два набора из трёх пунктов. Набор «Без name» состоит из обычных `details`, набор «С name» получит группу, о ней речь в следующем разделе. Откроем в первом наборе все три пункта: они останутся открытыми одновременно. Если на узком экране наборы расположились друг под другом, это не меняет поведения. Проверить результат просто: откроем второй пункт в наборе «С name», и первый закроется сам.

[Живой пример: Аккордеон на details: без name и с name](https://penlab.space/pen/eEQVCtd0)

## Как оставить открытым только один пункт

Для аккордеона, где открыт один пункт, у каждого `details` группы ставим одинаковый `name`.

```html
<details name="faq" open>
  <summary>Что такое аккордеон?</summary>
  <p>Список пунктов, у каждого заголовок и скрытый текст.</p>
</details>

<details name="faq">
  <summary>Нужен ли JavaScript?</summary>
  <p>Нет, пункты раскрывает сам браузер.</p>
</details>

<details name="faq">
  <summary>Можно открыть сразу два?</summary>
  <p>Нет, при открытии пункта предыдущий закрывается.</p>
</details>
```

Браузер следит за группой сам. В наборе «С name» предыдущего примера мы открывали пункты по очереди, и в Chrome 154 открытым оставался только последний. Если после этого кликнуть по уже открытому пункту, он закроется, и в группе не будет открытых пунктов: `name` ограничивает число открытых пунктов сверху, но не требует, чтобы один из них был открыт всегда.

Несколько тонкостей группы:

- Пункты группы не обязаны идти подряд в разметке: между ними может быть другой код. Группу задаёт значение `name`, а не соседство.
- На странице может быть несколько аккордеонов, если у каждого свой `name`.
- Если в группе несколько пунктов помечены `open`, по документации MDN откроется только первый по порядку в разметке. Мы проверили в Chrome 154 запись, где первый пункт закрыт, а второй и третий с `open`: открытым остался второй.
- Когда мы открываем пункт кодом, действует то же правило: `details.open = true` закрывает остальные пункты группы, а для каждого изменённого пункта приходит своё событие `toggle`.

В браузере без поддержки `name` атрибут игнорируется. Пункты остаются независимыми, каждый по-прежнему открывается и закрывается. Поддержка у `name` такая: Chrome и Edge 120, Firefox 130, Safari 17.2.

## Как заменить стрелку и оформить заголовок

Браузер рисует перед `summary` треугольник, маркер раскрытия. По умолчанию `summary` ведёт себя как элемент списка со значением `display: list-item`, поэтому маркером управляют так же, как маркером списка: `list-style: none` его убирает, а `::marker` меняет его вид. По документации MDN, треугольник пропадает и при смене `display` на `block`. Safari дополнительно показывает маркер через нестандартный `::-webkit-details-marker`, и в нём подстраховываем правилом `display: none`. Свою стрелку рисуем псевдоэлементом `::after`.

```html
<section class="faq">
  <details class="faq__item" name="faq" open>
    <summary class="faq__question">Что такое аккордеон?</summary>
    <p class="faq__answer">Список пунктов: у каждого есть заголовок, а текст под ним скрыт, пока пункт не открыт.</p>
  </details>
  <!-- остальные пункты такие же -->
</section>
```

```css
.faq__question {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 14px 0;
  cursor: pointer;
  list-style: none;
}

.faq__question::-webkit-details-marker {
  display: none;
}

.faq__question::after {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.2s;
}

.faq__item[open] > .faq__question::after {
  transform: rotate(-135deg);
}

.faq__question:focus-visible {
  outline: 2px solid #6aa9ff;
  outline-offset: 2px;
}
```

Стрелка поворачивается по селектору `[open]`: браузер сам выставляет этот атрибут, поэтому состояние пункта и вид стрелки не расходятся. Рамку фокуса мы не убираем: без неё человек, который ходит по странице клавишей Tab, не видит, на каком пункте стоит.

С клавиатуры пункт управляется без дополнительного кода. В Chrome 154 мы перешли на заголовок клавишей Tab, Enter открыл пункт, Пробел закрыл его, и второй Пробел открыл снова.

[Живой пример: Аккордеон на details со своей стрелкой](https://penlab.space/pen/4F8596qm)

Внутри `summary` лучше держать только текст и простую разметку без заголовков. По документации MDN, в части браузеров `summary` получает роль кнопки, а у вложенного `h3` роль заголовка пропадает: скринридер не объявит его как заголовок. Если нужен заголовок в структуре страницы, роль придётся проверять в нужных браузерах и программах чтения.

## Что учесть: поиск по странице и ограничения

У `details` есть ещё одно свойство: текст в закрытом пункте находится поиском по странице. По таблицам совместимости MDN поиск раскрывает пункт с найденным текстом в Chrome и Edge с версии 97, в Firefox с версии 139 и в Safari с версии 26.2. В Firefox до версии 148 и в Safari 26.2 есть ошибка: страница может не прокрутиться к найденному месту.

Есть и границы:

- Сам по себе `details` пункт не анимирует: переключение мгновенное. Плавность добавляет CSS из следующего раздела.
- Если пункту нужно сложное поведение, например подгрузка с сервера или закрытие по условию, понадобится скрипт на событии `toggle`.
- Чтобы развернуть или свернуть все пункты одной кнопкой, нужен скрипт со свойством `details.open`. Пункты с общим `name` так вместе не откроются: останется открытым один.

## Как плавно раскрывать и закрывать пункт

Браузер хранит содержимое `details` в отдельной части, и CSS получил для неё псевдоэлемент `::details-content`. Пока пункт закрыт, у этой части стоит `content-visibility: hidden`, а при открытии оно меняется на `visible`. В Chrome 154 мы прочитали это значение у закрытого и открытого пункта через `getComputedStyle`: `hidden` и `visible`. Без перехода содержимое при закрытии исчезает мгновенно, поэтому плавность строится на трёх приёмах:

- `block-size: 0` и `overflow: clip` у закрытого пункта и `block-size: auto` у открытого задают, откуда и докуда меняется высота;
- `interpolate-size: allow-keywords` разрешает анимировать высоту между числом и ключевым словом `auto`, как в статье [«Плавное появление блока в CSS: как анимировать display: none»](https://penlab.space/blog/ru/css-transition-display-none);
- `content-visibility` в списке переходов с ключевым словом `allow-discrete` удерживает содержимое видимым, пока идёт закрытие.

```css
.faq__answer {
  margin: 0;
  padding: 0 0 14px;
}

@supports (interpolate-size: allow-keywords) {
  :root {
    interpolate-size: allow-keywords;
  }

  .faq__item::details-content {
    block-size: 0;
    overflow: clip;
    transition: block-size 0.25s ease, content-visibility 0.25s allow-discrete;
  }

  .faq__item[open]::details-content {
    block-size: auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  .faq__question::after,
  .faq__item::details-content {
    transition: none;
  }
}
```

Правило `.faq__answer` с `margin: 0` здесь нужно: у абзаца по умолчанию есть внешние поля, и если их оставить, пункт в конце перехода подпрыгивает. В Chrome 154 высота пункта в последних кадрах менялась с 116,5 до 133 пикселей, а с `margin: 0` росла плавно до 115. Нижний отступ задаём через `padding`. В пене к коду добавлены общие стили страницы и рамки между пунктами, на поведение они не влияют.

Мы замерили в Chrome 154 высоту `::details-content` у пункта с абзацем в 62 пикселя. При открытии она выросла от 0 до 62 пикселей с промежуточными значениями 18, 48 и 57 пикселей, а при закрытии вернулась к 0, и содержимое оставалось видимым до конца перехода.

Запасной вариант мы вынесли в условие `@supports`. Поддержка у частей разная: `::details-content` понимают Chrome и Edge 131, Firefox 143 и Safari 18.4, а `interpolate-size` пока только Chrome и Edge 129. В Firefox и Safari условие ложно, блок правил не применяется, и пункт работает как обычный `details`: открывается и закрывается сразу. Мы имитировали такой случай в Chrome, заменив условие на заведомо ложное: пункт открывался и закрывался сразу, без промежуточных значений высоты. В самих Firefox и Safari мы пример не запускали и опираемся на таблицы совместимости. Для читателей с настройкой «уменьшить движение» блок `prefers-reduced-motion` отключает переходы.

Ниже итоговый аккордеон: группа через `name`, своя стрелка, плавное раскрытие и запасной вариант. Чтобы рассмотреть анимацию, откроем пример в редакторе Penlab и поставим в обоих значениях `transition` у `.faq__item::details-content` по `1s` вместо `0.25s`.

[Живой пример: Аккордеон на details: группа и плавное раскрытие](https://penlab.space/pen/HqZjIZvu)

Свой аккордеон проще всего собрать в [новом пене](https://penlab.space/new): он бесплатный, а готовый пример можно отправить ссылкой. Родственный нативный элемент для окон поверх страницы разобран в статье [«Как сделать модальное окно на HTML, CSS и JS»](https://penlab.space/blog/ru/modal-dialog-html-css).

## FAQ

### Нужен ли JavaScript для аккордеона?

Нет. `details` открывается и закрывается сам, атрибут `name` делает аккордеон из одного открытого пункта, а плавность даёт CSS. Скрипт нужен, когда код должен реагировать на открытие пункта: для этого есть событие `toggle`.

### Как открыть пункт по умолчанию?

Ставим атрибут `open`: `<details open>`. Если в группе с одним `name` открыты несколько пунктов, по документации MDN откроется первый по порядку в разметке.

### Можно ли закрыть все пункты группы?

Да. Группа с `name` разрешает не больше одного открытого пункта, но не требует, чтобы один был открыт. В Chrome 154 клик по открытому пункту закрыл его, и в группе не осталось открытых.

### Как открыть пункт из JavaScript?

Записываем `details.open = true`. В группе с `name` остальные пункты при этом закрываются. Мы проверили в Chrome 154: пункт открылся, предыдущий закрылся, и для каждого пришло событие `toggle`.

### Что будет в старом браузере?

Атрибут `name` без поддержки игнорируется: пункты работают по отдельности. Блок с `::details-content` в нашем коде лежит под `@supports`, поэтому без поддержки `interpolate-size` пункт раскрывается без анимации.

### Почему открытие плавное, а закрытие мгновенное?

Стоит проверить список переходов: в нём должен быть `content-visibility` с `allow-discrete`. По документации MDN, без такого перехода содержимое при закрытии исчезает мгновенно.

## Источники

- [MDN: элемент details](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/details)
- [MDN: элемент summary](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/summary)
- [MDN: ::details-content](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/::details-content)
- [MDN: HTML details exclusive accordions](https://developer.mozilla.org/en-US/blog/html-details-exclusive-accordions/)
- [Chrome for Developers: Exclusive Accordion](https://developer.chrome.com/docs/css-ui/exclusive-accordion)
- [Chrome for Developers: More options for styling details](https://developer.chrome.com/blog/styling-details)
- [MDN: таблицы совместимости browser-compat-data](https://github.com/mdn/browser-compat-data)
