How to catch current css translate() position in javascript - javascript

I would like to animate element on the screen by arrows. It should change the direction immediately while translation. So if element go to right and I press down arrow in half of the animation it should go straight down and stop to go right. But how can I catch current x position of the element. offsetLeft does not work. It is still the same origin position. Is it possible to catch current position of animated element? Thanks.

I think you need to call element.getBoundingClientRect()
let circle = document.querySelector(".animate");
let style = window.getComputedStyle(circle);
setInterval(() => {
let rect = circle.getBoundingClientRect();
console.log(rect.left)
}, 1000)
div {
height: 100px;
width: 100px;
border-radius: 100px;
background: blue;
}
.animate {
animation: animate;
animation-duration: 3s;
animation-direction: alternate;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
#keyframes animate {
from {
transform: translate(0)
}
to {
transform: translate(calc(100vw - 120px))
}
}
<div class="animate"> </div>
Not sure why code snippet renders the entire element in console.log, but in an actual script it would return only the value.

Related

CSS Property: " transition-delay: 3s " is not working [duplicate]

I'm currently designing a CSS 'mega dropdown' menu - basically a regular CSS-only dropdown menu, but one that contains different types of content.
At the moment, it appears that CSS 3 transitions don't apply to the 'display' property, i.e., you can't do any sort of transition from display: none to display: block (or any combination).
Is there a way for the second-tier menu from the above example to 'fade in' when someone hovers over one of the top level menu items?
I'm aware that you can use transitions on the visibility: property, but I can't think of a way to use that effectively.
I've also tried using height, but that just failed miserably.
I'm also aware that it's trivial to achieve this using JavaScript, but I wanted to challenge myself to use just CSS, and I think I'm coming up a little short.
You can concatenate two transitions or more, and visibility is what comes handy this time.
div {
border: 1px solid #eee;
}
div > ul {
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity 0.5s linear;
}
div:hover > ul {
visibility: visible;
opacity: 1;
}
<div>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
(Don't forget the vendor prefixes to the transition property.)
More details are in this article.
You need to hide the element by other means in order to get this to work.
I accomplished the effect by positioning both <div>s absolutely and setting the hidden one to opacity: 0.
If you even toggle the display property from none to block, your transition on other elements will not occur.
To work around this, always allow the element to be display: block, but hide the element by adjusting any of these means:
Set the height to 0.
Set the opacity to 0.
Position the element outside of the frame of another element that has overflow: hidden.
There are likely more solutions, but you cannot perform a transition if you toggle the element to display: none. For example, you may attempt to try something like this:
div {
display: none;
transition: opacity 1s ease-out;
opacity: 0;
}
div.active {
opacity: 1;
display: block;
}
But that will not work. From my experience, I have found this to do nothing.
Because of this, you will always need to keep the element display: block - but you could get around it by doing something like this:
div {
transition: opacity 1s ease-out;
opacity: 0;
height: 0;
overflow: hidden;
}
div.active {
opacity: 1;
height: auto;
}
At the time of this post all major browsers disable CSS transitions if you try to change the display property, but CSS animations still work fine so we can use them as a workaround.
Example Code (you can apply it to your menu accordingly) Demo:
Add the following CSS to your stylesheet:
#-webkit-keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
#keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
Then apply the fadeIn animation to the child on parent hover (and of course set display: block):
.parent:hover .child {
display: block;
-webkit-animation: fadeIn 1s;
animation: fadeIn 1s;
}
Update 2019 - Method that also supports fading out:
(Some JavaScript code is required)
// We need to keep track of faded in elements so we can apply fade out later in CSS
document.addEventListener('animationstart', function (e) {
if (e.animationName === 'fade-in') {
e.target.classList.add('did-fade-in');
}
});
document.addEventListener('animationend', function (e) {
if (e.animationName === 'fade-out') {
e.target.classList.remove('did-fade-in');
}
});
div {
border: 5px solid;
padding: 10px;
}
div:hover {
border-color: red;
}
.parent .child {
display: none;
}
.parent:hover .child {
display: block;
animation: fade-in 1s;
}
.parent:not(:hover) .child.did-fade-in {
display: block;
animation: fade-out 1s;
}
#keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
<div class="parent">
Parent
<div class="child">
Child
</div>
</div>
Instead of callbacks, which don't exist in CSS, we can use transition-delay property.
#selector {
overflow: hidden; /* Hide the element content, while height = 0 */
height: 0;
opacity: 0;
transition: height 0ms 400ms, opacity 400ms 0ms;
}
#selector.visible {
height: auto; opacity: 1;
transition: height 0ms 0ms, opacity 600ms 0ms;
}
So, what's going on here?
When visible class is added, both height and opacity start animation without delay (0 ms), though height takes 0 ms to complete animation (equivalent of display: block) and opacity takes 600 ms.
When visible class is removed, opacity starts animation (0 ms delay, 400 ms duration), and height waits 400 ms and only then instantly (0 ms) restores initial value (equivalent of display: none in the animation callback).
Note, this approach is better than ones using visibility. In such cases, the element still occupies the space on the page, and it's not always suitable.
For more examples please refer to this article.
I suspect that the reason that transitions are disabled if display is changed is because of what display actually does. It does not change anything that could conceivably be smoothly animated.
display: none; and visibility: hidden; are two entirely different things.
Both do have the effect of making the element invisible, but with visibility: hidden; it’s still rendered in the layout, but just not visibly so.
The hidden element still takes up space, and is still rendered inline or as a block or block-inline or table or whatever the display element tells it to render as, and takes up space accordingly.
Other elements do not automatically move to occupy that space. The hidden element just doesn’t render its actual pixels to the output.
display: none on the other hand actually prevents the element from rendering entirely.
It does not take up any layout space.
Other elements that would’ve occupied some or all of the space taken up by this element now adjust to occupy that space, as if the element simply did not exist at all.
display is not just another visual attribute.
It establishes the entire rendering mode of the element, such as whether it’s a block, inline, inline-block, table, table-row, table-cell, list-item, or whatever!
Each of those have very different layout ramifications, and there would be no reasonable way to animate or smoothly transition them (try to imagine a smooth transition from block to inline or vice-versa, for instance!).
This is why transitions are disabled if display changes (even if the change is to or from none — none isn’t merely invisibility, it’s its own element rendering mode that means no rendering at all!).
display is not one of the properties that transition works upon.
See Animatable CSS properties for the list of CSS properties that can have transitions applied to them. See CSS Values and Units Module Level 4, Combining Values: Interpolation, Addition, and Accumulation for how they are interpolated.
Up to CSS 3 was listed in 9.1. Properties from CSS (just close the warning popup)
I've also tried using height, but that just failed miserably.
Last time I had to do this, I used max-height instead, which is an animatable property (although it was a bit of a hack, it did work), but beware that it may be very janky for complex pages or users with low-end mobile devices.
I found better way for this issue, you can use CSS Animation and make your awesome effect for showing items.
.item {
display: none;
}
.item:hover {
display: block;
animation: fade_in_show 0.5s
}
#keyframes fade_in_show {
0% {
opacity: 0;
transform: scale(0)
}
100% {
opacity: 1;
transform: scale(1)
}
}
You can add a custom animation to the block property now.
#keyframes showNav {
from {opacity: 0;}
to {opacity: 1;}
}
.subnav-is-opened .main-nav__secondary-nav {
display: block;
animation: showNav 250ms ease-in-out both;
}
Demo
In this demo the sub-menu changes from display:none to display:block and still manages to fade.
Fade it in with CSS Animations:
.item {
display: none;
}
.item:hover {
display: block;
animation: fadeIn 0.5s;
}
#keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
According to W3C Working Draft 19 November 2013 display is not an animatable property. Fortunately, visibility is animatable. You may chain its transition with a transition of opacity (JSFiddle):
HTML:
Foo
<button id="hide-button">Hide</button>
<button id="show-button">Show</button>
CSS:
#foo {
transition-property: visibility, opacity;
transition-duration: 0s, 1s;
}
#foo.hidden {
opacity: 0;
visibility: hidden;
transition-property: opacity, visibility;
transition-duration: 1s, 0s;
transition-delay: 0s, 1s;
}
JavaScript for testing:
var foo = document.getElementById('foo');
document.getElementById('hide-button').onclick = function () {
foo.className = 'hidden';
};
document.getElementById('show-button').onclick = function () {
foo.className = '';
};
Note that if you just make the link transparent, without setting visibility: hidden, then it would stay clickable.
Edit: display none is not being applied in this example.
#keyframes hide {
0% {
display: block;
opacity: 1;
}
99% {
display: block;
}
100% {
display: none;
opacity: 0;
}
}
What's happening above is that through 99% of the animation display is set to block while the opacity fades out. In the last moment display property is set to none.
And the most important bit is to retain the last frame after the animation ends using animation-fill-mode: forwards
.hide {
animation: hide 1s linear;
animation-fill-mode: forwards;
}
Here are two examples: https://jsfiddle.net/qwnz9tqg/3/
My neat JavaScript trick is to separate the entire scenario into two different functions!
To prepare things, one global variable is declared and one event handler is defined:
var tTimeout;
element.addEventListener("transitionend", afterTransition, true);//firefox
element.addEventListener("webkitTransitionEnd", afterTransition, true);//chrome
Then, when hiding element, I use something like this:
function hide(){
element.style.opacity = 0;
}
function afterTransition(){
element.style.display = 'none';
}
For reappearing the element, I am doing something like this:
function show(){
element.style.display = 'block';
tTimeout = setTimeout(timeoutShow, 100);
}
function timeoutShow(){
element.style.opacity = 1;
}
It works, so far!
I ran into this today, with a position: fixed modal that I was reusing. I couldn't keep it display: none and then animate it, as it just jumped into appearance, and and z-index (negative values, etc) did weird things as well.
I was also using a height: 0 to height: 100%, but it only worked when the modal appeared. This is the same as if you used left: -100% or something.
Then it struck me that there was a simple answer. Et voila:
First, your hidden modal. Notice the height is 0, and check out the height declaration in transitions... it has a 500ms, which is longer than my opacity transition. Remember, this affects the out-going fade-out transition: returning the modal to its default state.
#modal-overlay {
background: #999;
background: rgba(33,33,33,.2);
display: block;
overflow: hidden;
height: 0;
width: 100%;
position: fixed;
top: 0;
left: 0;
opacity: 0;
z-index: 1;
-webkit-transition: height 0s 500ms, opacity 300ms ease-in-out;
-moz-transition: height 0s 500ms, opacity 300ms ease-in-out;
-ms-transition: height 0s 500ms, opacity 300ms ease-in-out;
-o-transition: height 0s 500ms, opacity 300ms ease-in-out;
transition: height 0s 500ms, opacity 300ms ease-in-out;
}
Second, your visible modal. Say you're setting a .modal-active to the body. Now the height is 100%, and my transition has also changed. I want the height to be instantly changed, and the opacity to take 300ms.
.modal-active #modal-overlay {
height: 100%;
opacity: 1;
z-index: 90000;
-webkit-transition: height 0s, opacity 300ms ease-in-out;
-moz-transition: height 0s, opacity 300ms ease-in-out;
-ms-transition: height 0s, opacity 300ms ease-in-out;
-o-transition: height 0s, opacity 300ms ease-in-out;
transition: height 0s, opacity 300ms ease-in-out;
}
That's it, it works like a charm.
Taking from a few of these answers and some suggestions elsewhere, the following works great for hover menus (I'm using this with Bootstrap 3, specifically):
nav .dropdown-menu {
display: block;
overflow: hidden;
max-height: 0;
opacity: 0;
transition: max-height 500ms, opacity 300ms;
-webkit-transition: max-height 500ms, opacity 300ms;
}
nav .dropdown:hover .dropdown-menu {
max-height: 500px;
opacity: 1;
transition: max-height 0, opacity 300ms;
-webkit-transition: max-height 0, opacity 300ms;
}
You could also use height in place of max-height if you specify both values since height:auto is not allowed with transitions. The hover value of max-height needs to be greater than the height of the menu can possibly be.
It is as simple as the following :)
#keyframes fadeout {
0% { opacity: 1; height: auto; }
90% { opacity: 0; height: auto; }
100% { opacity: 0; height: 0;
}
animation: fadeout linear 0.5s 1 normal forwards !important;
Get it to fade away, and then make it height 0;. Also make sure to use forwards so that it stays in the final state.
I've came across this issue multiple times and now simply went with:
.block {
opacity: 1;
transition: opacity 250ms ease;
}
.block--invisible {
pointer-events: none;
opacity: 0;
}
By adding the class block--invisible the whole Elements will not be clickable but all Elements behind it will be because of the pointer-events:none which is supported by all major browsers (no IE < 11).
Change overflow:hidden to overflow:visible. It works better. I use like this:
#menu ul li ul {
background-color:#fe1c1c;
width:85px;
height:0px;
opacity:0;
box-shadow:1px 3px 10px #000000;
border-radius:3px;
z-index:1;
-webkit-transition:all 0.5s ease;
-moz-transition:all 0.6s ease;
}
#menu ul li:hover ul {
overflow:visible;
opacity:1;
height:140px;
}
visible is better because overflow:hidden act exactly like a display:none.
Well another way to apply transition in this situation without using keyframes is to set the width of your element to zero and then unset it on hover
.className{
visibility:hidden;
opacity: 0;
transition: .2s;
width:0;
}
.className:hover{
visibility:visible;
margin-right: .5rem;
opacity: 1;
width:unset;
}
I appreciate all the answers. Here is what I'm using for similar purposes: transition vs animation.
Example: https://jsfiddle.net/grinevri/tcod87Le/22/
<div class="animation"></div>
<div class="transition"></div>
#keyframes animationTo {
0% { background-color: rgba(0, 0, 0, 0.1); }
100% { background-color: rgba(0, 0, 0, 0.5); }
}
#keyframes animationFrom {
0% { background-color: rgba(0, 0, 0, 0.5); }
100% { background-color: rgba(0, 0, 0, 0.1); }
}
.animation,
.transition{
margin: 5px;
height: 100px;
width: 100px;
background-color: rgba(0, 0, 0, 0.1);
}
.animation{
animation: animationFrom 250ms;
}
.animation:hover{
background-color: rgba(0, 0, 0, 0.5);
animation: animationTo 250ms;
}
.transition{
transition: background-color 250ms;
}
.transition:hover{
background-color: rgba(0, 0, 0, 0.5);
}
I finally found a solution for me, by combining opacity with position absolute (not to occupy space when hidden).
.toggle {
opacity: 0;
position: absolute;
transition: opacity 0.8s;
}
.parent:hover .toggle {
opacity: 1;
position: static;
}
JavaScript is not required, and no outrageously huge max-height is needed. Instead, set your max-height on your text elements, and use a font relative unit such as rem or em. This way, you can set a maximum height larger than your container, while avoiding a delay or "popping" when the menu closes:
HTML
<nav>
<input type="checkbox" />
<ul>
<li>Link 1</li>
<li>Link 1</li>
<li>Link 1</li>
<li>Link 1</li>
</ul>
</nav>
CSS
nav input + ul li { // Notice I set max-height on li, not ul
max-height: 0;
}
nav input:checked + ul li {
max-height: 3rem; // A little bigger to allow for text-wrapping - but not outrageous
}
See an example here:
http://codepen.io/mindfullsilence/pen/DtzjE
After the accepted answer from Guillermo was written, the CSS
transition specification of 2012-04-03 changed the behavior of the visibility transition and now it is possible to solve this problem in a shorter way, without the use of transition-delay:
.myclass > div {
transition:visibility 1s, opacity 1s;
visibility:hidden; opacity:0
}
.myclass:hover > div
{ visibility:visible; opacity:1 }
The run time specified for both transitions should usually be
identical (although a slightly longer time for visibility is not a problem).
For a running version, see my blog post CSS Transition Visibility.
W.r.t. the title of the question "Transitions on the display: property" and in response to comments from Rui Marques and josh to the accepted answer:
This solution works in cases where it is irrelevant if the display or
visibility property is used (as it probably was the case in this question).
It will not completely remove the element as display:none, just make it invisible, but it still stays in the document flow and influences the position of the following elements.
Transitions that completely remove the element similar to display:none can be done using height (as indicated by other answers and comments), max-height, or margin-top/bottom, but also see
How can I transition height: 0; to height: auto; using CSS? and my blog post Workarounds for CSS Transitions on the Display and Height Properties.
In response to comment from GeorgeMillo:
Both properties and both transitions are needed: The opacity property
is used to create a fade-in and fade-out animation and the visibility
property to avoid the element still reacting on mouse
events. Transitions are needed on opacity for the visual effect and on
visibility to delay hiding until the fade-out is finished.
I suspect anyone just starting CSS transitions quickly discovers that they don't work if you're modifying the display property (block/none) at the same time. One workaround that hasn't yet been mentioned is that you can continue to use display:block/none to hide/show the element, but set its opacity to 0 so that even when it's display:block, it's still invisible.
Then to fade it in, add another CSS class such as "on" which sets the opacity to 1 and defines the transition for opacity. As you may have imagined, you'll have to use JavaScript to add that "on" class to the element, but at least you're still using CSS for the actual transition.
P.S. If you find yourself in a situation where you need to do both display:block, and add class "on", at the same time, defer the latter using setTimeout. Otherwise, the browser just sees both things as happening at once and disables the transition.
You can get this to work the natural way you expected - using display - but you have to throttle the browser to get it to work, using either Javascript or as others have suggested a fancy trick with one tag inside another. I don't care for the inner tag as it further complicates CSS and dimensions, so here's the Javascript solution:
https://jsfiddle.net/b9chris/hweyecu4/17/
Starting with a box like:
<div id="box" class="hidden">Lorem</div>
A hidden box.
div.hidden {
display: none;
}
#box {
transition: opacity 1s;
}
We're going to use a trick found in a related q/a, checking offsetHeight to throttle the browser instantaneously:
https://stackoverflow.com/a/16575811/176877
First, a library formalizing the above trick:
$.fn.noTrnsn = function () {
return this.each(function (i, tag) {
tag.style.transition = 'none';
});
};
$.fn.resumeTrnsn = function () {
return this.each(function (i, tag) {
tag.offsetHeight;
tag.style.transition = null;
});
};
Next, we're going to use it to reveal a box, and fade it in:
$('#button').on('click', function() {
var tag = $('#box');
if (tag.hasClass('hidden'))
tag.noTrnsn().removeClass('hidden')
.css({ opacity: 0 })
.resumeTrnsn().css({ opacity: 1 });
else
tag.css({ opacity: 0 });
});
This fades the box in and out. So, .noTrnsn() turns off transitions, then we remove the hidden class, which flips display from none to its default, block. We then set opacity to 0 to get ready for fading in. Now that we've set the stage, we turn transitions back on, with .resumeTrnsn(). And finally, kick off the transition by setting opacity to 1.
Without the library, both the change to display and the change to opacity would've gotten us undesirable results. If we simply removed the library calls, we'd get no transitions at all.
Note that the above does not set display to none again at the end of the fadeout animation. We can get fancier though. Let's do so with one that fades in and grows in height from 0.
Fancy!
https://jsfiddle.net/b9chris/hweyecu4/22/
#box {
transition: height 1s, opacity 1s;
}
We're now transitioning both height and opacity. Note that we are not setting height, which means it is the default, auto. Conventionally this cannot be transitioned - moving from auto to a pixel value (like 0) will get you no transition. We're going to work around that with the library, and one more library method:
$.fn.wait = function (time, fn) {
if (time)
this.delay(time);
if (!fn)
return this;
var _this = this;
return this.queue(function (n) {
fn.call(_this);
n();
});
};
This is a convenience method that lets us participate in jQuery's existing fx/animation queue, without requiring any of the animation framework that's now excluded in jQuery 3.x. I'm not going to explain how jQuery works, but suffice to say, the .queue() and .stop() plumbing that jQuery provides help us prevent our animations from stepping on each other.
Let's animate the slide down effect.
$('#button').on('click', function() {
var tag = $('#box');
if (tag.hasClass('hidden')) {
// Open it
// Measure it
tag.stop().noTrnsn().removeClass('hidden').css({
opacity: 0, height: 'auto'
});
var h = tag.height();
tag.css({ height: 0 }).resumeTrnsn()
// Animate it
.css({ opacity: 1, height: h })
.wait(1000, function() {
tag.css({ height: 'auto' });
});
} else {
// Close it
// Measure it
var h = tag.noTrnsn().height();
tag.stop().css({ height: h })
.resumeTrnsn()
// Animate it
.css({ opacity: 0, height: 0 })
.wait(1000, function() {
tag.addClass('hidden');
});
}
});
This code begins by checking on #box and whether it's currently hidden, by checking on its class. But it accomplishes more using the wait() library call, by adding the hidden class at the end of the slideout/fade animation, which you'd expect to find if it is in fact hidden - something the above simpler example could not do. This happens to also enable display/hiding the element over and over, which was a bug in the previous example, because the hidden class was never restored.
You can also see CSS and class changes being called after .noTrnsn() to generally set the stage for animations, including taking measurements, like measuring what will be the final height of #box without showing that to the user, before calling .resumeTrnsn(), and animating it from that fully-set stage to its goal CSS values.
Old Answer
https://jsfiddle.net/b9chris/hweyecu4/1/
You can have it transition on click with:
function toggleTransition() {
var el = $("div.box1");
if (el.length) {
el[0].className = "box";
el.stop().css({maxWidth: 10000}).animate({maxWidth: 10001}, 2000, function() {
el[0].className = "box hidden";
});
} else {
el = $("div.box");
el[0].className = "box";
el.stop().css({maxWidth: 10001}).animate({maxWidth: 10000}, 50, function() {
el[0].className = "box box1";
});
}
return el;
}
someTag.click(toggleTransition);
The CSS is what you'd guess:
.hidden {
display: none;
}
.box {
width: 100px;
height: 100px;
background-color: blue;
color: yellow;
font-size: 18px;
left: 20px;
top: 20px;
position: absolute;
-webkit-transform-origin: 0 50%;
transform-origin: 0 50%;
-webkit-transform: scale(.2);
transform: scale(.2);
-webkit-transition: transform 2s;
transition: transform 2s;
}
.box1{
-webkit-transform: scale(1);
transform: scale(1);
}
The key is throttling the display property. By removing the hidden class and then waiting 50 ms, then starting the transition via the added class, we get it to appear and then expand like we wanted, instead of it just blipping onto the screen without any animation. Similar occurs going the other way, except we wait till the animation is over before applying hidden.
Note: I'm abusing .animate(maxWidth) here to avoid setTimeout race conditions. setTimeout is quick to introduce hidden bugs when you or someone else picks up code unaware of it. .animate() can easily be killed with .stop(). I'm just using it to put a 50 ms or 2000 ms delay on the standard fx queue where it's easy to find/resolve by other coders building on top of this.
I had a similar issue that I couldn't find the answer to. A few Google searches later led me here. Considering I didn't find the simple answer I was hoping for, I stumbled upon a solution that is both elegant and effective.
It turns out the visibility CSS property has a value collapse which is generally used for table items. However, if used on any other elements it effectively renders them as hidden, pretty much the same as display: hidden but with the added ability that the element doesn't take up any space and you can still animate the element in question.
Below is a simple example of this in action.
function toggleVisibility() {
let exampleElement = document.querySelector('span');
if (exampleElement.classList.contains('visible')) {
return;
}
exampleElement.innerHTML = 'I will not take up space!';
exampleElement.classList.toggle('hidden');
exampleElement.classList.toggle('visible');
setTimeout(() => {
exampleElement.classList.toggle('visible');
exampleElement.classList.toggle('hidden');
}, 3000);
}
#main {
display: flex;
flex-direction: column;
width: 300px;
text-align: center;
}
.hidden {
visibility: collapse;
opacity: 0;
transition: visibility 2s, opacity 2s linear;
}
.visible {
visibility: visible;
opacity: 1;
transition: visibility 0.5s, opacity 0.5s linear;
}
<div id="main">
<button onclick="toggleVisibility()">Click Me!</button>
<span class="hidden"></span>
<span>I will get pushed back up...</span>
</div>
The simplest universal solution to the problem is: feel free to specify display:none in your CSS, however you will have change it to block (or whatever else) using JavaScript, and then you'll also have to add a class to your element in question that actually does the transition with setTimeout(). That's all.
I.e.:
<style>
#el {
display: none;
opacity: 0;
}
#el.auto-fade-in {
opacity: 1;
transition: all 1s ease-out; /* Future, future, please come sooner! */
-webkit-transition: all 1s ease-out;
-moz-transition: all 1s ease-out;
-o-transition: all 1s ease-out;
}
</style>
<div id=el>Well, well, well</div>
<script>
var el = document.getElementById('el');
el.style.display = 'block';
setTimeout(function () { el.className = 'auto-fade-in' }, 0);
</script>
This was tested in the latest sane browsers. Obviously it shouldn't work in Internet Explorer 9 or earlier.
I think SalmanPK has the closest answer. It does fade an item in or out, with the following CSS animations. However, the display property does not animate smoothly, only the opacity.
#-webkit-keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
#-webkit-keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
If you want to animate the element moving from display block to display none, I can't see that it is currently possible just with CSS. You have to get the height and use a CSS animation to decrease the height. This is possible with CSS as shown in the example below, but it would be tricky to know the exact height values you need to animate for an element.
jsFiddle example
CSS
#-webkit-keyframes pushDown {
0% {
height: 10em;
}
25% {
height: 7.5em;
}
50% {
height: 5em;
}
75% {
height: 2.5em;
}
100% {
height: 0em;
}
}
.push-down {
-webkit-animation: pushDown 2s forwards linear;
}
JavaScript
var element = document.getElementById("element");
// Push item down
element.className = element.className + " push-down";
This solution has excellent compatibility, and I haven't seen it yet:
.hidden-element {
position: absolute;
z-index: -1;
pointer-events: none;
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity .5s ease-out;
}
.hidden-element.visible {
position: static;
z-index: auto;
pointer-events: auto;
visibility: visible;
opacity: 1;
}
Explanation: it uses the visibility: hidden trick (which is compatible with “show-and-animate” in one step), but it uses the combination position: absolute; z-index: -1; pointer-events: none; to make sure that the hidden container does not take space and does not answer to user interactions.
You can do this with transition events, so you build two CSS classes for the transition, one holding the animation other, holding the display none state. And you switch them after the animation is ended? In my case I can display the divs again if I press a button, and remove both classes.
Try the snippet below...
$(document).ready(function() {
// Assign transition event
$("table").on("animationend webkitAnimationEnd", ".visibility_switch_off", function(event) {
// We check if this is the same animation we want
if (event.originalEvent.animationName == "col_hide_anim") {
// After the animation we assign this new class that basically hides the elements.
$(this).addClass("animation-helper-display-none");
}
});
$("button").click(function(event) {
$("table tr .hide-col").toggleClass(function() {
// We switch the animation class in a toggle fashion...
// and we know in that after the animation end, there
// is will the animation-helper-display-none extra
// class, that we nee to remove, when we want to
// show the elements again, depending on the toggle
// state, so we create a relation between them.
if ($(this).is(".animation-helper-display-none")) {
// I'm toggling and there is already the above class, then
// what we want it to show the elements , so we remove
// both classes...
return "visibility_switch_off animation-helper-display-none";
}
else {
// Here we just want to hide the elements, so we just
// add the animation class, the other will be added
// later be the animationend event...
return "visibility_switch_off";
}
});
});
});
table th {
background-color: grey;
}
table td {
background-color: white;
padding: 5px;
}
.animation-helper-display-none {
display: none;
}
table tr .visibility_switch_off {
animation-fill-mode: forwards;
animation-name: col_hide_anim;
animation-duration: 1s;
}
#-webkit-keyframes col_hide_anim {
0% {opacity: 1;}
100% {opacity: 0;}
}
#-moz-keyframes col_hide_anim {
0% {opacity: 1;}
100% {opacity: 0;}
}
#-o-keyframes col_hide_anim {
0% {opacity: 1;}
100% {opacity: 0;}
}
#keyframes col_hide_anim {
0% {opacity: 1;}
100% {opacity: 0;}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<theader>
<tr>
<th>Name</th>
<th class='hide-col'>Age</th>
<th>Country</th>
</tr>
</theader>
<tbody>
<tr>
<td>Name</td>
<td class='hide-col'>Age</td>
<td>Country</td>
</tr>
</tbody>
</table>
<button>Switch - Hide Age column with fadeout animation and display none after</button>
Instead of using display you could store the element 'off-screen' until you needed it, and then set its position to where you want it and transform it at the same time. This brings up a whole host of other design issues though, so your mileage may vary.
You probably wouldn't want to use display anyway, as you'd want the content to be accessible to screen readers, which for the most part try to obey rules for visibility - i.e., if it shouldn't be visible to the eye, it won't show up as content to the agent.

