Ok, I have a situation where I have basically built a little notification dropdown box that happens when the user does something, at the end it transitions to a opacity: 0;
state.
However, because the user may click something else that will trigger this notification box again I am trying to come up with a way to reset it back to normal without affecting any in-progress transitions and attempting to keep the animation done by CSS rather than JavaScript.
CodePen:http://codepen.io/gutterboy/pen/WoEydg
HTML:
<a href="#">Open Notify Window</a>
<div id="top_notify" class="top-notify">
<div class="container-fluid">
<div class="row">
<div class="content col-xs-12">
<div class="alert" role="alert"></div>
</div>
</div>
</div>
</div>
SCSS:
body {
text-align: center;
padding-top: 150px;
}
.top-notify {
position: fixed;
top: 0;
width: 100%;
z-index: 9999;
.content {
text-align: center;
background-color: transparent;
transform-style: preserve-3d;
}
.alert {
display: inline-block;
transform: translateY(-100%);
min-width: 250px;
max-width: 500px;
border-top-left-radius: 0;
border-top-right-radius: 0;
&.visible {
transform: translateY(0%);
transition: 0.8s 0s, opacity 1s 3.8s;
opacity: 0;
}
}
}
JS:
$('a').on('click', function(e){
e.preventDefault();
myFunc();
});
function myFunc() {
// Set file to prepare our data
var loadUrl = "https://crossorigin.me/http://codepen.io/gutterboy/pen/ObjExz.html";
// Run request
getAjaxData(loadUrl, null, 'POST', 'html')
.done(function(response) {
var alert_el = $('#top_notify').find('.alert');
// Update msg in alert box
alert_el.text(response);
alert_el.addClass('alert-success');
// Slide in alert box
alert_el.addClass('visible');
})
.fail(function() {
alert('Problem!!');
});
// End
}
function getAjaxData(loadUrl, dataObject, action, type) {
return jQuery.ajax({
type: action,
url: loadUrl,
data: dataObject,
dataType: type
});
}
I know I can reset it back to normal by doing this in JS:
$('#top_notify').find('.alert').removeClass().addClass('alert'); // The classes it ends up with vary
...however doing this removes the classes before the transition is finished fading out the opacity and it just vanishes straight away.
I know I can do a delay in JS to counteract the CSS delay but doing it that way just doesn't seem a very good way to do it since you have the timings in 2 different places.
Is there any way I can accomplish this whilst keeping the animation done by CSS or will I have to move to using jQuery's animate
so I can run the reset procedure once the animation is complete?
To add the CSS classes to an element we use addClass() method, and to remove the CSS classes we use removeClass() method.
To remove all CSS classes of an element, we use removeClass() method. The removeClass() method is used to remove one or more class names from the selected element.
To remove a class from an element, you use the remove() method of the classList property of the element.
Transition triggers # Your CSS must include a change of state and an event that triggers that state change for CSS transitions to activate. A typical example of such a trigger is the :hover pseudo-class. This pseudo-class matches when the user hovers over an element with their cursor.
Ok, I came up with a simple solution after coming up with a convoluted one ha.
Simple solution I should have come up with in the first place was removing any additional added classes before the ajax
call; I got too focused on doing it within the ajax
block and of course that didn't work, but until I started playing around with the other solution I never tried it.
Any way, the simple solution is simply moving this code:
var alert_el = $('#top_notify').find('.alert');
...above the ajax
call, rather than being inside of it.
Then adding this directly under it:
alert_el.removeClass('visible alert-success alert-info alert-danger alert-warning');
With the full function code being:
function myFunc() {
// Set file to prepare our data
var loadUrl = "https://crossorigin.me/http://codepen.io/gutterboy/pen/ObjExz.html";
var alert_el = $('#top_notify').find('.alert');
alert_el.removeClass('visible alert-success alert-info alert-danger alert-warning');
// Run request
getAjaxData(loadUrl, null, 'POST', 'html')
.done(function(response) {
// Update msg in alert box
alert_el.text(response);
alert_el.addClass('alert-success');
// Slide in alert box
alert_el.addClass('visible');
})
.fail(function() {
alert('Problem!!');
});
// End
}
CodePen: http://codepen.io/gutterboy/pen/xRXbXy
The other solution I came up with, whilst not really needed now, I thought I would post it anyway in-case it comes in handy for me (or someone) else in the future.
It doesn't remove the visible
class after the animation is finished (as there is no way that I know of to alert JS when it's done) but the visible
class - which I would change the name of if you use this method - doesn't add any new styles, it just runs the animation.
Here is how I did it:
The JavaScript remains the same as the solution above, it's all in the CSS.
TLDR;
Basically uses multiple CSS animations to control different states during the effect runtime; CodePen at bottom.
The changes being in the .visible
class and the addition of some @keyframes
.
.visible class:
&.visible {
animation: slideDown 0.8s 0s, keepThere 3s 0.8s, fadeAway 1s 3.8s;
}
As you can see we have gotten rid of any additional styling here - this means when the animation is done, it essentially resets back to normal, which is what we want.
Now, let's break down this code:
We are running 3 different animations here and it's important to note they don't run one after the other - meaning they don't wait until one is finished until it starts the next one, hence why we needed to include delay
settings.
So first up we start with the slideDown
animation:
slideDown 0.8s 0s
If you are new to animations in CSS then basically what this does is sets a delay of 0s
before it starts running and the animation runs for 0.8s
, and this is the animation:
@keyframes slideDown {
0% {
transform: translateY(-100%);
}
100% {
transform: translateY(0%);
}
}
So, pretty simple, just slides it down with transform
from -100%
to 0%
and this animation takes 0.8s
as we set in our call to this animation.
Now, I wanted this to stay visible for 3 seconds before it started to fade away, but we have a problem; once the animation ends then it goes back to it's standard styling, which in our case means it vanishes as it goes back to transform: translateY(-100%)
since we have no extra styles in the .visible
class, and we can't put any extra styles in there as then we won't be able to reset it back to it's original state (style wise).
But what do we do? The fadeAway
animation doesn't start for another 3 seconds and at the moment it doesn't have anything to fade away (well it does, but you can't see it as it's hidden).
The solution to that was adding another animation - which technically doesn't really animate anything, it just keeps it visible until the fadeAway
animation starts.
That's where we get to:
keepThere 3s 0.8s
Now, remembering the settings of our fadeAway
animation are: fadeAway 1s 3.8s
this means that we have 3 seconds before this animation is going to start and hence before we can control any of the styling with it.
So that's where these parameter values comes in - we set the delay to 0.8s
so the keepThere
animation doesn't start until the slideDown
one has finished; then we set the duration for 3s
to counter for the wait time until the fadeAway
animation starts, and this is the keepThere
animation:
@keyframes keepThere {
0%, 100% {
transform: translateY(0%);
}
}
Since it has the same start and end styling we combine it into one selector of 0%, 100%
and as you can see, this does just what it says it does, keeps the element visible for the set duration of 3s
until we can control the styling with the fadeAway
animation.
I guess technically you could combine this functionality into the fadeAway
animation if you wanted to do the math at what % equals 3 seconds and hence know when to start fading the element away.
Lastly we have the fadeAway
animation:
fadeAway 1s 3.8s
Now as we have discussed above, we already know why we have set the delay
to 3.8s
, the 0.8s
offset to allow the slideDown
animation to run and an additional 3s
delay as that's how long we want the element to be visible for until it starts fading away and then of course the fade takes 1s
to complete.
The animation for this is:
@keyframes fadeAway {
0%, 100% {
transform: translateY(0%);
}
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
Now, since the keepThere
animation has completed, we have to make sure to keep the element visible so the fade has something visible to actually fade away, that's why we make sure to include the style transform: translateY(0%);
as a value from start to finish; after that it's quite obvious what it's doing I think.
Put it all together and you get:
.top-notify {
position: fixed;
top: 0;
width: 100%;
z-index: 9999;
.content {
text-align: center;
background-color: transparent;
transform-style: preserve-3d;
}
.alert {
display: inline-block;
transform: translateY(-100%);
min-width: 250px;
max-width: 500px;
border-top-left-radius: 0;
border-top-right-radius: 0;
&.visible {
animation: slideDown 0.8s 0s, keepThere 3s 0.8s, fadeAway 1s 3.8s;
}
}
}
@keyframes slideDown {
0% {
transform: translateY(-100%);
}
100% {
transform: translateY(0%);
}
}
@keyframes keepThere {
0%, 100% {
transform: translateY(0%);
}
}
@keyframes fadeAway {
0%, 100% {
transform: translateY(0%);
}
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
CodePen: http://codepen.io/gutterboy/pen/QGqwBg
Then of course to be able to run it again the class has to be re-added and hence that was the purpose of removing the .visible
class at the start of each run (before the ajax call) and then when it gets re-added during the ajax call it runs again.
Thanks to @Nathaniel Flick for sharing the link that led me down this path to begin with :)
Well, hopefully that comes in handy for someone seeing as I am no longer going to use that option ha!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With