Здравствуй, Хабр!
Хочу поделиться ещё одним способом создания css-перехода (
Столкнулся с данной проблемой при разработке веб-компонентов TreeView и DataGrid. В TreeView решил сделать плавное развёртывание/свёртывание узлов, а в DataGrid — строки с дополнительным контентом. Почитав интернет, нашёл несколько способов реализации, основные — через свойство
В TreeView каждый узел имеет неограниченную вложенность, поэтому сразу не получится определить максимальную высоту его содержимого, да и если
Итак, приступим к реализации перехода по свойству
Пусть:
Определим css-класс для блока, в котором установим обрезку содержимого и сам переход:
Опишем обработчик события
Осталось добавить возврат
Ну вот и всё, теперь развёртывание/свёртывание блока работает как надо и не зависит от размера контента.

Рисунок 1 — Пример развёртывания/свёртывания узлов в TreeView
Стоит отметить минусы данного подхода:
Спасибо за внимание!
Хочу поделиться ещё одним способом создания css-перехода (
transition
) свойства height
от 0px
до auto
. Столкнулся с данной проблемой при разработке веб-компонентов TreeView и DataGrid. В TreeView решил сделать плавное развёртывание/свёртывание узлов, а в DataGrid — строки с дополнительным контентом. Почитав интернет, нашёл несколько способов реализации, основные — через свойство
max-height
и на javascript. Реализация на javascript была исключена — есть же css с поддержкой переходов и анимаций. Остался max-height
, тем более в примерах с выпадающими меню всё работает. В TreeView каждый узел имеет неограниченную вложенность, поэтому сразу не получится определить максимальную высоту его содержимого, да и если
max-height
задать очень большим, будут проблемы с анимацией перехода. Также, если развернуть дочерние узлы, высота родительского увеличится и может перекрыть max-height
. Как ни крути, max-height
не подходит. С DataGrid та же проблема — дополнительный контент в строке может быть любой. Нужен height:auto
! Итак, приступим к реализации перехода по свойству
height
от 0px
до auto
. Рассмотрим простой пример. Пусть:
elBlock: HTMLDivElement
— блок, который нужно развёртывать/свёртывать;elToggle: HTMLButtonElement
— кнопка-переключатель состояния.
Определим css-класс для блока, в котором установим обрезку содержимого и сам переход:
.block {
overflow: hidden;
transition: height 500ms ease;
}
Опишем обработчик события
onClick
для elToggle
:elToggle.addEventListener("click", () => {
if (elBlock.style.height === "0px") {
elBlock.style.height = `${ elBlock.scrollHeight }px`
} else {
elBlock.style.height = `${ elBlock.scrollHeight }px`;
window.getComputedStyle(elBlock, null).getPropertyValue("height");
elBlock.style.height = "0";
}
});
Осталось добавить возврат
height:auto
после перехода:elBlock.addEventListener("transitionend", () => {
if (elBlock.style.height !== "0px") {
elBlock.style.height = "auto"
}
});
Ну вот и всё, теперь развёртывание/свёртывание блока работает как надо и не зависит от размера контента.

Рисунок 1 — Пример развёртывания/свёртывания узлов в TreeView
Стоит отметить минусы данного подхода:
- использование javascript, хотелось бы только css;
- во время перехода может измениться контент (его высота,
scrollHeight
) и после его завершения, в случае возвратаauto
, высота блока резко поменяется в ту или иную сторону. Для избежания данного эффекта, необходимо отслеживать изменениеscrollHeight
и менятьheight
. Как показывает практика, обычно переходы развёртывания/свёртывания занимают по 0.5 с, а за это время пользователь вряд ли успеет изменить что-то внутри, например, в случае TreeView, развернуть дочерний узел.
Спасибо за внимание!