How to enable left to right transition effect on a div? [duplicate]

I'm currently designing a CSS 'mega dropdown' menu - basically a regular CSS-only dropdown menu, but one that contains different types of content.
At the moment, it appears that CSS 3 transitions don't apply to the 'display' property, i.e., you can't do any sort of transition from display: none to display: block (or any combination).
Is there a way for the second-tier menu from the above example to 'fade in' when someone hovers over one of the top level menu items?
I'm aware that you can use transitions on the visibility: property, but I can't think of a way to use that effectively.
I've also tried using height, but that just failed miserably.
I'm also aware that it's trivial to achieve this using JavaScript, but I wanted to challenge myself to use just CSS, and I think I'm coming up a little short.
You can concatenate two transitions or more, and visibility is what comes handy this time.
div {
border: 1px solid #eee;
}
div > ul {
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity 0.5s linear;
}
div:hover > ul {
visibility: visible;
opacity: 1;
}
<div>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
(Don't forget the vendor prefixes to the transition property.)
More details are in this article.
You need to hide the element by other means in order to get this to work.
I accomplished the effect by positioning both <div>s absolutely and setting the hidden one to opacity: 0.
If you even toggle the display property from none to block, your transition on other elements will not occur.
To work around this, always allow the element to be display: block, but hide the element by adjusting any of these means:
Set the height to 0.
Set the opacity to 0.
Position the element outside of the frame of another element that has overflow: hidden.
There are likely more solutions, but you cannot perform a transition if you toggle the element to display: none. For example, you may attempt to try something like this:
div {
display: none;
transition: opacity 1s ease-out;
opacity: 0;
}
div.active {
opacity: 1;
display: block;
}
But that will not work. From my experience, I have found this to do nothing.
Because of this, you will always need to keep the element display: block - but you could get around it by doing something like this:
div {
transition: opacity 1s ease-out;
opacity: 0;
height: 0;
overflow: hidden;
}
div.active {
opacity: 1;
height: auto;
}
At the time of this post all major browsers disable CSS transitions if you try to change the display property, but CSS animations still work fine so we can use them as a workaround.
Example Code (you can apply it to your menu accordingly) Demo:
Add the following CSS to your stylesheet:
#-webkit-keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
#keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
Then apply the fadeIn animation to the child on parent hover (and of course set display: block):
.parent:hover .child {
display: block;
-webkit-animation: fadeIn 1s;
animation: fadeIn 1s;
}
Update 2019 - Method that also supports fading out:
(Some JavaScript code is required)
// We need to keep track of faded in elements so we can apply fade out later in CSS
document.addEventListener('animationstart', function (e) {
if (e.animationName === 'fade-in') {
e.target.classList.add('did-fade-in');
}
});
document.addEventListener('animationend', function (e) {
if (e.animationName === 'fade-out') {
e.target.classList.remove('did-fade-in');
}
});
div {
border: 5px solid;
padding: 10px;
}
div:hover {
border-color: red;
}
.parent .child {
display: none;
}
.parent:hover .child {
display: block;
animation: fade-in 1s;
}
.parent:not(:hover) .child.did-fade-in {
display: block;
animation: fade-out 1s;
}
#keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
<div class="parent">
Parent
<div class="child">
Child
</div>
</div>
Instead of callbacks, which don't exist in CSS, we can use transition-delay property.
#selector {
overflow: hidden; /* Hide the element content, while height = 0 */
height: 0;
opacity: 0;
transition: height 0ms 400ms, opacity 400ms 0ms;
}
#selector.visible {
height: auto; opacity: 1;
transition: height 0ms 0ms, opacity 600ms 0ms;
}
So, what's going on here?
When visible class is added, both height and opacity start animation without delay (0 ms), though height takes 0 ms to complete animation (equivalent of display: block) and opacity takes 600 ms.
When visible class is removed, opacity starts animation (0 ms delay, 400 ms duration), and height waits 400 ms and only then instantly (0 ms) restores initial value (equivalent of display: none in the animation callback).
Note, this approach is better than ones using visibility. In such cases, the element still occupies the space on the page, and it's not always suitable.
For more examples please refer to this article.
I suspect that the reason that transitions are disabled if display is changed is because of what display actually does. It does not change anything that could conceivably be smoothly animated.
display: none; and visibility: hidden; are two entirely different things.
Both do have the effect of making the element invisible, but with visibility: hidden; it’s still rendered in the layout, but just not visibly so.
The hidden element still takes up space, and is still rendered inline or as a block or block-inline or table or whatever the display element tells it to render as, and takes up space accordingly.
Other elements do not automatically move to occupy that space. The hidden element just doesn’t render its actual pixels to the output.
display: none on the other hand actually prevents the element from rendering entirely.
It does not take up any layout space.
Other elements that would’ve occupied some or all of the space taken up by this element now adjust to occupy that space, as if the element simply did not exist at all.
display is not just another visual attribute.
It establishes the entire rendering mode of the element, such as whether it’s a block, inline, inline-block, table, table-row, table-cell, list-item, or whatever!
Each of those have very different layout ramifications, and there would be no reasonable way to animate or smoothly transition them (try to imagine a smooth transition from block to inline or vice-versa, for instance!).
This is why transitions are disabled if display changes (even if the change is to or from none — none isn’t merely invisibility, it’s its own element rendering mode that means no rendering at all!).
display is not one of the properties that transition works upon.
See Animatable CSS properties for the list of CSS properties that can have transitions applied to them. See CSS Values and Units Module Level 4, Combining Values: Interpolation, Addition, and Accumulation for how they are interpolated.
Up to CSS 3 was listed in 9.1. Properties from CSS (just close the warning popup)
I've also tried using height, but that just failed miserably.
Last time I had to do this, I used max-height instead, which is an animatable property (although it was a bit of a hack, it did work), but beware that it may be very janky for complex pages or users with low-end mobile devices.
I found better way for this issue, you can use CSS Animation and make your awesome effect for showing items.
.item {
display: none;
}
.item:hover {
display: block;
animation: fade_in_show 0.5s
}
#keyframes fade_in_show {
0% {
opacity: 0;
transform: scale(0)
}
100% {
opacity: 1;
transform: scale(1)
}
}
You can add a custom animation to the block property now.
#keyframes showNav {
from {opacity: 0;}
to {opacity: 1;}
}
.subnav-is-opened .main-nav__secondary-nav {
display: block;
animation: showNav 250ms ease-in-out both;
}
Demo
In this demo the sub-menu changes from display:none to display:block and still manages to fade.
Fade it in with CSS Animations:
.item {
display: none;
}
.item:hover {
display: block;
animation: fadeIn 0.5s;
}
#keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
According to W3C Working Draft 19 November 2013 display is not an animatable property. Fortunately, visibility is animatable. You may chain its transition with a transition of opacity (JSFiddle):
HTML:
Foo
<button id="hide-button">Hide</button>
<button id="show-button">Show</button>
CSS:
#foo {
transition-property: visibility, opacity;
transition-duration: 0s, 1s;
}
#foo.hidden {
opacity: 0;
visibility: hidden;
transition-property: opacity, visibility;
transition-duration: 1s, 0s;
transition-delay: 0s, 1s;
}
JavaScript for testing:
var foo = document.getElementById('foo');
document.getElementById('hide-button').onclick = function () {
foo.className = 'hidden';
};
document.getElementById('show-button').onclick = function () {
foo.className = '';
};
Note that if you just make the link transparent, without setting visibility: hidden, then it would stay clickable.
Edit: display none is not being applied in this example.
#keyframes hide {
0% {
display: block;
opacity: 1;
}
99% {
display: block;
}
100% {
display: none;
opacity: 0;
}
}
What's happening above is that through 99% of the animation display is set to block while the opacity fades out. In the last moment display property is set to none.
And the most important bit is to retain the last frame after the animation ends using animation-fill-mode: forwards
.hide {
animation: hide 1s linear;
animation-fill-mode: forwards;
}
Here are two examples: https://jsfiddle.net/qwnz9tqg/3/
My neat JavaScript trick is to separate the entire scenario into two different functions!
To prepare things, one global variable is declared and one event handler is defined:
var tTimeout;
element.addEventListener("transitionend", afterTransition, true);//firefox
element.addEventListener("webkitTransitionEnd", afterTransition, true);//chrome
Then, when hiding element, I use something like this:
function hide(){
element.style.opacity = 0;
}
function afterTransition(){
element.style.display = 'none';
}
For reappearing the element, I am doing something like this:
function show(){
element.style.display = 'block';
tTimeout = setTimeout(timeoutShow, 100);
}
function timeoutShow(){
element.style.opacity = 1;
}
It works, so far!
I ran into this today, with a position: fixed modal that I was reusing. I couldn't keep it display: none and then animate it, as it just jumped into appearance, and and z-index (negative values, etc) did weird things as well.
I was also using a height: 0 to height: 100%, but it only worked when the modal appeared. This is the same as if you used left: -100% or something.
Then it struck me that there was a simple answer. Et voila:
First, your hidden modal. Notice the height is 0, and check out the height declaration in transitions... it has a 500ms, which is longer than my opacity transition. Remember, this affects the out-going fade-out transition: returning the modal to its default state.
#modal-overlay {
background: #999;
background: rgba(33,33,33,.2);
display: block;
overflow: hidden;
height: 0;
width: 100%;
position: fixed;
top: 0;
left: 0;
opacity: 0;
z-index: 1;
-webkit-transition: height 0s 500ms, opacity 300ms ease-in-out;
-moz-transition: height 0s 500ms, opacity 300ms ease-in-out;
-ms-transition: height 0s 500ms, opacity 300ms ease-in-out;
-o-transition: height 0s 500ms, opacity 300ms ease-in-out;
transition: height 0s 500ms, opacity 300ms ease-in-out;
}
Second, your visible modal. Say you're setting a .modal-active to the body. Now the height is 100%, and my transition has also changed. I want the height to be instantly changed, and the opacity to take 300ms.
.modal-active #modal-overlay {
height: 100%;
opacity: 1;
z-index: 90000;
-webkit-transition: height 0s, opacity 300ms ease-in-out;
-moz-transition: height 0s, opacity 300ms ease-in-out;
-ms-transition: height 0s, opacity 300ms ease-in-out;
-o-transition: height 0s, opacity 300ms ease-in-out;
transition: height 0s, opacity 300ms ease-in-out;
}
That's it, it works like a charm.
Taking from a few of these answers and some suggestions elsewhere, the following works great for hover menus (I'm using this with Bootstrap 3, specifically):
nav .dropdown-menu {
display: block;
overflow: hidden;
max-height: 0;
opacity: 0;
transition: max-height 500ms, opacity 300ms;
-webkit-transition: max-height 500ms, opacity 300ms;
}
nav .dropdown:hover .dropdown-menu {
max-height: 500px;
opacity: 1;
transition: max-height 0, opacity 300ms;
-webkit-transition: max-height 0, opacity 300ms;
}
You could also use height in place of max-height if you specify both values since height:auto is not allowed with transitions. The hover value of max-height needs to be greater than the height of the menu can possibly be.
It is as simple as the following :)
#keyframes fadeout {
0% { opacity: 1; height: auto; }
90% { opacity: 0; height: auto; }
100% { opacity: 0; height: 0;
}
animation: fadeout linear 0.5s 1 normal forwards !important;
Get it to fade away, and then make it height 0;. Also make sure to use forwards so that it stays in the final state.
I've came across this issue multiple times and now simply went with:
.block {
opacity: 1;
transition: opacity 250ms ease;
}
.block--invisible {
pointer-events: none;
opacity: 0;
}
By adding the class block--invisible the whole Elements will not be clickable but all Elements behind it will be because of the pointer-events:none which is supported by all major browsers (no IE < 11).
Change overflow:hidden to overflow:visible. It works better. I use like this:
#menu ul li ul {
background-color:#fe1c1c;
width:85px;
height:0px;
opacity:0;
box-shadow:1px 3px 10px #000000;
border-radius:3px;
z-index:1;
-webkit-transition:all 0.5s ease;
-moz-transition:all 0.6s ease;
}
#menu ul li:hover ul {
overflow:visible;
opacity:1;
height:140px;
}
visible is better because overflow:hidden act exactly like a display:none.
Well another way to apply transition in this situation without using keyframes is to set the width of your element to zero and then unset it on hover
.className{
visibility:hidden;
opacity: 0;
transition: .2s;
width:0;
}
.className:hover{
visibility:visible;
margin-right: .5rem;
opacity: 1;
width:unset;
}
I appreciate all the answers. Here is what I'm using for similar purposes: transition vs animation.
Example: https://jsfiddle.net/grinevri/tcod87Le/22/
<div class="animation"></div>
<div class="transition"></div>
#keyframes animationTo {
0% { background-color: rgba(0, 0, 0, 0.1); }
100% { background-color: rgba(0, 0, 0, 0.5); }
}
#keyframes animationFrom {
0% { background-color: rgba(0, 0, 0, 0.5); }
100% { background-color: rgba(0, 0, 0, 0.1); }
}
.animation,
.transition{
margin: 5px;
height: 100px;
width: 100px;
background-color: rgba(0, 0, 0, 0.1);
}
.animation{
animation: animationFrom 250ms;
}
.animation:hover{
background-color: rgba(0, 0, 0, 0.5);
animation: animationTo 250ms;
}
.transition{
transition: background-color 250ms;
}
.transition:hover{
background-color: rgba(0, 0, 0, 0.5);
}
I finally found a solution for me, by combining opacity with position absolute (not to occupy space when hidden).
.toggle {
opacity: 0;
position: absolute;
transition: opacity 0.8s;
}
.parent:hover .toggle {
opacity: 1;
position: static;
}
JavaScript is not required, and no outrageously huge max-height is needed. Instead, set your max-height on your text elements, and use a font relative unit such as rem or em. This way, you can set a maximum height larger than your container, while avoiding a delay or "popping" when the menu closes:
HTML
<nav>
<input type="checkbox" />
<ul>
<li>Link 1</li>
<li>Link 1</li>
<li>Link 1</li>
<li>Link 1</li>
</ul>
</nav>
CSS
nav input + ul li { // Notice I set max-height on li, not ul
max-height: 0;
}
nav input:checked + ul li {
max-height: 3rem; // A little bigger to allow for text-wrapping - but not outrageous
}
See an example here:
http://codepen.io/mindfullsilence/pen/DtzjE
After the accepted answer from Guillermo was written, the CSS
transition specification of 2012-04-03 changed the behavior of the visibility transition and now it is possible to solve this problem in a shorter way, without the use of transition-delay:
.myclass > div {
transition:visibility 1s, opacity 1s;
visibility:hidden; opacity:0
}
.myclass:hover > div
{ visibility:visible; opacity:1 }
The run time specified for both transitions should usually be
identical (although a slightly longer time for visibility is not a problem).
For a running version, see my blog post CSS Transition Visibility.
W.r.t. the title of the question "Transitions on the display: property" and in response to comments from Rui Marques and josh to the accepted answer:
This solution works in cases where it is irrelevant if the display or
visibility property is used (as it probably was the case in this question).
It will not completely remove the element as display:none, just make it invisible, but it still stays in the document flow and influences the position of the following elements.
Transitions that completely remove the element similar to display:none can be done using height (as indicated by other answers and comments), max-height, or margin-top/bottom, but also see
How can I transition height: 0; to height: auto; using CSS? and my blog post Workarounds for CSS Transitions on the Display and Height Properties.
In response to comment from GeorgeMillo:
Both properties and both transitions are needed: The opacity property
is used to create a fade-in and fade-out animation and the visibility
property to avoid the element still reacting on mouse
events. Transitions are needed on opacity for the visual effect and on
visibility to delay hiding until the fade-out is finished.
I suspect anyone just starting CSS transitions quickly discovers that they don't work if you're modifying the display property (block/none) at the same time. One workaround that hasn't yet been mentioned is that you can continue to use display:block/none to hide/show the element, but set its opacity to 0 so that even when it's display:block, it's still invisible.
Then to fade it in, add another CSS class such as "on" which sets the opacity to 1 and defines the transition for opacity. As you may have imagined, you'll have to use JavaScript to add that "on" class to the element, but at least you're still using CSS for the actual transition.
P.S. If you find yourself in a situation where you need to do both display:block, and add class "on", at the same time, defer the latter using setTimeout. Otherwise, the browser just sees both things as happening at once and disables the transition.
You can get this to work the natural way you expected - using display - but you have to throttle the browser to get it to work, using either Javascript or as others have suggested a fancy trick with one tag inside another. I don't care for the inner tag as it further complicates CSS and dimensions, so here's the Javascript solution:
https://jsfiddle.net/b9chris/hweyecu4/17/
Starting with a box like:
<div id="box" class="hidden">Lorem</div>
A hidden box.
div.hidden {
display: none;
}
#box {
transition: opacity 1s;
}
We're going to use a trick found in a related q/a, checking offsetHeight to throttle the browser instantaneously:
https://stackoverflow.com/a/16575811/176877
First, a library formalizing the above trick:
$.fn.noTrnsn = function () {
return this.each(function (i, tag) {
tag.style.transition = 'none';
});
};
$.fn.resumeTrnsn = function () {
return this.each(function (i, tag) {
tag.offsetHeight;
tag.style.transition = null;
});
};
Next, we're going to use it to reveal a box, and fade it in:
$('#button').on('click', function() {
var tag = $('#box');
if (tag.hasClass('hidden'))
tag.noTrnsn().removeClass('hidden')
.css({ opacity: 0 })
.resumeTrnsn().css({ opacity: 1 });
else
tag.css({ opacity: 0 });
});
This fades the box in and out. So, .noTrnsn() turns off transitions, then we remove the hidden class, which flips display from none to its default, block. We then set opacity to 0 to get ready for fading in. Now that we've set the stage, we turn transitions back on, with .resumeTrnsn(). And finally, kick off the transition by setting opacity to 1.
Without the library, both the change to display and the change to opacity would've gotten us undesirable results. If we simply removed the library calls, we'd get no transitions at all.
Note that the above does not set display to none again at the end of the fadeout animation. We can get fancier though. Let's do so with one that fades in and grows in height from 0.
Fancy!
https://jsfiddle.net/b9chris/hweyecu4/22/
#box {
transition: height 1s, opacity 1s;
}
We're now transitioning both height and opacity. Note that we are not setting height, which means it is the default, auto. Conventionally this cannot be transitioned - moving from auto to a pixel value (like 0) will get you no transition. We're going to work around that with the library, and one more library method:
$.fn.wait = function (time, fn) {
if (time)
this.delay(time);
if (!fn)
return this;
var _this = this;
return this.queue(function (n) {
fn.call(_this);
n();
});
};
This is a convenience method that lets us participate in jQuery's existing fx/animation queue, without requiring any of the animation framework that's now excluded in jQuery 3.x. I'm not going to explain how jQuery works, but suffice to say, the .queue() and .stop() plumbing that jQuery provides help us prevent our animations from stepping on each other.
Let's animate the slide down effect.
$('#button').on('click', function() {
var tag = $('#box');
if (tag.hasClass('hidden')) {
// Open it
// Measure it
tag.stop().noTrnsn().removeClass('hidden').css({
opacity: 0, height: 'auto'
});
var h = tag.height();
tag.css({ height: 0 }).resumeTrnsn()
// Animate it
.css({ opacity: 1, height: h })
.wait(1000, function() {
tag.css({ height: 'auto' });
});
} else {
// Close it
// Measure it
var h = tag.noTrnsn().height();
tag.stop().css({ height: h })
.resumeTrnsn()
// Animate it
.css({ opacity: 0, height: 0 })
.wait(1000, function() {
tag.addClass('hidden');
});
}
});
This code begins by checking on #box and whether it's currently hidden, by checking on its class. But it accomplishes more using the wait() library call, by adding the hidden class at the end of the slideout/fade animation, which you'd expect to find if it is in fact hidden - something the above simpler example could not do. This happens to also enable display/hiding the element over and over, which was a bug in the previous example, because the hidden class was never restored.
You can also see CSS and class changes being called after .noTrnsn() to generally set the stage for animations, including taking measurements, like measuring what will be the final height of #box without showing that to the user, before calling .resumeTrnsn(), and animating it from that fully-set stage to its goal CSS values.
Old Answer
https://jsfiddle.net/b9chris/hweyecu4/1/
You can have it transition on click with:
function toggleTransition() {
var el = $("div.box1");
if (el.length) {
el[0].className = "box";
el.stop().css({maxWidth: 10000}).animate({maxWidth: 10001}, 2000, function() {
el[0].className = "box hidden";
});
} else {
el = $("div.box");
el[0].className = "box";
el.stop().css({maxWidth: 10001}).animate({maxWidth: 10000}, 50, function() {
el[0].className = "box box1";
});
}
return el;
}
someTag.click(toggleTransition);
The CSS is what you'd guess:
.hidden {
display: none;
}
.box {
width: 100px;
height: 100px;
background-color: blue;
color: yellow;
font-size: 18px;
left: 20px;
top: 20px;
position: absolute;
-webkit-transform-origin: 0 50%;
transform-origin: 0 50%;
-webkit-transform: scale(.2);
transform: scale(.2);
-webkit-transition: transform 2s;
transition: transform 2s;
}
.box1{
-webkit-transform: scale(1);
transform: scale(1);
}
The key is throttling the display property. By removing the hidden class and then waiting 50 ms, then starting the transition via the added class, we get it to appear and then expand like we wanted, instead of it just blipping onto the screen without any animation. Similar occurs going the other way, except we wait till the animation is over before applying hidden.
Note: I'm abusing .animate(maxWidth) here to avoid setTimeout race conditions. setTimeout is quick to introduce hidden bugs when you or someone else picks up code unaware of it. .animate() can easily be killed with .stop(). I'm just using it to put a 50 ms or 2000 ms delay on the standard fx queue where it's easy to find/resolve by other coders building on top of this.
I had a similar issue that I couldn't find the answer to. A few Google searches later led me here. Considering I didn't find the simple answer I was hoping for, I stumbled upon a solution that is both elegant and effective.
It turns out the visibility CSS property has a value collapse which is generally used for table items. However, if used on any other elements it effectively renders them as hidden, pretty much the same as display: hidden but with the added ability that the element doesn't take up any space and you can still animate the element in question.
Below is a simple example of this in action.
function toggleVisibility() {
let exampleElement = document.querySelector('span');
if (exampleElement.classList.contains('visible')) {
return;
}
exampleElement.innerHTML = 'I will not take up space!';
exampleElement.classList.toggle('hidden');
exampleElement.classList.toggle('visible');
setTimeout(() => {
exampleElement.classList.toggle('visible');
exampleElement.classList.toggle('hidden');
}, 3000);
}
#main {
display: flex;
flex-direction: column;
width: 300px;
text-align: center;
}
.hidden {
visibility: collapse;
opacity: 0;
transition: visibility 2s, opacity 2s linear;
}
.visible {
visibility: visible;
opacity: 1;
transition: visibility 0.5s, opacity 0.5s linear;
}
<div id="main">
<button onclick="toggleVisibility()">Click Me!</button>
<span class="hidden"></span>
<span>I will get pushed back up...</span>
</div>
The simplest universal solution to the problem is: feel free to specify display:none in your CSS, however you will have change it to block (or whatever else) using JavaScript, and then you'll also have to add a class to your element in question that actually does the transition with setTimeout(). That's all.
I.e.:
<style>
#el {
display: none;
opacity: 0;
}
#el.auto-fade-in {
opacity: 1;
transition: all 1s ease-out; /* Future, future, please come sooner! */
-webkit-transition: all 1s ease-out;
-moz-transition: all 1s ease-out;
-o-transition: all 1s ease-out;
}
</style>
<div id=el>Well, well, well</div>
<script>
var el = document.getElementById('el');
el.style.display = 'block';
setTimeout(function () { el.className = 'auto-fade-in' }, 0);
</script>
This was tested in the latest sane browsers. Obviously it shouldn't work in Internet Explorer 9 or earlier.
I think SalmanPK has the closest answer. It does fade an item in or out, with the following CSS animations. However, the display property does not animate smoothly, only the opacity.
#-webkit-keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
#-webkit-keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
If you want to animate the element moving from display block to display none, I can't see that it is currently possible just with CSS. You have to get the height and use a CSS animation to decrease the height. This is possible with CSS as shown in the example below, but it would be tricky to know the exact height values you need to animate for an element.
jsFiddle example
CSS
#-webkit-keyframes pushDown {
0% {
height: 10em;
}
25% {
height: 7.5em;
}
50% {
height: 5em;
}
75% {
height: 2.5em;
}
100% {
height: 0em;
}
}
.push-down {
-webkit-animation: pushDown 2s forwards linear;
}
JavaScript
var element = document.getElementById("element");
// Push item down
element.className = element.className + " push-down";
This solution has excellent compatibility, and I haven't seen it yet:
.hidden-element {
position: absolute;
z-index: -1;
pointer-events: none;
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity .5s ease-out;
}
.hidden-element.visible {
position: static;
z-index: auto;
pointer-events: auto;
visibility: visible;
opacity: 1;
}
Explanation: it uses the visibility: hidden trick (which is compatible with “show-and-animate” in one step), but it uses the combination position: absolute; z-index: -1; pointer-events: none; to make sure that the hidden container does not take space and does not answer to user interactions.
You can do this with transition events, so you build two CSS classes for the transition, one holding the animation other, holding the display none state. And you switch them after the animation is ended? In my case I can display the divs again if I press a button, and remove both classes.
Try the snippet below...
$(document).ready(function() {
// Assign transition event
$("table").on("animationend webkitAnimationEnd", ".visibility_switch_off", function(event) {
// We check if this is the same animation we want
if (event.originalEvent.animationName == "col_hide_anim") {
// After the animation we assign this new class that basically hides the elements.
$(this).addClass("animation-helper-display-none");
}
});
$("button").click(function(event) {
$("table tr .hide-col").toggleClass(function() {
// We switch the animation class in a toggle fashion...
// and we know in that after the animation end, there
// is will the animation-helper-display-none extra
// class, that we nee to remove, when we want to
// show the elements again, depending on the toggle
// state, so we create a relation between them.
if ($(this).is(".animation-helper-display-none")) {
// I'm toggling and there is already the above class, then
// what we want it to show the elements , so we remove
// both classes...
return "visibility_switch_off animation-helper-display-none";
}
else {
// Here we just want to hide the elements, so we just
// add the animation class, the other will be added
// later be the animationend event...
return "visibility_switch_off";
}
});
});
});
table th {
background-color: grey;
}
table td {
background-color: white;
padding: 5px;
}
.animation-helper-display-none {
display: none;
}
table tr .visibility_switch_off {
animation-fill-mode: forwards;
animation-name: col_hide_anim;
animation-duration: 1s;
}
#-webkit-keyframes col_hide_anim {
0% {opacity: 1;}
100% {opacity: 0;}
}
#-moz-keyframes col_hide_anim {
0% {opacity: 1;}
100% {opacity: 0;}
}
#-o-keyframes col_hide_anim {
0% {opacity: 1;}
100% {opacity: 0;}
}
#keyframes col_hide_anim {
0% {opacity: 1;}
100% {opacity: 0;}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<theader>
<tr>
<th>Name</th>
<th class='hide-col'>Age</th>
<th>Country</th>
</tr>
</theader>
<tbody>
<tr>
<td>Name</td>
<td class='hide-col'>Age</td>
<td>Country</td>
</tr>
</tbody>
</table>
<button>Switch - Hide Age column with fadeout animation and display none after</button>
Instead of using display you could store the element 'off-screen' until you needed it, and then set its position to where you want it and transform it at the same time. This brings up a whole host of other design issues though, so your mileage may vary.
You probably wouldn't want to use display anyway, as you'd want the content to be accessible to screen readers, which for the most part try to obey rules for visibility - i.e., if it shouldn't be visible to the eye, it won't show up as content to the agent.

