Olá Habr!
Eu quero compartilhar outra maneira de criar uma transição css da propriedade
height
de
0px
para
auto
.
Enfrentou esse problema ao desenvolver componentes da Web TreeView e DataGrid. No TreeView, eu decidi fazer uma expansão / colapso suave de nós e em um DataGrid - linhas com conteúdo adicional. Depois de ler a Internet, encontrei vários métodos de implementação, os principais através da
max-height
e em javascript. A implementação do javascript foi descartada - há CSS com suporte para transições e animações.
max-height
restante, especialmente nos exemplos com menus suspensos, tudo funciona.
No TreeView, cada nó tem aninhamento ilimitado, portanto você não pode determinar imediatamente a altura máxima de seu conteúdo e, mesmo que você defina a
max-height
como muito grande, haverá problemas com a animação de transição. Além disso, se você expandir os nós filhos, a altura do pai aumentará e poderá se sobrepor
max-height
. Goste ou não,
max-height
não
max-height
adequada. O DataGrid tem o mesmo problema - pode haver qualquer conteúdo adicional em uma linha. Precisa de
height:auto
!
Então, vamos começar a implementar a transição na propriedade
height
de
0px
para
auto
. Considere um exemplo simples.
Vamos:
elBlock: HTMLDivElement
- bloco a ser elBlock: HTMLDivElement
/ recolhido;elToggle: HTMLButtonElement
- botão para alternar o status.
Defina uma classe css para o bloco em que definimos o corte do conteúdo e a própria transição:
.block { overflow: hidden; transition: height 500ms ease; }
Descrevemos o
onClick
eventos
onClick
para
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"; } });
Resta adicionar a
height:auto
retorno
height:auto
após a transição:
elBlock.addEventListener("transitionend", () => { if (elBlock.style.height !== "0px") { elBlock.style.height = "auto" } });
Bem, isso é tudo, agora a expansão / colapso do bloco funciona como deveria e não depende do tamanho do conteúdo.
Figura 1 - Um exemplo de expansão / recolhimento de nós em um TreeViewVale ressaltar as desvantagens dessa abordagem:
- usando javascript, gostaria apenas de css;
- durante a transição, o conteúdo (sua altura,
scrollHeight
) pode mudar e, após a conclusão, se o retorno auto
, a altura do bloco mudará drasticamente em uma direção ou outra. Para evitar esse efeito, você precisa acompanhar a alteração no scrollHeight
e alterar a height
. Como mostra a prática, geralmente as transições de expansão / recolhimento levam 0,5 s cada e, durante esse período, é improvável que o usuário tenha tempo para alterar algo interno, por exemplo, no caso do TreeView, expanda o nó filho.
Obrigado pela atenção!