Перейти к содержимому
EN
Масштаб
Плотность
Тема
Акцент

Обратная связь

Аккордеон

Группа сворачиваемых разделов, из которых открыт ровно один. На нативных <details> с общим name, поэтому взаимное исключение, раскрытие и клавиатура достаются от платформы — без единой строки JS.

Компонент
Почему прогон занял 42 секунды?
Три прохода расстановки ресурсов плюс запекание навмеша. Основное время ушло на валидацию путей, которая перезапускалась дважды.
Можно ли ограничить расход токенов?
Да, в параметрах проекта. Лимит проверяется перед стартом каждого агента, а не по факту — прогон не уйдёт в минус.
Что происходит с артефактами после удаления?
Удаляются вместе с прогоном. Резервная копия хранится семь суток, восстановление — через поддержку.
Разметка
<div class="inst-accordion">
  <details class="inst-accordion-item" name="faq" open>
    <summary class="inst-accordion-head">Почему прогон занял 42 секунды?</summary>
    <div class="inst-accordion-body">Три прохода расстановки ресурсов плюс запекание навмеша.
      Основное время ушло на валидацию путей, которая перезапускалась дважды.</div>
  </details>
  <details class="inst-accordion-item" name="faq">
    <summary class="inst-accordion-head">Можно ли ограничить расход токенов?</summary>
    <div class="inst-accordion-body">Да, в параметрах проекта. Лимит проверяется перед стартом
      каждого агента, а не по факту — прогон не уйдёт в минус.</div>
  </details>
  <details class="inst-accordion-item" name="faq">
    <summary class="inst-accordion-head">Что происходит с артефактами после удаления?</summary>
    <div class="inst-accordion-body">Удаляются вместе с прогоном. Резервная копия хранится семь
      суток, восстановление — через поддержку.</div>
  </details>
</div>

Контракт

Что Обязательно Почему
<details> под inst-accordion-item да Раскрытие, клавиатура и состояние open — от платформы
<summary> под inst-accordion-head да Только <summary> фокусируем и переключает <details>
Общий name да, для аккордеона Делает группу взаимоисключающей. Без него секции независимы
Прямое вложение да Правила открытой секции записаны через >: заголовок обязан быть прямым потомком <details>
Настоящий заголовок внутри <summary> нет, но обычно да <summary> сам по себе в оглавление страницы не попадает

Доступность

Клавиатура Tab до заголовка, Enter или Space — переключение. Всё нативное, instrument.js ничего не перехватывает
Роль и состояние <summary> сам объявляет себя переключателем и сообщает, раскрыт ли раздел. Своего aria-expanded ставить не надо и не нужно
Поиск по странице Содержимое закрытой секции находится браузерным поиском, и секция раскрывается сама — это поведение <details>, ради него нативный элемент и взят
Заголовок Если секции — разделы страницы, вложите в <summary> настоящий заголовок нужного уровня: <summary> сам по себе в оглавление не попадает
Цель нажатия Заголовок нажимается целиком, от края до края: --control-h-lg в высоту
Уменьшенное движение Поворот шеврона схлопывается вместе со всеми переходами
Печать Закрытые секции раскрываются на листе: закрытый <details> на бумаге — невосстановимо потерянное содержимое

Устройство

Элемент Класс Тег
Контейнер группы inst-accordion <div>
Секция inst-accordion-item <details>
Заголовок-переключатель inst-accordion-head <summary>
Содержимое inst-accordion-body <div>

Шеврон рисуется псевдоэлементом заголовка и поворачивается на 180° при открытии — своего класса у него нет и разметки он не требует. Нативный треугольник <summary> снят.

Волосок под заголовком появляется только у открытой секции (.inst-accordion-item[open] > .inst-accordion-head): у закрытой отделять нечего.

Внутри чужой рамки

Раскрывашка часто стоит не сама по себе, а внизу панели или карточки: «ещё поля», «разметка», «журнал». Своя рамка была бы там второй в пикселе от первой, а своё скругление — скруглением внутри скругления, ни с чем не концентричным.