Transitions on css display property [duplicate]

I'm currently designing a CSS 'mega dropdown' menu - basically a regular CSS-only dropdown menu, but one that contains different types of content.
At the moment, it appears that CSS 3 transitions don't apply to the 'display' property, i.e., you can't do any sort of transition from display: none to display: block (or any combination).
Is there a way for the second-tier menu from the above example to 'fade in' when someone hovers over one of the top level menu items?
I'm aware that you can use transitions on the visibility: property, but I can't think of a way to use that effectively.
I've also tried using height, but that just failed miserably.
I'm also aware that it's trivial to achieve this using JavaScript, but I wanted to challenge myself to use just CSS, and I think I'm coming up a little short.
You can concatenate two transitions or more, and visibility is what comes handy this time.
div {
border: 1px solid #eee;
}
div > ul {
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity 0.5s linear;
}
div:hover > ul {
visibility: visible;
opacity: 1;
}
<div>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
(Don't forget the vendor prefixes to the transition property.)
More details are in this article.
You need to hide the element by other means in order to get this to work.
I accomplished the effect by positioning both <div>s absolutely and setting the hidden one to opacity: 0.
If you even toggle the display property from none to block, your transition on other elements will not occur.
To work around this, always allow the element to be display: block, but hide the element by adjusting any of these means:
Set the height to 0.
Set the opacity to 0.
Position the element outside of the frame of another element that has overflow: hidden.
There are likely more solutions, but you cannot perform a transition if you toggle the element to display: none. For example, you may attempt to try something like this:
div {
display: none;
transition: opacity 1s ease-out;
opacity: 0;
}
div.active {
opacity: 1;
display: block;
}
But that will not work. From my experience, I have found this to do nothing.
Because of this, you will always need to keep the element display: block - but you could get around it by doing something like this:
div {
transition: opacity 1s ease-out;
opacity: 0;
height: 0;
overflow: hidden;
}
div.active {
opacity: 1;
height: auto;
}
At the time of this post all major browsers disable CSS transitions if you try to change the display property, but CSS animations still work fine so we can use them as a workaround.
Example Code (you can apply it to your menu accordingly) Demo:
Add the following CSS to your stylesheet:
#-webkit-keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
#keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
Then apply the fadeIn animation to the child on parent hover (and of course set display: block):
.parent:hover .child {
display: block;
-webkit-animation: fadeIn 1s;
animation: fadeIn 1s;
}
Update 2019 - Method that also supports fading out:
(Some JavaScript code is required)
// We need to keep track of faded in elements so we can apply fade out later in CSS
document.addEventListener('animationstart', function (e) {
if (e.animationName === 'fade-in') {
e.target.classList.add('did-fade-in');
}
});
document.addEventListener('animationend', function (e) {
if (e.animationName === 'fade-out') {
e.target.classList.remove('did-fade-in');
}
});
div {
border: 5px solid;
padding: 10px;
}
div:hover {
border-color: red;
}
.parent .child {
display: none;
}
.parent:hover .child {
display: block;
animation: fade-in 1s;
}
.parent:not(:hover) .child.did-fade-in {
display: block;
animation: fade-out 1s;
}
#keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
<div class="parent">
Parent
<div class="child">
Child
</div>
</div>
Instead of callbacks, which don't exist in CSS, we can use transition-delay property.
#selector {
overflow: hidden; /* Hide the element content, while height = 0 */
height: 0;
opacity: 0;
transition: height 0ms 400ms, opacity 400ms 0ms;
}
#selector.visible {
height: auto; opacity: 1;
transition: height 0ms 0ms, opacity 600ms 0ms;
}
So, what's going on here?
When visible class is added, both height and opacity start animation without delay (0 ms), though height takes 0 ms to complete animation (equivalent of display: block) and opacity takes 600 ms.
When visible class is removed, opacity starts animation (0 ms delay, 400 ms duration), and height waits 400 ms and only then instantly (0 ms) restores initial value (equivalent of display: none in the animation callback).
Note, this approach is better than ones using visibility. In such cases, the element still occupies the space on the page, and it's not always suitable.
For more examples please refer to this article.
I suspect that the reason that transitions are disabled if display is changed is because of what display actually does. It does not change anything that could conceivably be smoothly animated.
display: none; and visibility: hidden; are two entirely different things.
Both do have the effect of making the element invisible, but with visibility: hidden; it’s still rendered in the layout, but just not visibly so.
The hidden element still takes up space, and is still rendered inline or as a block or block-inline or table or whatever the display element tells it to render as, and takes up space accordingly.
Other elements do not automatically move to occupy that space. The hidden element just doesn’t render its actual pixels to the output.
display: none on the other hand actually prevents the element from rendering entirely.
It does not take up any layout space.
Other elements that would’ve occupied some or all of the space taken up by this element now adjust to occupy that space, as if the element simply did not exist at all.
display is not just another visual attribute.
It establishes the entire rendering mode of the element, such as whether it’s a block, inline, inline-block, table, table-row, table-cell, list-item, or whatever!
Each of those have very different layout ramifications, and there would be no reasonable way to animate or smoothly transition them (try to imagine a smooth transition from block to inline or vice-versa, for instance!).
This is why transitions are disabled if display changes (even if the change is to or from none — none isn’t merely invisibility, it’s its own element rendering mode that means no rendering at all!).
display is not one of the properties that transition works upon.
See Animatable CSS properties for the list of CSS properties that can have transitions applied to them. See CSS Values and Units Module Level 4, Combining Values: Interpolation, Addition, and Accumulation for how they are interpolated.
Up to CSS 3 was listed in 9.1. Properties from CSS (just close the warning popup)
I've also tried using height, but that just failed miserably.
Last time I had to do this, I used max-height instead, which is an animatable property (although it was a bit of a hack, it did work), but beware that it may be very janky for complex pages or users with low-end mobile devices.
I found better way for this issue, you can use CSS Animation and make your awesome effect for showing items.
.item {
display: none;
}
.item:hover {
display: block;
animation: fade_in_show 0.5s
}
#keyframes fade_in_show {
0% {
opacity: 0;
transform: scale(0)
}
100% {
opacity: 1;
transform: scale(1)
}
}
You can add a custom animation to the block property now.
#keyframes showNav {
from {opacity: 0;}
to {opacity: 1;}
}
.subnav-is-opened .main-nav__secondary-nav {
display: block;
animation: showNav 250ms ease-in-out both;
}
Demo
In this demo the sub-menu changes from display:none to display:block and still manages to fade.
Fade it in with CSS Animations:
.item {
display: none;
}
.item:hover {
display: block;
animation: fadeIn 0.5s;
}
#keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
According to W3C Working Draft 19 November 2013 display is not an animatable property. Fortunately, visibility is animatable. You may chain its transition with a transition of opacity (JSFiddle):
HTML:
Foo
<button id="hide-button">Hide</button>
<button id="show-button">Show</button>
CSS:
#foo {
transition-property: visibility, opacity;
transition-duration: 0s, 1s;
}
#foo.hidden {
opacity: 0;
visibility: hidden;
transition-property: opacity, visibility;
transition-duration: 1s, 0s;
transition-delay: 0s, 1s;
}
JavaScript for testing:
var foo = document.getElementById('foo');
document.getElementById('hide-button').onclick = function () {
foo.className = 'hidden';
};
document.getElementById('show-button').onclick = function () {
foo.className = '';
};
Note that if you just make the link transparent, without setting visibility: hidden, then it would stay clickable.
Edit: display none is not being applied in this example.
#keyframes hide {
0% {
display: block;
opacity: 1;
}
99% {
display: block;
}
100% {
display: none;
opacity: 0;
}
}
What's happening above is that through 99% of the animation display is set to block while the opacity fades out. In the last moment display property is set to none.
And the most important bit is to retain the last frame after the animation ends using animation-fill-mode: forwards
.hide {
animation: hide 1s linear;
animation-fill-mode: forwards;
}
Here are two examples: https://jsfiddle.net/qwnz9tqg/3/
My neat JavaScript trick is to separate the entire scenario into two different functions!
To prepare things, one global variable is declared and one event handler is defined:
var tTimeout;
element.addEventListener("transitionend", afterTransition, true);//firefox
element.addEventListener("webkitTransitionEnd", afterTransition, true);//chrome
Then, when hiding element, I use something like this:
function hide(){
element.style.opacity = 0;
}
function afterTransition(){
element.style.display = 'none';
}
For reappearing the element, I am doing something like this:
function show(){
element.style.display = 'block';
tTimeout = setTimeout(timeoutShow, 100);
}
function timeoutShow(){
element.style.opacity = 1;
}
It works, so far!
I ran into this today, with a position: fixed modal that I was reusing. I couldn't keep it display: none and then animate it, as it just jumped into appearance, and and z-index (negative values, etc) did weird things as well.
I was also using a height: 0 to height: 100%, but it only worked when the modal appeared. This is the same as if you used left: -100% or something.
Then it struck me that there was a simple answer. Et voila:
First, your hidden modal. Notice the height is 0, and check out the height declaration in transitions... it has a 500ms, which is longer than my opacity transition. Remember, this affects the out-going fade-out transition: returning the modal to its default state.
#modal-overlay {
background: #999;
background: rgba(33,33,33,.2);
display: block;
overflow: hidden;
height: 0;
width: 100%;
position: fixed;
top: 0;
left: 0;
opacity: 0;
z-index: 1;
-webkit-transition: height 0s 500ms, opacity 300ms ease-in-out;
-moz-transition: height 0s 500ms, opacity 300ms ease-in-out;
-ms-transition: height 0s 500ms, opacity 300ms ease-in-out;
-o-transition: height 0s 500ms, opacity 300ms ease-in-out;
transition: height 0s 500ms, opacity 300ms ease-in-out;
}
Second, your visible modal. Say you're setting a .modal-active to the body. Now the height is 100%, and my transition has also changed. I want the height to be instantly changed, and the opacity to take 300ms.
.modal-active #modal-overlay {
height: 100%;
opacity: 1;
z-index: 90000;
-webkit-transition: height 0s, opacity 300ms ease-in-out;
-moz-transition: height 0s, opacity 300ms ease-in-out;
-ms-transition: height 0s, opacity 300ms ease-in-out;
-o-transition: height 0s, opacity 300ms ease-in-out;
transition: height 0s, opacity 300ms ease-in-out;
}
That's it, it works like a charm.
Taking from a few of these answers and some suggestions elsewhere, the following works great for hover menus (I'm using this with Bootstrap 3, specifically):
nav .dropdown-menu {
display: block;
overflow: hidden;
max-height: 0;
opacity: 0;
transition: max-height 500ms, opacity 300ms;
-webkit-transition: max-height 500ms, opacity 300ms;
}
nav .dropdown:hover .dropdown-menu {
max-height: 500px;
opacity: 1;
transition: max-height 0, opacity 300ms;
-webkit-transition: max-height 0, opacity 300ms;
}
You could also use height in place of max-height if you specify both values since height:auto is not allowed with transitions. The hover value of max-height needs to be greater than the height of the menu can possibly be.
It is as simple as the following :)
#keyframes fadeout {
0% { opacity: 1; height: auto; }
90% { opacity: 0; height: auto; }
100% { opacity: 0; height: 0;
}
animation: fadeout linear 0.5s 1 normal forwards !important;
Get it to fade away, and then make it height 0;. Also make sure to use forwards so that it stays in the final state.
I've came across this issue multiple times and now simply went with:
.block {
opacity: 1;
transition: opacity 250ms ease;
}
.block--invisible {
pointer-events: none;
opacity: 0;
}
By adding the class block--invisible the whole Elements will not be clickable but all Elements behind it will be because of the pointer-events:none which is supported by all major browsers (no IE < 11).
Change overflow:hidden to overflow:visible. It works better. I use like this:
#menu ul li ul {
background-color:#fe1c1c;
width:85px;
height:0px;
opacity:0;
box-shadow:1px 3px 10px #000000;
border-radius:3px;
z-index:1;
-webkit-transition:all 0.5s ease;
-moz-transition:all 0.6s ease;
}
#menu ul li:hover ul {
overflow:visible;
opacity:1;
height:140px;
}
visible is better because overflow:hidden act exactly like a display:none.
Well another way to apply transition in this situation without using keyframes is to set the width of your element to zero and then unset it on hover
.className{
visibility:hidden;
opacity: 0;
transition: .2s;
width:0;
}
.className:hover{
visibility:visible;
margin-right: .5rem;
opacity: 1;
width:unset;
}
I appreciate all the answers. Here is what I'm using for similar purposes: transition vs animation.
Example: https://jsfiddle.net/grinevri/tcod87Le/22/
<div class="animation"></div>
<div class="transition"></div>
#keyframes animationTo {
0% { background-color: rgba(0, 0, 0, 0.1); }
100% { background-color: rgba(0, 0, 0, 0.5); }
}
#keyframes animationFrom {
0% { background-color: rgba(0, 0, 0, 0.5); }
100% { background-color: rgba(0, 0, 0, 0.1); }
}
.animation,
.transition{
margin: 5px;
height: 100px;
width: 100px;
background-color: rgba(0, 0, 0, 0.1);
}
.animation{
animation: animationFrom 250ms;
}
.animation:hover{
background-color: rgba(0, 0, 0, 0.5);
animation: animationTo 250ms;
}
.transition{
transition: background-color 250ms;
}
.transition:hover{
background-color: rgba(0, 0, 0, 0.5);
}
I finally found a solution for me, by combining opacity with position absolute (not to occupy space when hidden).
.toggle {
opacity: 0;
position: absolute;
transition: opacity 0.8s;
}
.parent:hover .toggle {
opacity: 1;
position: static;
}
JavaScript is not required, and no outrageously huge max-height is needed. Instead, set your max-height on your text elements, and use a font relative unit such as rem or em. This way, you can set a maximum height larger than your container, while avoiding a delay or "popping" when the menu closes:
HTML
<nav>
<input type="checkbox" />
<ul>
<li>Link 1</li>
<li>Link 1</li>
<li>Link 1</li>
<li>Link 1</li>
</ul>
</nav>
CSS
nav input + ul li { // Notice I set max-height on li, not ul
max-height: 0;
}
nav input:checked + ul li {
max-height: 3rem; // A little bigger to allow for text-wrapping - but not outrageous
}
See an example here:
http://codepen.io/mindfullsilence/pen/DtzjE
After the accepted answer from Guillermo was written, the CSS
transition specification of 2012-04-03 changed the behavior of the visibility transition and now it is possible to solve this problem in a shorter way, without the use of transition-delay:
.myclass > div {
transition:visibility 1s, opacity 1s;
visibility:hidden; opacity:0
}
.myclass:hover > div
{ visibility:visible; opacity:1 }
The run time specified for both transitions should usually be
identical (although a slightly longer time for visibility is not a problem).
For a running version, see my blog post CSS Transition Visibility.
W.r.t. the title of the question "Transitions on the display: property" and in response to comments from Rui Marques and josh to the accepted answer:
This solution works in cases where it is irrelevant if the display or
visibility property is used (as it probably was the case in this question).
It will not completely remove the element as display:none, just make it invisible, but it still stays in the document flow and influences the position of the following elements.
Transitions that completely remove the element similar to display:none can be done using height (as indicated by other answers and comments), max-height, or margin-top/bottom, but also see
How can I transition height: 0; to height: auto; using CSS? and my blog post Workarounds for CSS Transitions on the Display and Height Properties.
In response to comment from GeorgeMillo:
Both properties and both transitions are needed: The opacity property
is used to create a fade-in and fade-out animation and the visibility
property to avoid the element still reacting on mouse
events. Transitions are needed on opacity for the visual effect and on
visibility to delay hiding until the fade-out is finished.
I suspect anyone just starting CSS transitions quickly discovers that they don't work if you're modifying the display property (block/none) at the same time. One workaround that hasn't yet been mentioned is that you can continue to use display:block/none to hide/show the element, but set its opacity to 0 so that even when it's display:block, it's still invisible.
Then to fade it in, add another CSS class such as "on" which sets the opacity to 1 and defines the transition for opacity. As you may have imagined, you'll have to use JavaScript to add that "on" class to the element, but at least you're still using CSS for the actual transition.
P.S. If you find yourself in a situation where you need to do both display:block, and add class "on", at the same time, defer the latter using setTimeout. Otherwise, the browser just sees both things as happening at once and disables the transition.
You can get this to work the natural way you expected - using display - but you have to throttle the browser to get it to work, using either Javascript or as others have suggested a fancy trick with one tag inside another. I don't care for the inner tag as it further complicates CSS and dimensions, so here's the Javascript solution:
https://jsfiddle.net/b9chris/hweyecu4/17/
Starting with a box like:
<div id="box" class="hidden">Lorem</div>
A hidden box.
div.hidden {
display: none;
}
#box {
transition: opacity 1s;
}
We're going to use a trick found in a related q/a, checking offsetHeight to throttle the browser instantaneously:
https://stackoverflow.com/a/16575811/176877
First, a library formalizing the above trick:
$.fn.noTrnsn = function () {
return this.each(function (i, tag) {
tag.style.transition = 'none';
});
};
$.fn.resumeTrnsn = function () {
return this.each(function (i, tag) {
tag.offsetHeight;
tag.style.transition = null;
});
};
Next, we're going to use it to reveal a box, and fade it in:
$('#button').on('click', function() {
var tag = $('#box');
if (tag.hasClass('hidden'))
tag.noTrnsn().removeClass('hidden')
.css({ opacity: 0 })
.resumeTrnsn().css({ opacity: 1 });
else
tag.css({ opacity: 0 });
});
This fades the box in and out. So, .noTrnsn() turns off transitions, then we remove the hidden class, which flips display from none to its default, block. We then set opacity to 0 to get ready for fading in. Now that we've set the stage, we turn transitions back on, with .resumeTrnsn(). And finally, kick off the transition by setting opacity to 1.
Without the library, both the change to display and the change to opacity would've gotten us undesirable results. If we simply removed the library calls, we'd get no transitions at all.
Note that the above does not set display to none again at the end of the fadeout animation. We can get fancier though. Let's do so with one that fades in and grows in height from 0.
Fancy!
https://jsfiddle.net/b9chris/hweyecu4/22/
#box {
transition: height 1s, opacity 1s;
}
We're now transitioning both height and opacity. Note that we are not setting height, which means it is the default, auto. Conventionally this cannot be transitioned - moving from auto to a pixel value (like 0) will get you no transition. We're going to work around that with the library, and one more library method:
$.fn.wait = function (time, fn) {
if (time)
this.delay(time);
if (!fn)
return this;
var _this = this;
return this.queue(function (n) {
fn.call(_this);
n();
});
};
This is a convenience method that lets us participate in jQuery's existing fx/animation queue, without requiring any of the animation framework that's now excluded in jQuery 3.x. I'm not going to explain how jQuery works, but suffice to say, the .queue() and .stop() plumbing that jQuery provides help us prevent our animations from stepping on each other.
Let's animate the slide down effect.
$('#button').on('click', function() {
var tag = $('#box');
if (tag.hasClass('hidden')) {
// Open it
// Measure it
tag.stop().noTrnsn().removeClass('hidden').css({
opacity: 0, height: 'auto'
});
var h = tag.height();
tag.css({ height: 0 }).resumeTrnsn()
// Animate it
.css({ opacity: 1, height: h })
.wait(1000, function() {
tag.css({ height: 'auto' });
});
} else {
// Close it
// Measure it
var h = tag.noTrnsn().height();
tag.stop().css({ height: h })
.resumeTrnsn()
// Animate it
.css({ opacity: 0, height: 0 })
.wait(1000, function() {
tag.addClass('hidden');
});
}
});
This code begins by checking on #box and whether it's currently hidden, by checking on its class. But it accomplishes more using the wait() library call, by adding the hidden class at the end of the slideout/fade animation, which you'd expect to find if it is in fact hidden - something the above simpler example could not do. This happens to also enable display/hiding the element over and over, which was a bug in the previous example, because the hidden class was never restored.
You can also see CSS and class changes being called after .noTrnsn() to generally set the stage for animations, including taking measurements, like measuring what will be the final height of #box without showing that to the user, before calling .resumeTrnsn(), and animating it from that fully-set stage to its goal CSS values.
Old Answer
https://jsfiddle.net/b9chris/hweyecu4/1/
You can have it transition on click with:
function toggleTransition() {
var el = $("div.box1");
if (el.length) {
el[0].className = "box";
el.stop().css({maxWidth: 10000}).animate({maxWidth: 10001}, 2000, function() {
el[0].className = "box hidden";
});
} else {
el = $("div.box");
el[0].className = "box";
el.stop().css({maxWidth: 10001}).animate({maxWidth: 10000}, 50, function() {
el[0].className = "box box1";
});
}
return el;
}
someTag.click(toggleTransition);
The CSS is what you'd guess:
.hidden {
display: none;
}
.box {
width: 100px;
height: 100px;
background-color: blue;
color: yellow;
font-size: 18px;
left: 20px;
top: 20px;
position: absolute;
-webkit-transform-origin: 0 50%;
transform-origin: 0 50%;
-webkit-transform: scale(.2);
transform: scale(.2);
-webkit-transition: transform 2s;
transition: transform 2s;
}
.box1{
-webkit-transform: scale(1);
transform: scale(1);
}
The key is throttling the display property. By removing the hidden class and then waiting 50 ms, then starting the transition via the added class, we get it to appear and then expand like we wanted, instead of it just blipping onto the screen without any animation. Similar occurs going the other way, except we wait till the animation is over before applying hidden.
Note: I'm abusing .animate(maxWidth) here to avoid setTimeout race conditions. setTimeout is quick to introduce hidden bugs when you or someone else picks up code unaware of it. .animate() can easily be killed with .stop(). I'm just using it to put a 50 ms or 2000 ms delay on the standard fx queue where it's easy to find/resolve by other coders building on top of this.
I had a similar issue that I couldn't find the answer to. A few Google searches later led me here. Considering I didn't find the simple answer I was hoping for, I stumbled upon a solution that is both elegant and effective.
It turns out the visibility CSS property has a value collapse which is generally used for table items. However, if used on any other elements it effectively renders them as hidden, pretty much the same as display: hidden but with the added ability that the element doesn't take up any space and you can still animate the element in question.
Below is a simple example of this in action.
function toggleVisibility() {
let exampleElement = document.querySelector('span');
if (exampleElement.classList.contains('visible')) {
return;
}
exampleElement.innerHTML = 'I will not take up space!';
exampleElement.classList.toggle('hidden');
exampleElement.classList.toggle('visible');
setTimeout(() => {
exampleElement.classList.toggle('visible');
exampleElement.classList.toggle('hidden');
}, 3000);
}
#main {
display: flex;
flex-direction: column;
width: 300px;
text-align: center;
}
.hidden {
visibility: collapse;
opacity: 0;
transition: visibility 2s, opacity 2s linear;
}
.visible {
visibility: visible;
opacity: 1;
transition: visibility 0.5s, opacity 0.5s linear;
}
<div id="main">
<button onclick="toggleVisibility()">Click Me!</button>
<span class="hidden"></span>
<span>I will get pushed back up...</span>
</div>
The simplest universal solution to the problem is: feel free to specify display:none in your CSS, however you will have change it to block (or whatever else) using JavaScript, and then you'll also have to add a class to your element in question that actually does the transition with setTimeout(). That's all.
I.e.:
<style>
#el {
display: none;
opacity: 0;
}
#el.auto-fade-in {
opacity: 1;
transition: all 1s ease-out; /* Future, future, please come sooner! */
-webkit-transition: all 1s ease-out;
-moz-transition: all 1s ease-out;
-o-transition: all 1s ease-out;
}
</style>
<div id=el>Well, well, well</div>
<script>
var el = document.getElementById('el');
el.style.display = 'block';
setTimeout(function () { el.className = 'auto-fade-in' }, 0);
</script>
This was tested in the latest sane browsers. Obviously it shouldn't work in Internet Explorer 9 or earlier.
I think SalmanPK has the closest answer. It does fade an item in or out, with the following CSS animations. However, the display property does not animate smoothly, only the opacity.
#-webkit-keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
#-webkit-keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
If you want to animate the element moving from display block to display none, I can't see that it is currently possible just with CSS. You have to get the height and use a CSS animation to decrease the height. This is possible with CSS as shown in the example below, but it would be tricky to know the exact height values you need to animate for an element.
jsFiddle example
CSS
#-webkit-keyframes pushDown {
0% {
height: 10em;
}
25% {
height: 7.5em;
}
50% {
height: 5em;
}
75% {
height: 2.5em;
}
100% {
height: 0em;
}
}
.push-down {
-webkit-animation: pushDown 2s forwards linear;
}
JavaScript
var element = document.getElementById("element");
// Push item down
element.className = element.className + " push-down";
This solution has excellent compatibility, and I haven't seen it yet:
.hidden-element {
position: absolute;
z-index: -1;
pointer-events: none;
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity .5s ease-out;
}
.hidden-element.visible {
position: static;
z-index: auto;
pointer-events: auto;
visibility: visible;
opacity: 1;
}
Explanation: it uses the visibility: hidden trick (which is compatible with “show-and-animate” in one step), but it uses the combination position: absolute; z-index: -1; pointer-events: none; to make sure that the hidden container does not take space and does not answer to user interactions.
You can do this with transition events, so you build two CSS classes for the transition, one holding the animation other, holding the display none state. And you switch them after the animation is ended? In my case I can display the divs again if I press a button, and remove both classes.
Try the snippet below...
$(document).ready(function() {
// Assign transition event
$("table").on("animationend webkitAnimationEnd", ".visibility_switch_off", function(event) {
// We check if this is the same animation we want
if (event.originalEvent.animationName == "col_hide_anim") {
// After the animation we assign this new class that basically hides the elements.
$(this).addClass("animation-helper-display-none");
}
});
$("button").click(function(event) {
$("table tr .hide-col").toggleClass(function() {
// We switch the animation class in a toggle fashion...
// and we know in that after the animation end, there
// is will the animation-helper-display-none extra
// class, that we nee to remove, when we want to
// show the elements again, depending on the toggle
// state, so we create a relation between them.
if ($(this).is(".animation-helper-display-none")) {
// I'm toggling and there is already the above class, then
// what we want it to show the elements , so we remove
// both classes...
return "visibility_switch_off animation-helper-display-none";
}
else {
// Here we just want to hide the elements, so we just
// add the animation class, the other will be added
// later be the animationend event...
return "visibility_switch_off";
}
});
});
});
table th {
background-color: grey;
}
table td {
background-color: white;
padding: 5px;
}
.animation-helper-display-none {
display: none;
}
table tr .visibility_switch_off {
animation-fill-mode: forwards;
animation-name: col_hide_anim;
animation-duration: 1s;
}
#-webkit-keyframes col_hide_anim {
0% {opacity: 1;}
100% {opacity: 0;}
}
#-moz-keyframes col_hide_anim {
0% {opacity: 1;}
100% {opacity: 0;}
}
#-o-keyframes col_hide_anim {
0% {opacity: 1;}
100% {opacity: 0;}
}
#keyframes col_hide_anim {
0% {opacity: 1;}
100% {opacity: 0;}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<theader>
<tr>
<th>Name</th>
<th class='hide-col'>Age</th>
<th>Country</th>
</tr>
</theader>
<tbody>
<tr>
<td>Name</td>
<td class='hide-col'>Age</td>
<td>Country</td>
</tr>
</tbody>
</table>
<button>Switch - Hide Age column with fadeout animation and display none after</button>
Instead of using display you could store the element 'off-screen' until you needed it, and then set its position to where you want it and transform it at the same time. This brings up a whole host of other design issues though, so your mileage may vary.
You probably wouldn't want to use display anyway, as you'd want the content to be accessible to screen readers, which for the most part try to obey rules for visibility - i.e., if it shouldn't be visible to the eye, it won't show up as content to the agent.

