Bonjour, Habr!
Je veux partager une autre façon de créer une transition css de la propriété
height
de
0px
à
auto
.
Face à ce problème lors du développement de composants Web TreeView et DataGrid. Dans TreeView, j'ai décidé de faire une expansion / un effondrement en douceur des nœuds, et dans un DataGrid - des lignes avec du contenu supplémentaire. Après avoir lu Internet, j'ai trouvé plusieurs méthodes d'implémentation, les principales via la
max-height
et en javascript. L'implémentation javascript a été exclue - il existe des CSS avec prise en charge des transitions et des animations.
max-height
, en particulier dans les exemples de menus déroulants, tout fonctionne.
Dans TreeView, chaque nœud a une imbrication illimitée, vous ne pouvez donc pas déterminer immédiatement la hauteur maximale de son contenu, et même si vous définissez la
max-height
sur très grande, il y aura des problèmes avec l'animation de transition. De plus, si vous développez les nœuds enfants, la hauteur du parent augmentera et peut chevaucher
max-height
. Qu'on le veuille ou non, la
max-height
ne convient pas. DataGrid a le même problème - il peut y avoir n'importe quel contenu supplémentaire dans une rangée. Besoin de
height:auto
!
Commençons donc à implémenter la transition sur la propriété
height
de
0px
à
auto
. Prenons un exemple simple.
Soit:
elBlock: HTMLDivElement
- bloc à elBlock: HTMLDivElement
/ elBlock: HTMLDivElement
;elToggle: HTMLButtonElement
- bouton pour basculer le statut.
Définissez une classe css pour le bloc dans lequel nous définissons le découpage du contenu et la transition elle-même:
.block { overflow: hidden; transition: height 500ms ease; }
Nous décrivons le
onClick
événements
elToggle
pour
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"; } });
Reste à ajouter la
height:auto
retour
height:auto
après la transition:
elBlock.addEventListener("transitionend", () => { if (elBlock.style.height !== "0px") { elBlock.style.height = "auto" } });
Eh bien, c'est tout, maintenant l'expansion / l'effondrement du bloc fonctionne comme il se doit et ne dépend pas de la taille du contenu.
Figure 1 - Un exemple de développement / réduction de nœuds dans un TreeViewIl convient de noter les inconvénients de cette approche:
- en utilisant javascript, je voudrais seulement css;
- pendant la transition, le contenu (sa hauteur,
scrollHeight
) peut changer et après son achèvement, si l' auto
revient, la hauteur du bloc changera considérablement dans une direction ou une autre. Pour éviter cet effet, vous devez suivre le changement dans scrollHeight
et changer la height
. Comme le montre la pratique, les transitions expand / collapse prennent généralement 0,5 s chacune, et pendant ce temps, il est peu probable que l'utilisateur ait le temps de changer quelque chose à l'intérieur, par exemple, dans le cas de TreeView, développez le nœud enfant.
Merci de votre attention!