В контексте
Прогон 4127
Собран за 4,2 с. Тестов 318, упавших нет.
Параметры сборки
Ветка master, коммит d7c9cd3, кэш включён.
Разметка
<div class="inst-panel" style="inline-size:26rem">
  <div class="inst-panel-header"><span class="inst-panel-title">Прогон 4127</span></div>
  <div class="inst-panel-body">Собран за 4,2 с. Тестов 318, упавших нет.</div>
  <details class="inst-accordion-item inst-accordion-item--flush">
    <summary class="inst-accordion-head">Параметры сборки</summary>
    <div class="inst-accordion-body">Ветка master, коммит d7c9cd3, кэш включён.</div>
  </details>
</div>

Остаётся один шов сверху: секция продолжает то, под чем стоит, а не объявляет себя отдельным блоком. Контейнер .inst-accordion при этом не нужен — секция здесь одна и живёт в чужой стопке.

Поведение

Взаимное исключение

Общий атрибут name на элементах <details> делает группу взаимоисключающей: открытие второй секции закрывает первую.

Что нужно Как
Открыта ровно одна секция Общий name на всех <details>
Открыто сколько угодно name не ставить
Какая открыта при загрузке open на нужном <details>

Уберите name — и секции станут независимыми, открывать можно сколько угодно. Это единственная разница между «аккордеоном» и «списком раскрывашек», и она в один атрибут.

Пример
Без name — открываются независимо
Эту можно оставить открытой и открыть следующую.
Вторая секция
Первая при этом не закроется.
Разметка
<div class="inst-accordion">
  <details class="inst-accordion-item" open>
    <summary class="inst-accordion-head">Без name — открываются независимо</summary>
    <div class="inst-accordion-body">Эту можно оставить открытой и открыть следующую.</div>
  </details>
  <details class="inst-accordion-item">
    <summary class="inst-accordion-head">Вторая секция</summary>
    <div class="inst-accordion-body">Первая при этом не закроется.</div>
  </details>
</div>

API

Классы
ИмяЧто делает
класс
inst-accordionКонтейнер. Колонка секций с зазором --space-1
inst-accordion-itemСекция. Рамка, радиус, overflow: hidden
inst-accordion-headЗаголовок. Высота от --control-h-lg, шеврон у дальнего края
inst-accordion-bodyСодержимое
модификатор
inst-accordion-item--flushСекция ВНУТРИ чужой рамки: панели, карточки, поля примера. Своей рамки и радиуса нет, остаётся шов сверху
Токены
ИмяЗначениеОткуда
токен
--space-12pxодно на все ячейки
--space-36pxодно на все ячейки
--pad-cell-xvar(--space-4)база +14: плотность · масштаб
--pad-panelvar(--space-5)база +14: плотность · масштаб
--gap-inlinevar(--space-4)база +14: плотность · масштаб
--control-h-lg38pxбаза +14: плотность · масштаб
--radius-md8pxбаза +4: масштаб
--hairline1pxбаза +1: экран
--borderlight-dark(oklch(0 0 0 / 0.12), oklch(1 0 0 / 0.11))одно на все ячейки
--border-subtlelight-dark(oklch(0 0 0 / 0.07), oklch(1 0 0 / 0.06))одно на все ячейки
--surface-raisedlight-dark(var(--n-0), var(--n-12))база +1: тема
--surface-hoverlight-dark(oklch(0 0 0 / 0.035), oklch(1 0 0 / 0.045))одно на все ячейки
--size-chevron10pxбаза +4: масштаб
--text-mutedlight-dark(var(--n-8), var(--n-6))одно на все ячейки
--text-sm0.875remбаза +4: масштаб
--weight-medium600одно на все ячейки
--dur-180msодно на все ячейки
--ease-outcubic-bezier(0.22, 0.61, 0.36, 1)одно на все ячейки

Почему кит устроен именно так — конституция · Открытый код под MIT, github.com/keshon/instrument