1

I'm trying to animate a div using ng-show with CSS3 transitions. There are 2 divs: One in the foreground and another hidden behind it. The hidden div should slide up when the user mouse's over the foreground div. It should also remain shown if the users cursor moves over the slide div. If the users cursor leaves the slide div or the foreground div, it should slide back down. It doesn't seem to work correctly though. Here's a plunker: http://plnkr.co/edit/C1RaDTOXwpEMECGMkt19?p=preview

Is the css correct?

div#cover {
  background-color: lightblue;
  width: 90px;
  height: 30px;
  position:absolute;
  bottom: 0px;
  z-index:10;
}


.slide {
  background-color: white;
  width: 90px;
  height: 30px;
  position:absolute;
  bottom: 0px;
  z-index:5;
}

.slide.ng-hide-add, .slide.ng-hide-remove { 
    transition: bottom 1s ease;
}

.slide.ng-hide-remove-active {
    bottom: 30px
}

.slide.ng-hide-add-active {
    bottom: 0px
}

Any ideas?

1 Answer 1

2

You only need two states:

  1. Shown
  2. Hidden

Let the base slide class define the state for shown (30px from bottom):

.slide {
  background-color: white;
  width: 90px;
  height: 30px;
  position: absolute;
  bottom: 30px;
  z-index: 5;
  transition: 1s ease bottom !important;
  display: block !important;
}

When the expression used in the ng-show directive is evaluated to false the hidden state will be activated and the class ng-hide will be added to the element by Angular.

Use that class to decorate the base class and define the hidden state (0px from bottom):

.slide.ng-hide {
  bottom: 0;
}

This means the two states will have the following classes when active:

  1. Shown: slide
  2. Hidden: slide ng-hide

As you see the slide class is always present, which is why the transition is put there.

You must use !important on the transition otherwise if you move the cursor back and forth over the element Angular will override it with transition: none briefly, which will cause the transition to interrupt and the element to snap into its final position.

You must also use display: block !important in the slide class to override the default behavior of ng-hide, which is display: none.

Demo: http://plnkr.co/edit/WN8v2riSYhhMyOgbZiWO?p=preview

Note: Personally I wouldn't recommend using ng-mouseenter or ng-mouseleave for this. Everytime they trigger the entire digest cycle and all watchers will be executed multiple times. The alternative would be to create a directive that uses event listeners to add/remove classes manually.

Sign up to request clarification or add additional context in comments.

3 Comments

Awesome, thanks for this! Just out of curiosity about final note, would changing the event to ng-mousedown just on the cover div prevent this problem?
You're welcome :) Yes, it should. The problem with ng-mouseenter and ng-mouseleave is that if you have a lot of them and a user moves the cursor across the screen, triggering multiple of them, you will have a bunch of unnecessary digest cycles. This can have a big impact on performance, especially on slower computers or mobile devices (unless your application is really thin of course). ng-mousedown is usually not triggered involuntarily as often.
I've used $watch here to register a watchExpression without a listener to console.log everytime one digest cycle runs: plnkr.co/edit/zn3L3mSy7asa6KtMi3yo?p=preview Try moving the cursor back and forth over the elements with the console opened and you will see how many of them are fired.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.