start second animation css at position of first animation css

I need to chain two animations in my interface HTML/CSS on user event (here just a click on the document). The first animation start correctly, but when I want to restart the second animation nothing move ?
I know if i remove the .rotaiotn class and with a timeout put other animation class for the element, the second animation start from the first position of the element.
I want to know if exist a solution to start the second animation from the position of the blue ball after the first animation ?
document.addEventListener('click', startAnimation, false);
var isFisrtAnim = false;
function startAnimation(evt) {
var elt = document.querySelector('#blue_ball');
if (!isFisrtAnim) {
elt.setAttribute('class', 'rotation');
} else {
elt.setAttribute('class', 'rotation2');
}
elt.addEventListener("animationend", animationAtEnd, false);
}
function animationAtEnd(evt) {
evt.preventDefault();
isFisrtAnim = !isFisrtAnim;
var elt = evt.target;
// todo here get new position of elt to start another animation
// from the new position after first animation
var new_margin_top = window.getComputedStyle(elt).getPropertyValue('margin-top');
var new_margin_left = window.getComputedStyle(elt).getPropertyValue('margin-left');
console.log('At end new margin-top : ' + new_margin_top + ' - new margin-left : ' + new_margin_left);
// positions are the same of start element ? they are not modify ?
}
#circleNav {
background: rgba(215, 229, 231, 0.4) !important;
margin-top: 100px;
margin-left: 120px;
border-radius: 50%;
width: 335px;
height: 335px;
border: 2px solid #0e6694;
}
img {
max-width: 100%;
}
#blue_ball {
position: absolute;
margin-top: -350px;
margin-left: 165px;
width: 70px;
height: 70px;
border: none;
z-index: 5;
transform-origin: 120px 180px;
}
.rotation {
-webkit-animation: rotation 3s linear;
animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards !important;
}
#-webkit-keyframes rotation {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(240deg);
}
}
.rotation2 {
-webkit-animation: rotation 3s linear;
animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards !important;
}
#-webkit-keyframes rotation2 {
from {
-webkit-transform: rotate(240deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
<h2>
CLICK ON THE BODY TO START ANIMATION
</h2>
<h4>
When the Blue ball stop click an other time to start second animation, but don't work ?
</h4>
<div id="circleNav"></div>
<div id="blue_ball">
<a href="#">
<img id="btn_menu" src="http://mascaron.net/img/mini_rond_logo.png">
</a>
</div>
smaple code on jsfiddle
thanks in advance.
Just one question, in css:
.rotation2 {
-webkit-animation: rotation 3s linear;
animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards !important;
}
should not be:
.rotation2 {
-webkit-animation: rotation2 3s linear; /* <----- here, rotation2
animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards !important;
}
In js part, why not use elem.classList https://developer.mozilla.org/fr/docs/Web/API/Element/classList to manipulate css class property.

Restart animation in CSS3: any better way than removing the element?

I have a CSS3 animation that needs to be restarted on a click. It's a bar showing how much time is left. I'm using the scaleY(0) transform to create the effect.
Now I need to restart the animation by restoring the bar to scaleY(1) and let it go to scaleY(0) again.
My first attempt to set scaleY(1) failed because it takes the same 15 seconds to bring it back to full length. Even if I change the duration to 0.1 second, I would need to delay or chain the assignment of scaleY(0) to let the bar replenishment complete.
It feels too complicated for such a simple task.
I also found an interesting tip to restart the animation by removing the element from the document, and then re-inserting a clone of it:
http://css-tricks.com/restart-css-animation/
It works, but is there a better way to restart a CSS animation?
I'm using Prototype and Move.js, but I'm not restricted to them.
No need in timeout, use reflow to apply the change:
function reset_animation() {
var el = document.getElementById('animated');
el.style.animation = 'none';
el.offsetHeight; /* trigger reflow */
el.style.animation = null;
}
#animated {
position: absolute;
width: 50px; height: 50px;
background-color: black;
animation: bounce 3s ease-in-out infinite;
}
#keyframes bounce {
0% { left: 0; }
50% { left: calc( 100% - 50px ); }
100% { left: 0; }
}
<div id="animated"></div>
<button onclick="reset_animation()">Reset</button>
Just set the animation property via JavaScript to "none" and then set a timeout that changes the property to "", so it inherits from the CSS again.
Demo for Webkit here: http://jsfiddle.net/leaverou/xK6sa/
However, keep in mind that in real world usage, you should also include -moz- (at least).
#ZachB's answer about the Web Animation API seems like "right"™ way to do this, but unfortunately seems to require that you define your animations through JavaScript. However it caught my eye and I found something related that's useful:
Element.getAnimations() and Document.getAnimations()
The support for them is pretty good as of 2021.
In my case, I wanted to restart all the animations on the page at the same time, so all I had to do was this:
const replayAnimations = () => {
document.getAnimations().forEach((anim) => {
anim.cancel();
anim.play();
});
};
But in most cases people will probably want to select which animation they restart...
getAnimations returns a bunch of CSSAnimation and CSSTransition objects that look like this:
animationName: "fade"
currentTime: 1500
effect: KeyframeEffect
composite: "replace"
pseudoElement: null
target: path.line.yellow
finished: Promise {<fulfilled>: CSSAnimation}
playState: "finished"
ready: Promise {<fulfilled>: CSSAnimation}
replaceState: "active"
timeline: DocumentTimeline {currentTime: 135640.502}
# ...etc
So you could use the animationName and target properties to select just the animations you want (albeit a little circuitously).
EDIT
Here's a handy function that might be more compatible using just Document.getAnimations, with TypeScript thrown in for demonstration/fun:
// restart animations on a given dom element
const restartAnimations = (element: Element): void => {
for (const animation of document.getAnimations()) {
if (element.contains((animation.effect as KeyframeEffect).target)) {
animation.cancel();
animation.play();
}
}
};
Implement the animation as a CSS descriptor
Add the descriptor to an element to start the animation
Use a animationend event handler function to remove the descriptor when the animation completes so that it will be ready to be added again next time you want to restart the animation.
HTML
<div id="animatedText">
Animation happens here
</div>
<script>
function startanimation(element) {
element.classList.add("animateDescriptor");
element.addEventListener( "animationend", function() {
element.classList.remove("animateDescriptor");
} );
}
</script>
<button onclick="startanimation(
document.getElementById('animatedText') )">
Click to animate above text
</button>
CSS
#keyframes fadeinout {
from { color: #000000; }
25% {color: #0000FF; }
50% {color: #00FF00; }
75% {color: #FF0000; }
to { color : #000000; }
}
.animateDescriptor {
animation: fadeinout 1.0s;
}
Try it here: jsfiddle
If you have a class for CSS3 animation, for example .blink, then you can removeClass for some element and addClass for this element thought setTimeout with 1 millisecond by click.
$("#element").click(function(){
$(this).removeClass("blink");
setTimeout(function(){
$(this).addClass("blink);
},1 // it may be only 1 millisecond, but it's enough
});
You can also use display property, just set the display to none.
display:none;
and the change backs it to block (or any other property you want).
display:block;
using JavaScript.
and it will work amazingly.
The Animation API gives you full control over when and what to play, and is supported by all modern browsers (Safari 12.1+, Chrome 44+, Firefox 48+, Edge 79+) .
const effect = new KeyframeEffect(
el, // Element to animate
[ // Keyframes
{transform: "translateY(0%)"},
{transform: "translateY(100%)"}
],
{duration: 3000, direction: "alternate", easing: "linear"} // Keyframe settings
);
const animation = new Animation(effect, document.timeline);
animation.play();
Demo: https://jsfiddle.net/cstz9L8v/
References:
https://developer.mozilla.org/en-US/docs/Web/API/KeyframeEffect/KeyframeEffect
https://developer.mozilla.org/en-US/docs/Web/API/Animation
There is an answer on MDN, which is similar to the reflow approach:
<div class="box">
</div>
<div class="runButton">Click me to run the animation</div>
#keyframes colorchange {
0% { background: yellow }
100% { background: blue }
}
.box {
width: 100px;
height: 100px;
border: 1px solid black;
}
.changing {
animation: colorchange 2s;
}
function play() {
document.querySelector(".box").className = "box";
window.requestAnimationFrame(function(time) {
window.requestAnimationFrame(function(time) {
document.querySelector(".box").className = "box changing";
});
});
}
If you create two identical sets of keyframes, you can "restart" the animation by swapping between them:
function restart_animation(element) {
element.classList.toggle('alt')
}
#keyframes spin1 {
to { transform: rotateY(360deg); }
}
#keyframes spin2 {
to { transform: rotateY(360deg); }
}
.spin {
animation-name: spin1;
animation-duration: 2s;
}
.alt {
animation-name: spin2;
}
div {
width: 100px;
background: #8CF;
padding: 5px;
}
<div id=_square class=spin>
<button onclick="restart_animation(_square)">
Click to restart animation
</button>
</div>
On this page you can read about restarting the element animation: Restart CSS Animation (CSS Tricks)
Here is my example:
<head>
<style>
#keyframes selectss
{
0%{opacity: 0.7;transform:scale(1);}
100%{transform:scale(2);opacity: 0;}
}
</style>
<script>
function animation()
{
var elm = document.getElementById('circle');
elm.style.animation='selectss 2s ease-out';
var newone = elm.cloneNode(true);
elm.parentNode.replaceChild(newone, elm);
}
</script>
</head>
<body>
<div id="circle" style="height: 280px;width: 280px;opacity: 0;background-color: aqua;border-radius: 500px;"></div>
<button onclick="animation()"></button>
</body>
But if you want to you can just remove the element animation and then return it:
function animation()
{
var elm = document.getElementById('circle');
elm.style.animation='';
setTimeout(function () {elm.style.animation='selectss 2s ease-out';},10)
}
setInterval(() => {
$('#XMLID_640_').css('animation', 'none')
setTimeout(() => {
$('#XMLID_640_').css('animation', '')
}, 3000)
}, 13000)
Create a second "keyframe#" which restarts you animation, only problem with this you cannot set any animation properties for the restarting animation (it just kinda pops back)
HTML
<div class="slide">
Some text..............
<div id="slide-anim"></div>
</div><br>
<button onclick="slider()"> Animation </button>
<button id="anim-restart"> Restart Animation </button>
<script>
var animElement = document.getElementById('slide-anim');
document.getElementById('anim-restart').addEventListener("mouseup", restart_slider);
function slider() {
animElement.style.animationName = "slider"; // other animation properties are specified in CSS
}
function restart_slider() {
animElement.style.animation = "slider-restart";
}
</script>
CSS
.slide {
position: relative;
border: 3px black inset;
padding: 3px;
width: auto;
overflow: hidden;
}
.slide div:first-child {
position: absolute;
width: 100%;
height: 100%;
background: url(wood.jpg) repeat-x;
left: 0%;
top: 0%;
animation-duration: 2s;
animation-delay: 250ms;
animation-fill-mode: forwards;
animation-timing-function: cubic-bezier(.33,.99,1,1);
}
#keyframes slider {
to {left: 100%;}
}
#keyframes slider-restart {
to {left: 0%;}
}
Note that with React, clearing the animation like this, a codesandbox I found helps.
Example I used in my code:
function MyComponent() {
const [shouldTransition, setShouldTransition] = useState(true);
useEffect(() => {
setTimeout(() => {
// in my code, I change a background image here, and call this hook restart then animation,
// which first clears the animationName
setShouldTransition(false);
}, timeout * 1000);
}, [curr]);
useEffect(() => {
// then restore the animation name after it was cleared
if (shouldTransition === false) {
setShouldTransition(true);
}
}, [shouldTransition]);
return (
<div
ref={ref2}
style={{
animationName: shouldTransition ? "zoomin" : "",
}}
/>
);
}
I found out a simple solution today. Using the example provided in this answer, you can just append the element again to the body:
function resetAnimation() {
let element = document.getElementById('animated');
document.body.append(element);
}
#animated {
position: absolute;
width: 50px;
height: 50px;
background-color: LightSalmon;
animation: bounce 3s ease-in-out infinite;
}
#keyframes bounce {
0% {left: 0;}
50% {left: calc(100% - 50px);}
100% {left: 0;}
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="animated"></div>
<button onclick="resetAnimation()">Reset</button>
</body>
</html>
Using Chrome's developer tools, the append does not actually append the element to the body and just replace it, probably because the same reference to the element is used.

Categories