4

I have a dropdown that I want a scaling down animation to show when the dropdown opens and closes. I have a CODEPEN here with the code for you to experiment in.

I slowed it down to a 10 sec animation (not the final speed obviously) just for you to see what I mean. The items are scaling down at the speed I instructed (10 sec) but the items below won't come down until the ng-animation is completed. This causes overlap.

This is what I have in my HTML

<div class="cnt">
    <md-list ng-click="menuIsOpen = 1" layout="row" layout-padding="" class="layout-row" layout-align="start center" flex> 
        <span class="title flex" flex=""> Menu Item</span>
        <i class="fa fa-chevron-down"></i>
    </md-list>
    <div class="sub-menu" ng-show="menuIsOpen===1" ng-animate="'animate'" >
        <md-menu-item ng-repeat="item in data"  >
            <md-button>
                <div layout="row" flex="">
                    <a ui-sref="{{item.link}}">
                        <p flex=""><i class="fa fa-{{item.icon}}"></i> {{item.title}}</p>
                    </a>
                </div>
            </md-button>
        </md-menu-item>
    </div>

    <md-list ng-click="menuIsOpen = 2" layout="row" layout-padding="" class="layout-row" layout-align="start center" flex> 
        <span class="title flex" flex=""> Menu Item 2</span>
        <i class="fa fa-chevron-down"></i>
    </md-list>
    <div class="sub-menu" ng-show="menuIsOpen===2" ng-animate="'animate'" >
        <md-menu-item ng-repeat="item in data">
            <md-button>
                <div layout="row" flex="">
                    <a ui-sref="{{item.link}}">
                        <p flex=""><i class="fa fa-{{item.icon}}"></i> {{item.title}}</p>
                    </a>
                </div>
            </md-button>
        </md-menu-item>
    </div>
</div>      

And the CSS

.ng-hide-remove {
    -webkit-animation:2s scaleIn ease;
    animation:2s scaleIn ease;
}

@-webkit-keyframes scaleIn {
    From {
        transform-origin:  top;
        -webkit-transform: scaleY(0);
        -moz-transform: scaleY(0);
        -ms-transform: scaleY(0);
        -o-transform: scaleY(0);
        transform: scaleY(0);
    }
    To {
        transform-origin:  top;
        -webkit-transform: scaleY(1);
        -moz-transform: scaleY(1);
        -ms-transform: scaleY(1);
        -o-transform: scaleY(1);
        transform: scaleY(1);
    }
}

@keyframes scaleIn {
    From {
            transform-origin:  top;
          -webkit-transform: scaleY(0);
          -moz-transform: scaleY(0);
          -ms-transform: scaleY(0);
          -o-transform: scaleY(0);
          transform: scaleY(0);
    }
        To {
          transform-origin:  top;
          -webkit-transform: scaleY(1);
        -moz-transform: scaleY(1);
        -ms-transform: scaleY(1);
        -o-transform: scaleY(1);
        transform: scaleY(1);
    }
}

I am essentially trying to reproduce the same animation as in the angular material website seen here

p.s. any different approach or idea that doesn't require too much change overall, I am open to it. I am hoping for a css modification, but I know that it may not be that easy after all. I am hopeful though :)

Thanks for the help.

LOTUSMS
  • 10,317
  • 15
  • 71
  • 140
  • Not entirely familiar with angular but the demo you linked to animates via height attribute while you do it with scale. Also, you have an animation from 0 pixels to 30 which is what's holding up the menu and makes it snap down. It travels from 0 to 30px height during animation and once the animation class is removed it takes it's proper place. – Serg Chernata Jan 23 '17 at 15:34
  • @SergChernata While adjusting those parameter, I still get no closer to the desired effect. if I remove the 30px nothing shows. If I change it to 100% it opens forn the center outwards not from top to bottom. I'm sure something is not right. I can't figure out what – LOTUSMS Jan 23 '17 at 15:39
  • Oh I know, I can't get it to work either lol But that's because I don't know Angular that well and I don't want to post you a jquery solution or something random :) – Serg Chernata Jan 23 '17 at 15:39
  • I can probably pass a jquery solution into a directive and work it that way. Go for it. It wouldn't hurt – LOTUSMS Jan 23 '17 at 15:40
  • @SergChernata you do at least need to be aware of the ng-animate classes that are in play from Angular tho. So I guess, to correct my last statement, a jquery solution won't probably work. I believe this is a strictly css3 solution. I'm just not too knowledgeable at handling css transitions – LOTUSMS Jan 23 '17 at 15:48
  • Yeah I'm gonna put this on hold. If no-one else answers in a couple of days I might look again. I'm equally comfortable with jquery and css animation but this is internal to angular. – Serg Chernata Jan 23 '17 at 15:49
  • @SergChernata fair enough. Thanks – LOTUSMS Jan 23 '17 at 15:50

2 Answers2

2

UPDATE:

After a litte bit trial and error I think I found a SOLUTION. If you animate not the div around (sub-menu) your md-menu-items but the item itself, it will work.

