As you might already know, CSS transitions and animations allow you to animate a specific set of CSS properties. One of the properties that cannot be animated is the display property.
It would be great if you could do it, but it’s not currently possible and I’m guessing it never will be (e.g. how would you animate to “display: table”?). But there are ways to work around it, and I’ll present one way here.
Why the Need to Animate “display”?
The need to animate the display
property comes from wanting to solve the following problem:
- You want to make an element gradually disappear visually from the page.
- You don’t want that element to take up space after it has disappeared (i.e., you want the disappearance to cause reflow).
- You want to use CSS for the animation, not a library.
For this reason, animating opacity
to zero is simply not enough because an element with zero opacity still occupies the same space on the page.
Let’s look at how you might attempt to solve this problem, step by step.
Use Opacity and Display
The first thing you might think of doing is using both the opacity
property and the display
property. The HTML might look like this:
<div id="box" class="box"> </div> <button>TOGGLE VISIBILITY</button>
And the CSS might look like this:
.box { background: goldenrod; width: 300px; height: 300px; margin: 30px auto; transition: all 2s linear; display: block; } .hidden { display: none; opacity: 0; }
Notice I have display: none
and opacity: 0
on my “hidden” class. If you toggle this “hidden” class using JavaScript, you might have code that looks like this:
let box = document.getElementById('box'), btn = document.querySelector('button'); btn.addEventListener('click', function () { box.classList.toggle('hidden'); }, false);
But if you do that, you will not see the transition (defined in the .box
declaration block) take effect. Instead you’ll see this :
See the Pen
Trying to Mimic Animating to display:none by Louis Lazaris (@impressivewebs)
on CodePen.
Click the ‘toggle visibility’ button repeatedly and you’ll see the box disappear and appear suddenly, with no transition.
To fix this, you might try to separate the display
property from opacity
in your CSS:
.hidden { display: none; } .visuallyhidden { opacity: 0; }
Then you could toggle both classes:
var box = $('#box'); $('button').on('click', function () { box.toggleClass('visuallyhidden'); box.toggleClass('hidden'); });
But this won’t work, as shown in the demo below:
See the Pen
Trying to Animate to display:none (Part 2) by Louis Lazaris (@impressivewebs)
on CodePen.
What we want is for the element to disappear visually, then be removed from the page after it finishes disappearing visually, in a manner similar to a callback function.
(As a side point here, even if you combined opacity: 0
with visibility: hidden
, it would animate just fine but the element would still occupy space on the page after it disappears, so that won’t work either.)
Why Doesn’t This Work?
Before getting to my solution, I’ll just explain why you can’t do this by just changing the classes one after the other. First, if you’re adding classes like in the examples above, even if the transition worked, you’d have to set up a separate section for removing the classes and reverse how that’s done (i.e. if the box starts out hidden you have to first set it to display: block
, then change the opacity).
But that’s beside the point, because it doesn’t work anyhow. JavaScript executes one line after the other, but it doesn’t wait for all things associated with one line to be finished before executing the next line. (In other words, if you execute an animation or other asynchronous event on line 1, line 2 will proceed even if the animation isn’t done).
What’s happening is that the ‘opacity’ is attempting to animate immediately, and even if for a fraction of a millisecond it does start to animate, you won’t see it because the display: none
part will take effect just as quickly.
We can sum up the problem we want to solve as follows:
- When the element is visible, first animate the opacity, then, when that’s finished, make it
display: none
. - When the element is invisible, first make it
display: block
, then (while it’s still visually hidden, but existing on the page), animate the opacity.
A Possible Solution
There are probably other ways to do this, and I’d be glad to hear how you’d solve this problem. But here is my solution.
The CSS is the same (with the two ‘hidden’ classes still separated), but the JavaScript will look like this:
let box = document.getElementById('box'), btn = document.querySelector('button'); btn.addEventListener('click', function () { if (box.classList.contains('hidden')) { box.classList.remove('hidden'); setTimeout(function () { box.classList.remove('visuallyhidden'); }, 20); } else { box.classList.add('visuallyhidden'); box.addEventListener('transitionend', function(e) { box.classList.add('hidden'); }, { capture: false, once: true, passive: false }); } }, false);
And here it is in action:
See the Pen
Animating from display:none to display:block by Louis Lazaris (@impressivewebs)
on CodePen.
Here’s a summary of what the code does when the box is visible:
- Add the
visuallyhidden
class, which will animate it until it disappears. - At the same time that class is added, a single event handler is added using the
options
object in theaddEventListener()
method (a new feature with decent browser support), which tells the browser to wait for thetransitionend
event to occur once, then it stops looking. - The
transitionend
event fires when the opacity is done animating, and when this occurs the element is set todisplay: block
.
Because you can’t detect a transitionend
event on the display
property, you have to use a different method for when the box is invisible:
- First remove the
hidden
class, making itdisplay: block
while it’s still visually hidden. - While this is occuring, the script has executed a delay using
setTimeout()
, after which the opacity begins to animate.
The delay is very small (20 milliseconds), but because display: block
occurs instantly, you don’t need much of a delay at all, just enough to allow the element to take its full place on the page before animating the opacity. You might have to mess around with the timing in some cases, possibly going down to as little as a single millisecond.
And in case you want to start with a box that’s hidden and make it appear, you just have to ensure that both the hidden
and visuallyhidden
classes are on the box when it starts. Here’s a demo:
See the Pen
Animating from display:none to display:block by Louis Lazaris (@impressivewebs)
on CodePen.
If you don’t include both classes, the initial appearance won’t be animated.
How Would You Do It?
As mentioned, there are probably other ways to do this, or maybe there’s some improvement that could be made to my code.
Personally, I feel the use of setTimeout
is a bit lame and hacky. But hey, it works, and I don’t think it’s going to cause any problems unless you had tons of similar animations on the page. But that would be another issue altogether.
There are a few possible solutions to this on StackOverflow, but I find most, if not all, of the proposed solutions don’t really solve the problem at hand.
Feedback is welcome.
I usually avoid display:none and use instead transform:translate(9999px);
Yes, but that doesn’t solve the problem of removing the space occupied by the original element. Also, in your example, I don’t think you’d see the animation, because the translate transform would occur instantly, removing it from view.
My good sir you are a genius.. glad i scrolled to the comments this saved me a lot of headache. Thumbs up
That is wrong. If you attempt to hide an intractable component like that you can still access it via assistive technology. This does not lead to a good product.
Well. You’re doing it wrong. You should avoid moving the element far away. that is a very ugly hack.
I used to think that way I don’t used
display: none
, anddisplay: block
, I hide the element in terms of width and height, not knowing that the element is still visible in the document, and this effect harms accessibility.Though visually, we we’re able to hide the element but in terms of accessibility, the element is still visible. We imagine that we hide elements only for visual users, however for visually impaired users, user using screen readers, the element is visible for them. In this case, we harm their experience.
So therefore using
display: none
anddisplay: block
is essential, you may encounter this in creating responsive navbars as an example. When the breakpoint reach mobile view we need to hide the navbar and show the toggle menu button, we may use to set height or width to 0 but the navbar is visible in the document.By displaying it to none, we can assure that it’s not visible at the moment until the user toggles’ the menu button, which provides better experience not only for visual users but including visually impaired users.
What if you did something like the following: http://jsbin.com/IBumuMo/1/
Using
step-start
andstep-end
opens up a few other possibilities.Nice. In your example, I don’t think you need z-index. And you could use “height: 0” instead of the margin thing:
https://jsbin.com/lizinuq/edit?html,css,js,output
This is similar to one of the solutions on StackOverflow. Overall, I’m not crazy about all the extra CSS, but it does reduce the JS down to almost nothing, so it’s not a bad solution.
http://jsbin.com/nonoz/1
Would something like this be what you are talking about?
Yes, but you are dependent on the height for that. I would rather see a solution that doesn’t require a height on the element, so the full element is disappearing regardless of how big/small it is.
As for your comments about ‘height’, height should be manipulated in JS, not in CSS, as the GPU has to re-draw the bitmap for every pixel that the height is transitioned. Only do transforms in CSS, stuff that can be done in matrix math. Great article here on it
http://blogs.adobe.com/webplatform/2014/03/18/css-animations-and-transitions-performance/
That’s what I wanted. I hope you’ll have a wonderful day, chief!
How about a delay when the hidden class is added and no delay when removed?
Yep, this works fine (maybe needs adding some prefixes)! Transition delay of the ‘display’ property FTW!
Here it is in action: http://jsfiddle.net/xuv35/
It does not work in Chrome on OS X
Needs a unit (s) on the transition time for height.
This works in Firefox, Chrome, and Safari if you animate max-height instead of height.
Set the visible max-height to be something larger than the expected height.
Yay! An all-CSS solution!
Yes, max-height has been mentioned a couple of times in previous comments :)
Wow did this actually work in 2013? I don’t know when it stopped working but this no longer works in Chrome in 2023 :(.
great tips! I like this!!!!!!
It working prettry find for me !!!!
buy i make a little bit change
try it out!
all ease 300ms,display 0s;
JavaScript executes one line after the other, but it doesn’t wait for one line to be finished before executing the next line.
This is not true at all. JavaScript statements are not asynchronous, although they can invoke asynchronous behavior in other libraries. You may be referring to jQuery transitions here (which are asynchronous) but as written this statement is false. If JavaScript did not guarantee complete execution of one statement before executing the next, the language would be effectively useless.
Ah, you’re right. What I’m trying to say is that if the previous line contains an asynchronous event, then it will not wait for that one to finish (in this case, I’m referring to the result of the class being added/removed, which causes asynchronous events to occur). I’ll correct the wording.
How a bout keyframes?
Where the 0% would set the display property and the 1% – 99% do the opacity and 100% does the display again. ;-)
Here’s a small example (webkit, because lazy): http://codepen.io/TheDutchCoder/pen/KFisd
Codepen has a Prefix-free check-box. Use it and forget about prefixes.
Ha thanks, forgot about that!
The problem with this is that it won’t work on a variable/dynamic height element. It’s true, in my demos, I’m using a box that has a set height. But that’s only because of laziness, and wanting to simplify the demo.
I probably should have mentioned this in the article but the idea is that I don’t want to have a contstrained height value, but rather I’m assuming I don’t know the height of the element in question.
So yes, this solution sort of works, and it’s nice without JavaScript, but you’ll have to use some other method to get it to work without a known height.
Umm, I believe that what you did isn’t enough. Just like you said, when setting display: none on an element, it doesn’t just fade away. It also disappears and the page acts like the element weren’t there. So theoretically, you should animate the “disappearing” thing too, not just the opacity. And this means that after fading it away and before setting display: none to it, you should set the height to 0px smoothly (or width if content flow is horizontal).
I’ve updated my codepen to reflect that, I think that works better indeed.
Width and height are optional of course, depending on what you want animated.
I agree, from a visual standpoint, it’s probably jarring to see the content around flow into a new area so suddenly. So yes, you could animate height or width. That’s just one way to do it. And I think you’d also need to do “overflow: hidden” if you use that, depending on what’s inside the element.
But if you use height, then you have to have a specified height for the element, which is unlikely. Usually content dictates height. And you can’t animate to “height: auto”, so that’s not always an option. Of course there are workarounds for that too, but again, they always have some drawbacks.
To solve this in the past I’ve just animated min-height: property. If you have a rough idea of the general height it would have you can get away with using that to hide it.
If in the end you use so much JS, why would you not go for something like $(‘.box’).fadeToggle() ?
Because I want to use CSS animations, which generally the browser can optimize better. But probably in a case like this, using it one or two times wouldn’t matter. The idea is to try to get away from jQuery animations, leaving the animating part to CSS where I believe it is more appropriate.
Hi,
Nice article Louis.
It’s a shame that you can’t animate from height:auto to height:0 as usually that is what you want. However, if you need a fluid height then don’t use height but use max-height instead although you can’t actually animate the height you can create a decent fade effect and remove the element from the flow.
Here’s a codepen:
http://codepen.io/paulobrien/full/tpmAi
It’s not perfect but can be useful in certain situations and needs no JS in modern browsers (using the :checked pseudo class instead).
IMO playing with delays is the way to go. So you can combine opacity and top properties, which means our “fadeable” elements are always printed but they are offscreen.
If you absolutely need to support ie8 then you’d use opacity + top properties:
And if you don’t care about oldies, then you can go with opacity + translateY properties. This way is surely the best possible because your element gets uploaded to the GPU (translate property) and so you’ll get the lowest possible repaint cost. It could look like this:
Of course I omitted all the vendor prefixes in these little snippets.
Grunt (or Brunch) Autoprefixer FTW
In both those examples, you’re not really solving the problem I outlined at the beginning. In the case of both “top” and “translate”, the element is still going to take up the same amount of space on the page, so it will not cause reflow.
Your solution is fine if you want to just fade an element out, and don’t care about reflow. But if you want the original occupied space to be gone, then you have to use another method. For details on what I’m talking about, see this post:
http://www.impressivewebs.com/css-things-that-dont-occupy-space/
Playing with paddings and height works pretty fine to emulate the desired display effect: http://jsfiddle.net/catharsis/n5XfG/17/
Interesting.:) Adding the large top and bottom padding is a neat trick to make the height animate.
Well you need to add 0 padding and then only the needed padding to the container and it will be animated, because height: auto is not possible to animate right now.
How about scaleX(0.00001) as hidden state, then scaleX(1) as visible state, then couple that with opacity:0, opacity:.999 and transition both. scaleX(0.00001) gets the element out of view, like a better visibility: hidden, but uses hw acceleration.
Again, that would work fine in many circumstances, but not in the scenario I’ve presented in this post (which is, admittedly, not that common). As I mentioned to others, and in the article, stuff like transforms and opacity make things invisible but they don’t cause page reflow. In other words, if an element is 200×200 in size, if you shrink it down using scaleX/Y, it will still take up 200×200 pixels in space on the page.
The only way to do what you’re saying is to add “position: absolute” to the element, which takes it out of the flow. So I wonder if that would work better like that…. might be worth experimenting with.
Ah yes, I was assuming the element would be positioned absolute. I use the scale(0.0001) technique and it works well — for elements that are absolutely positioned.
If you need a reflow, then you should read a property which triggers it (e.g. “offsetWidth”). Here’s an eample:
Here’s the modified demo: http://jsbin.com/aQAXEDuy/1/
How about using
requestAnimationFrame()
instead, to wait for a “natural” reflow, rather than forcing a reflow?We could also do this animation without any JQuery or javascript by only css properies.
Some browser in client computers are javascript disabled for security reasons. So I think
that would be beneficial if you could also mentioned making animation with css only too.
I worked around the display none/block limitation by using height 0 like the earlier comments above. Needed to play an animation then remove it afterwards:
We often use JQuery because it is possible to make pages more user friendly and fun. Thanks for the useful tutorial.
Serkan
Thanks for the useful tutorial.
this is what i use:
I style my element in a way i want to display it and add display:none:
Then I create a keyframe animation
Add a class for the animation
I created a jquery function to handle display none which gets the timeout from the animation class and also has a callback function for after animation stuff…
Then I’m able to use any css3 Animation with keyframes on any object that has display none
from display block to display none i use another jQuery function that does basicly the same:
Very nice tutorial!
is it possible to animate the button to slide up after the box’s animation?
You may use ‘pointer-events:none’ with opacity to achieve the effects but with some fallback in >IE10.
we always look for nice transition techniques like this one. Thank you for the idea.
A beter way i thing
div.yourclass{
…
height: 0;
transition: opacity 0.3s
}
div.yourclass:hover{
height: 200px;
}
that code make just de opacity has transition :)
Thanks for the useful article, it works perfectly.
Well if I have to still use JavaScript… Why not use jQuery fadeIn and fadeOut function
Yep, that’s the simplest way, but the idea here was to try to figure out a way to do it with CSS performing the actual animation.
And if I wrote this today, I’d probably avoid jQuery and use plain JS.
Stumbled across this article with a similar problem. My solution is a little different from what I’ve seen and I’m cutting my teeth on JS.
I wrapped the hidden content in a div with ‘overflow: hidden’ and set its height to 1px (so I can calculate the height of the hidden content). When the click triggers, I set the wrapper height to the content’s height and fade in the content.
This way, CSS height animations still work, since the pixel value is set.
Three years later, but this comment really helped me, thanks!
I use this solution as well…
I would change the absolute position to be offscreen when the hidden class is applied
Hey, I really need help making this method work the other way around. So the initial div is hidden and by clicking a button I want it to fade in and then fade out (toggling). I want to use the method for an overlay menu.
Can you help me tweak the code?
Can you provide a demo of what you have so far? Also, doesn’t my final demo do exactly what you just said? I’m not sure what exactly you require beyond that. You might have to be more specific.
Ok, so, in your demo the div which the effect is applied on is initially visible whereas in my example the div is initially hidden. Imagine that I need to apply it on an overlay menu of a website and obviously on a website usually the overlay menu (which occupies the whole viewport) is initially hidden and then if you click a button (in my case the classic hamburger icon) it opens(fades in) and if you click it again it closes(fades out) and so on.
Conclusion: I basically need what your demo does but the other way around (from hidden to visible to start with instead of from visible to hidden to start with).
I managed to make it work by doing a workaround manually adding both classes “visuallyhidden” and “hidden” on the overlay menu div to start with. Example.
This is how I have the code in the HTML page to start with (it works) but.. I best believe this is not a best practice. I was wondering how do I tweak the code to make it work strictly with jQuery and CSS without manually adding “visuallyhidden” and “hidden”.
Let me know if this makes sense and if you still need me to provide a demo. Thanks a ton!
Based on my code from this article, what you’ve done is correct. That’s basically the only way to do it. Now, that being said, this is a bit of a hacky solution. But if that’s what you want, then yes, you just have to adjust the HTML classes so that it starts hidden.
If it requires a whole new function then I’ll just leave it as is. I tried manipulating the code but I couldn’t accomplish anything in my favor. I tried switching the classes from
visuallyhidden
tovisuallyshown
with"opacity:1"
andhidden
toshown
with"display:block"
, I added"display:none"
to the#menu_wrapper
but I always ended up with the the function adding thevisuallyshown
class but not theshown
class and then the function fell apart.Thanks again for the quick reply and keep up the great work!
Thanks for the post, I was able to create my own javascript for my website!
I typically use css transition on max-height, which allows for a sliding open/close of an element.
How can I use this to “show” a div instead of using toggle.
Meaning I have this layout:
I already have a script that ‘fades in’ the opacity to show the divs as a user scrolls to it, but I want to hide them with display:none so that the browser’s scroll bar looks small initially…
… so when the user scrolls to the concerned div, only then it shows up and ‘adds’ to the scroll bar.
Here is my demo of the scrolling opacity toggler:
https://output.jsbin.com/civuqu/edit</a.
Try this:
Thanks for sharing! I was getting obscure issue with the content on iOS. Was working on my Android phone though (ie. content that was set to opacity: 0 and visibility: hidden)
The below combination of JQuery’s “addClass & removeClass” (or Angularjs’s “ng-class”) along with the CSS @kayframe animation works perfectly for me in Chrome browser (did not check with other browsers)
Hmm, isn’t it easier to just use “position: absolute” on the element so it doesn’t take up any space? You can also place it in another container if you like. So something like in CSS:
HTML:
So every time you change the active element, it does the trick:
So this won’t work for everyone, but it solved my problem.
I wanted to hide links in the header when scrolled by adding a class with a css animation attached to it. I was able to hide the link by setting opacity to 0 but users could still click on it if they hovered over it. So, I just set the font size to 0 as well so the links wouldn’t show up, and wouldn’t take up any space. This only works with text obviously, but I’m thinking setting the height to 0 may produce a similar effect. The css looked like this:
Then I just toggled the class with jQuery with the link selector:
The link to Christian Heilmann’s solution is broken. Here is the correct link:
https://christianheilmann.com/2015/08/30/quicky-fading-in-a-newly-created-element-using-css/
Well, that’s dumb. He updated the post but didn’t redirect the old URL. Thanks, I’ll fix it.
Great post! Thank you so much!
Thank you very much, it’s work great for me :)
I just used width: 0; overflow: hidden; on element when hidden and width: 100%; when visible
thank you!!
overflow hidden worked for me !! :D
Hello everybody,
I like the initial idea about dispplay:none, and i found a way to use it in addition to use a fade with opacity. It’s based on a listener to know when an element has ended its transition.
I use this:
Hi,
Great post and a lot of useful comments.
Wonder if anyone could help me? So I have taken one of the solutions and trying to make it hide a div but the button stay where it is and not slide with the hidden div.
Here is a fiddle of it:
https://jsfiddle.net/Rick1107/resu6cqx/1/
Any help will be gratefully appreciated.
If you want the button to stay there, then you have to change the hiddenContent section to be like this:
You have to remove the height and margin. But I’m not sure if that’s what you want, because your comment wasn’t that clear.
Thanks Louis. Very much appreciated you understood my poor question perfectly and yes thats exactly what I wanted. Thank you!
Why not just set height and width to 0 on the element that has visibility:none? Not perfect, but it won’t take up any room on the screen and will allow transitions.
Generally when people are trying to animate display: none what they really want is:
Fade content in, and
Have the item not take up space in the document when hidden
Most popular answers use visibility, which can only achieve the first goal, but luckily it’s just as easy to achieve both by using position.
Since position: absolute removes the element from typing document flow spacing, you can toggle between position: absolute and position: static (global default), combined with opacity. See the below example.
source:
https://stackoverflow.com/questions/38772442/css-transition-from-display-none-to-display-block-navigation-with-subnav/38772750
How bout in reverse, starting with the display: none; then display: block.
The final demo on the page does that when you click the button a second time.
I mean starting with nothing then appearing, like as in a drop down box style if that makes sense. I tried reversing some of the properties around(like putting the box values in the hidden and visa versa and adjusting the js) but it doesn’t seem to register in the same way.
I’m making a header with a toggle button in it that when clicked has a unordered list with a bunch of lists in it appear underneath the header that display the menu.
I’ve got it all working I just want to add a sliding transition effect as the unordered list appears.
That’s not exactly what this code in the article is about. Maybe if you send me a CodePen demo or something, then I can help, but this article is attempting to solve a specific problem.
Your issue is just making something slide down, which is just a matter of adding some CSS and JS similar to what jQuery animations do.
Can you advise how to hide that yellow box by default and show it by pressing the button?
I want to apply this animation in Table of Contents but it does not work well. the transition was not showing properly. are you have any other method to show the transition.
Please post a CodePen demo and I’ll help you debug it.
There is an example by Marco Peralta at CodePen. I mixed it up with your’s, to eliminate the setTimeout() function.
https://elnet.ch/de/test/display-none
This is a good solution. If I were to write this solution today, I would definitely do what you’ve done, using the
transitionend
event along with theonce
option foraddEventListener
which I don’t believe existed when I first wrote this article.Here’s my solution
https://codepen.io/alfieindesigns/pen/eYJMKLZ
Couldn’t you use setTimeout in both appearing and disappearing? That is, if you set the transition to a certain interval in CSS, then can’t you just set your JS with the same interval (or a fraction longer)? It is interesting to use the transitionend listener, though. Thanks for the illustration of that event listener.
Works just fine, I just change the transition for smooth transition
transition: display 1s, opacity 500ms ease-in-out;
Your method is not a good solution when you have multiple transitions or if you want to change the timing of the transition.So I just inspected the YouTube page and found their secret.The secret life saver is “visibility” property.Their method is to add one extra element prior to the element you want to apply transitions .Then set the “display” property of all other elements after that to “block” or whatever you want but don’t set it to “none”.Now you can transition the “visibility” property of the extra element instead of transitioning the “display” property.Now you can add or remove classes from other elements when the button is pressed.They will be automatically transitioned without any problem.When you want to show the element set the “visibility” to “visible”.When you want to hide the element set the “visibility” to “hidden”.This works fine both in displaying and hiding a element.
Hi Kevin, instead of posting the code in a comment, can you please create a CodePen demo?
It helps a lot if readers can compare your solution if they can actually try it out. Thanks!
the first 3 suck its the same animation- the last one is good-
But why all this code for nothing?
Read the article, it outlines the process I took to try to find the best solution. The first 3 solutions didn’t work.
Hello, how can i implement that it is initially hidden at first and it can be shown at first click. I tried putting hidden in class first but it does not animate. Thank you
Good question! I added a new demo to demonstrate how to make that work. It turns out, you just have to add both of the
hidden
andvisuallyhidden
classes to the box to begin with, but the rest of the code stays the same.Thanks for the detailed blog post. I wrote a library called Onion to address this exact problem, please check it out at https://www.npmjs.com/package/onion and let me know what you think!
For all who hates jQuery:
$('.element').fadeOut(300);
Thanks for the post! I’ve been hunting for a solution too, and this is the best alternative I found that is pure CSS, feels less hacky, and works a treat for my use case:
https://jdsteinbach.com/css/snippet-animate-display-transform/
…at least until this becomes more widely adopted across vendors: https://developer.chrome.com/blog/entry-exit-animations