На выходных решил поэкспрементировать, и нашел в чем секрет.
Логика такая:
1. когда элемент невидим, то el.style.display = 'none';
2. начинаем открывать -
el.style.display = 'block;
el.style.height/width = 0 + 'px';
так активизируются scrollHeight/Width, имеем данные для анимации.
3.начинаем закрывать по onclick, например;
4.
неочевидная загадка - когда пункт закрылся надо сделать вот что:
el.style.height/width = "";
el.style.display = 'none';
почему именно пустая строка - не знаю, но именно так работает. Если это не сделать, то вложенные в данный пункт, пункты будут раскрываться, не растягивая родительский.
Тут возникает еще один вопрос - как получить момент полного открытия/особенно закрытия элемента.
Лучший вариант: функция анимации генерирует на старте и в конце события, например moveStart и moveEnd, универсальный обработчик самоопределенных событий, например, Eventer, получает их и запускает функции-обработчики точно в нужный момент и в нужной последовательности.
Как делается Eventer, рассказано на этом сайте. Я сделал свой, корявый, но в данном случае работает.
А можно, конечно, по setTimeout, но мелкие нестыковки по времени обязательно будут.
Так что, никакого волшебства здесь нет, решение заключается в одном, на мой взгляд, совсем в неочевидном и нелогичном действии. Если кто будет делать такое меню на чистом js, то не надо ломать голову, просто ставьте в конце
el.style.height/width = ""
.
Если это решение на самом деле логично, то объясните ход рассуждений, буду признателен, я его нашел совершенно случайно.