I just added ng-if="menuIsOpen===1" to your md-menu-item (deleted the ng-show="menuIsOpen===1 from the sub-menu) and changed the animation as follows:

md-menu-item.ng-enter{
    -webkit-animation:3s move ease;
    animation:3s move ease;
}

@-webkit-keyframes move {
    From {
        margin-bottom:-50px;
    }
    To {
        margin-bottom:0px;
    }
}


@keyframes move {
    From {
        margin-bottom:-50px;
    }
    To {
        margin-bottom:0px;
    }
}

Now the size of every item in the menu is animated. I cheated a little bit with margin-bottom, but height was still not working.


I think you have two options. ( At least I can't think of anything more.) Or maybe three, see above.

1.You can change the height and add transform-origin: top; like here:

    @keyframes scaleIn {
  From {
     transform-origin:  top;
    -webkit-transform: scaleY(0);
    -moz-transform: scaleY(0);
    -ms-transform: scaleY(0);
    -o-transform: scaleY(0);
    transform: scaleY(0);
    height: 0px;
  }
  To {
     transform-origin:  top;
    -webkit-transform: scaleY(1);
    -moz-transform: scaleY(1);
    -ms-transform: scaleY(1);
    -o-transform: scaleY(1);
    transform: scaleY(1);
    height: 190px;
  }
}

With transform-origin it will scale from the top and not from the middle. BUT then you have to adjust the height every time you change the number of menu items.

  1. You write it new (is probably nothig for you because you wont change much). I think there are definitely easier solutions like your posted example. e.g. see HERE

Only the styles are missing and everything works.

I tried to change the height to % too, but that just never worked. Even add some divs and change some positions nothing happens. So maybe someone else has a better solution.

theoretisch
  • 1,718
  • 5
  • 24
  • 34
  • A for effort, but not reeeaaally a solution. And I'm only saying this because that's about how far I got as well. – Serg Chernata Jan 24 '17 at 15:49
  • I know, I tried a lot to figure out why its not working, but without any solution. Its strange that it only works with px and not %. I tried it with `margin-top` instead of `height` and there % worked pretty good. But anyway I really dont know why he makes all this so complicated. There are much easier solutions in angular. (But maybe he needs it so complicated) I'm curious about any other better solution! – theoretisch Jan 24 '17 at 16:01
  • I can't use the example you posted from Plunker because it needs Bootstrap to get that collapse functionality. This system uses Material Design instead. I'd hate to load an entire framework just for one little thing – LOTUSMS Jan 24 '17 at 21:38
  • ahh ok, thats an argument. – theoretisch Jan 25 '17 at 07:23
  • 1
    @theoretisch GREAT SOLUTION! After speeding the animation to the normal speed, it looks amazing specially in my system. Thanks man. You're a life saver! – LOTUSMS Jan 26 '17 at 13:44
2

Hopefully I wasn't to slow only just got time to look at this properly.

Edited Codepen

Now to start your main problem was using CSS animations rather then transitions. With transitions being better for this as you are transitioning from one state(open) to another(closed). Rather then a complex animation with no defined start or end state.

So what I've done is change your classes:

.sub-menu{
    background: #333;
    max-height: 500px;
    position: relative;
    display: block;
    overflow:hidden;
}
.sub-menu.ng-hide{
max-height: 0;
}

.sub-menu.ng-hide-remove {
    transition: max-height 700ms cubic-bezier(0.35, 0, 0.25, 1);
}

.sub-menu.ng-hide-add {
    transition: max-height 600ms cubic-bezier(0.35, 0, 0.25, 1);
}

They now use transisiton. As well as max-height rather than height so that no specific height value needs to be given to the submenu to fully show it. Also using cubic-bezier for smoother transitioning.

Also I removed the ng-animate="'animate'" directives on elements as it isn't needed, it is the old way of adding animations. All classes are now managed by the ng-show directive and there is no ng-animate directive. The current ngAnimate docs can give more info about the classes.

The only other change made was to move the ng-show to the div with the submenu class, which was just so an extra class didn't need to be created for the <ul>.

Callum
  • 845
  • 11
  • 22
  • I'm checking it on my phone and it looks good so far. I'll look at it further when I get to the office. Thanks – LOTUSMS Jan 24 '17 at 16:08
  • Looks good on desktop too! But I'm curious if someone knows why % not working. Is there something missing ? – theoretisch Jan 24 '17 at 16:21
  • 1
    For percentages to work there needs to be a fixed height in their somewhere. Which means each `submenu` would need a container with fixed height around it. So it can expand to 100% of that fixed height container. – Callum Jan 24 '17 at 17:15
  • It doesn't work for some reason. I have no animation whatsoever. Not sure why it works in codepen but not in my code. :/ – LOTUSMS Jan 24 '17 at 21:35
  • Ok, So I went through it extensively and still couldn't figure out why cubic-bezier doesn't work. But the method I applied does, except the scaleY may not be the best animation. I did some changes to it. Perhaps you can help me with a different animation type that could work better? – LOTUSMS Jan 24 '17 at 22:12
  • Only thing I can think of if classes are correct is are you using matching and up to date versions of angular and nganimate and is the ng animate dependency in you app correctly – Callum Jan 24 '17 at 22:13
  • Can switch out `cubic-bezier` for CCS premade like `ease` – Callum Jan 24 '17 at 22:15
  • Or other possible values and their descriptions instead of cubic curves can be seen [here](http://www.w3schools.com/css/css3_transitions.asp) – Callum Jan 24 '17 at 22:19