Анимированная выпадушка на CSS
• css, html
details и summary
Начнём с вёрстки:
<details>
<summary>Заголовок</summary>
Содержимое
</details>Заголовок
Содержимое<details> и <summary> появились в браузерах уже давно (10+ лет назад). Комбинация тегов предлагает хороший, семантический и со всех сторон обкатанный механизм. “Заголовок” виден всегда и кликабелен, а “содержимое” переключается по клику.
Раскрывается без единой строчки JS – да.
Раскрывается от поиска по страница – да.
Поддерживает клавиатуру, скринридеры – тоже да.
Поэтому, если нужно делать раскрывающийся по месту элемент, details+summary – первый претендент на реализацию.
Псвевдоэлемент details-content
При ближайшем рассмотрении у вёрстки выше есть минус: если мы хотим анимированно скрывать/показывать контент, нам нужно на что-то повесить анимацию. И у нас может быть много контента:
<details>
<summary>Заголовок</summary>
<p>...</p>
<p>...</p>
<p>...</p>
</details>По данной вёрстке никакого единого контейнера для трёх параграфов нет. Для решения данной проблемы был создан псевдоэлемент ::details-content. Его нет в явном виде в HTML (как и других псевдоэлементов), однако он охватывает именно то, что нам нужно:
<!-- псевдовёрстка -->
<details>
<summary>Заголовок</summary>
<::details-content>
<p>...</p>
<p>...</p>
<p>...</p>
</::details-content>
</details>interpolate-size
Давняя проблема: transition и animation не могу анимировать значения вида height: auto (например, между auto и 0). Но в какой-то момент браузеры решили эту задачу, но уже не смогли включить это поведение по умолчанию. Так появилось свойство interpolate-size. У него буквально два значения: дефолтное поведение numeric-only и новое allow-keywords.
.block {
interpolate-size: allow-keywords;
transition: height .3s ease;
height: 0;
}
.block_opened {
height: auto;
}Свойство позволяет анимировать не только auto, но и min-content, fit-content, max-content и content (для расчётов с flex-basis). Однако анимировать между двумя ключевыми словами всё ещё нельзя, одно из значений обязательно должно быть числовым.
В ченжлоге Safari Technology Preview 254 написано, что добавлена поддержка данного свойства, однако у меня так и не заработало. Судя по всему, работа идёт.
Итоговый результат
Заголовок
Содержимое
Содержимое
Содержимое
В браузерах, в которых нет поддержки interpolate-size, будет просто выпадушка без анимации.
Несколько подводных камней, с которыми можно столкнуться:
1) Анимация работает только при открытии.
Это происходит из-за того, что в браузерных стилях есть content-visibility: hidden для ::details-content в скрытом состоянии. Когда details раскрывается, этот стиль исчезает мгновенно, и элемент может анимироваться из одного состояния в другое. А когда закрывается, стиль тоже появляется мгновенно, и элемент просто мгновенно скрывается.
Это можно победить, если использовать transition-behavior: allow-discrete:
::details-content {
transition: .3s ease;
transition-property: height, content-visibility;
transition-behavior: allow-discrete;
}Свойство меняет работу анимации свойств, которые можно менять только дискретно (отсюда и название). Без него установленное дискретное свойство сразу применится и скроет содержимое, а с allow-discrete новое значение применится позже и анимация скрытия заработает.
2) Скрытие стрелочки в summary
Казалось бы, в браузеры добавили псевдо-элемент ::marker, именно его и видно в девтулзах внутри summary. Используем примитивный CSS:
summary::marker {
display: none;
}И… не работает. Элемент всё равно виден. Чтобы решить данную проблему, я когда-то нашёл костыль с list-style: none:
summary {
list-style: none;
}Это успешно работает как в новых браузерах, так и в старых без поддержки ::marker. Но лучше использовать и то и то, ведь list-style явно не предназначается для summary.
Какие ещё варианты есть?
Если не использовать interpolate-size, то есть два хороших варианта:
1) JS. Вычисляем размеры, устанавливаем, готово. Ничего сложного, всё понятно.
2) grid и анимация ячеек через fr. Дело в том, что при несложной комбинации свойств 1fr начинает значить “размер содержимого”. И такое значение уже можно анимировать!
Однако у него есть ряд побочных эффектов, что негативно влияет на итоговый результат. Рассинхрон высоты во время анимации, вёрстка на чекбоксе – примеры подобных проблем.
Выводы
Шёл 2026й год, и мы уже почти получили анимированный спойлер (выпадушку) в двух браузерах. Ждём 2027й, чтобы это заработало в 3х основных браузерных движках?
Хотелось бы верить. А фича с interpolate-size очень мощная. И мы наконец можем анимировать показ элемента после снятия display: none.




