Can I use properties such as position:absolute and display:none in CSS keyframe animation? I don't care if they are transitioned smoothly, I just want them to be applied as 25% of the animation such as this :
#-webkit-keyframes expanding {
25% {
width: 50%;
height: 50%;
position: absolute;
}
100% {
width: 100%;
height: 100%;
position: absolute;
}
}
or
#-webkit-keyframes hiding {
0% {
opacity: 1;
}
25% {
opacity: 0;
display: none;
}
}
It appears to ignore position and display in the keyframes and doesn't apply them when I want them applied.
You can get a animationEnd callback when one of the animatable properties finishes its cycle, then use that to set the non-animatable properties:
var anim = document.getElementById("anim");
anim.addEventListener("animationend", function () {
anim.style.display = "none";
}, false);
Unfortunately, there's no keyframe event, so you might need to set up another animation with slightly different timing, synchronised to the 25% moment. For example, it could finish when the main animation gets to 25% or whatever. You could also set up a timeout.
Related
I have created an animation for an element on my page and it always runs when the page is refreshed but i would like the animation to play when an element is clicked. How would i go about doing this?
CSS:
#login-or-signup-selection {
display: flex;
animation-name: test;
animation-duration: 5s;
position: relative;
height: 70%;
}
#keyframes test {
0% {top: 0px;}
50% {top:300px}
100% {top: 0;}
}
HTML:
<p id="clickMe">Element to click</p>
$('#clickMe').click(function () {
$(this).addClass('login-or-signup-selection');
$(this).on("animationend", function(event) {
$(this).removeClass('login-or-signup-selection')
});
});
.login-or-signup-selection {
display: flex;
animation-name: test;
animation-duration: 5s;
position: relative;
height: 70%;
}
#keyframes test {
0% {top: 0px;}
50% {top:300px}
100% {top: 0;}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p id="clickMe">Element to click</p>
If you want only css and don't even care about js onclick events for now,
use the :active pseudo selector.
The only downside is that it only plays while (=during) e.g. the mouse button is down.
You would need some JavaScript for this.
First off, separate the CSS animation properties, and anything else related to your animation, and add them to their own class.
Next up, the JavaScript. You'll want to add an event listener to your element to add the animation class when clicked, and a timeout to remove the class afterwards so it will animate when clicked again.
const yourElement = document.getElementById('clickMe');
yourElement.addEventListener('click', _=> {
yourElement.classList.add('animation-class');
setTimeout(
_=> yourElement.classList.remove('animation-class'),
5000
)
});
#clickMe {
display: flex;
position: relative;
height: 70%;
}
.animation-class {
animation-name: test;
animation-duration: 5s;
}
#keyframes test {
0% { top: 0px; }
50% { top: 300px; }
100% { top: 0; }
}
<p id="clickMe">Element to click</p>
You need JavaScript for this.
If you add an event listener on the p element to listen for a click, this can then add the animation name to the selection div.
But you need to also listen for the end of the animation, otherwise subsequent clicks will have no effect. On animation end this snippet removes the animation name.
Note also that in order to be absolutely sure that the first (onload) animation end is trapped, the first animation name is not set until the event listeners have been set up.
function init() {
const clickMe = document.querySelector('#clickMe');
const selection = document.querySelector('#login-or-signup-selection');
clickMe.addEventListener('click', function() {
selection.style.animationName = 'test';
});
selection.addEventListener('animationend', function() {
selection.style.animationName = '';
});
selection.style.animationName = 'test';
}
window.onload = init;
#login-or-signup-selection {
display: flex;
animation-duration: 5s;
animation-iteration-count: 1;
position: relative;
height: 70%;
}
#keyframes test {
0% {
top: 0px;
}
50% {
top: 300px
}
100% {
top: 0;
}
}
<p id="clickMe">Element to click</p>
<div id="login-or-signup-selection">Login or signup selection</div>
I have been trying to get this to work for a while.
The point is that the inner div will have some shape and there will probably more than one (That's why I used the nth-child selector).
This inner div is supposed to be shown and then be hidden again both for some set amount of time.
the problem is, that I would like to animate all the (later) multiple inner divs in one animation. For this I thought I could use CSS variables, but this does not seem to work.
What I am trying to archieve in this example is the inner div basically just blinking by using the variable. But my result in Firefox is just a black box.
Am I missing anything? I already looked up if one could even use CSS variables in #keyframes and sure enough you can.
The only problem with them in animations seems to be that they are not interpolated in between but that they suddenly switch which is not a problem in this case.
#keyframes test{
from{
--one: 0;
}
to{
--one: 1;
}
}
#test{
width: 100px;
height: 200px;
background-color: black;
animation: test 1s infinite;
}
#test :nth-child(1){
width: 20px;
height: 20px;
margin: auto;
background-color: white;
opacity: var(--one,0);
}
<div id="test">
<div></div>
</div>
This can be achieved by defining variables using (as of writing this, not well-supported) #property, which allows declaring types and that allows the browser to "understand", for example, that a certain property (variable) is a Number and then it can gradually animate/transition that variable.
Example Code:
#property --opacity {
syntax: '<number>'; /* <- defined as type number for the transition to work */
initial-value: 0;
inherits: false;
}
#keyframes fadeIn {
50% {--opacity: 1}
}
html {
animation: 2s fadeIn infinite;
background: rgba(0 0 0 / var(--opacity));
}
The current types that are allowed include:
length, number, percentage, length-percentage, color, image, url, integer, angle, time, resolution, transform-list, transform-function, custom-ident (an identifier string)
Helpful articles:
https://web.dev/at-property/#writing-houdini-custom-properties
https://css-tricks.com/using-property-for-css-custom-properties
Cool Houdini demos
As stated in the specification:
Animatable: no
and also
Notably, they can even be transitioned or animated, but since the UA
has no way to interpret their contents, they always use the "flips at
50%" behavior that is used for any other pair of values that can’t be
intelligently interpolated. However, any custom property used in a
#keyframes rule becomes animation-tainted, which affects how it is
treated when referred to via the var() function in an animation
property.
So even if you use opacity with var() in the keyframes it won't animate:
#keyframes test {
from {
--one:0;
opacity: var(--one);
}
to {
opacity: var(--one);
--one: 1;
}
}
#test {
width: 100px;
height: 200px;
background-color: black;
}
#test :nth-child(1) {
width: 20px;
height: 20px;
margin: auto;
background-color: white;
animation: test 1s infinite;
}
<div id="test">
<div></div>
</div>
By the way you can make it working if you use it as a transition because in this case you will apply a transtion to the opacity and not the custom property:
#test {
width: 100px;
height: 200px;
background-color: black;
}
#test:hover {
--one:1;
}
#test :nth-child(1) {
width: 20px;
height: 20px;
margin: auto;
background-color: white;
opacity: var(--one,0);
transition:1s all;
}
<div id="test">
<div></div>
</div>
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have some right to left scrolling text that teleports back to the origin at the end of the animation, while I am more so looking for it to disappear out of and appear into the margin.
.example1 {
height: 50px;
overflow: hidden;
position: relative;
}
.example1 h3 {
position: absolute;
width: 100%;
height: 100%;
margin: 0;
color: white;
line-height: 50px;
animation: example1 10s linear infinite;te
}
#keyframes example1 {
from {
margin-left: 60%;
width: 300%;
}
to {
margin-left: 35%;
width: 100%;
}
}
body {
background-color: black;
}
<div class="example1">
<h3>text</h3>
</div>
If you need your CSS animation to only run once, you have to set the animation-iteration-count property to 1 (in fact, to not set it at all, as 1 is its default value).
You're currently setting it to infinite, using the animation shorthand, which sets multiple animation properties in one single declaration. Just remove infinte from that line. You should also remove the te following that declaration, which is invalid CSS.
To have your animation animate multiple properties, you can add as many animatable properties to your keyframes and they will animate accordingly. In your case, adding a 50% keyframe with opacity:1 and adding opacity:0 to the to keyframe will make your element fade from 1 to 0 starting at half of the animation until its end.
Using animation-timing-function, particularly with timing functions (a.k.a. as easings), allows adding acceleration and deceleration to animations, making them look more "natural", especially when used on movement animations.
Another handy property of CSS animations is the animation-fill-mode. It allows setting the animated properties to the values they have been animated to, when the animation ends (as opposed to being reset to any applying CSS). This avoids the "jump" whenever you have animated a property to a different value that what normally applies to it.
Last note, on performance: to make sure your animations run smoothly on any device, you should only animate properties which do not trigger repaints on subsequent elements. In fact, you should strive to ever animate only 2 properties: transform and opacity. In your case, rather than animating margin-left, which moves your element around and triggers repaint on subsequent elements in DOM, you should never actually move it and use transform to paint it at different positions.
Here's an example (not sure if this is what you asked for, but you can play around with it some more):
body {
overflow-x: hidden;
background-color: #212121;
}
.example1 h3 {
color: white;
font-size: 3rem;
margin: 0;
line-height: 50px;
animation: example1 5s cubic-bezier(.4,0,.2,1) forwards;
}
#keyframes example1 {
from{
transform: translateX(107%);
}
38% {
opacity: 1;
}
42% {
transform: translateX(35%);
}
60% {
opacity: 0;
transform: translateX(35%);
}
62% {
transform: translateX(0);
opacity: 0;
}
to {
opacity: 1;
}
}
<div class="example1">
<h3>text</h3>
</div>
If, on the contrary, you want your animation looping but want to simply create a smooth transition between end and start, the golden rule is in both from and to keyframes the animated properties have to have the same values (because default value of transform:translateX() is 0 and of opacity is 1, I don't need to set them in from - that's the starting point):
body {
overflow-x: hidden;
background-color: #212121;
}
.example1 h3 {
color: white;
text-align:right;
padding-right: 1rem;
font-size: 3rem;
margin: 0;
line-height: 50px;
animation: example1 5s cubic-bezier(.4,0,.2,1) infinite;
}
#keyframes example1 {
38% {
opacity: 1;
}
42% {
transform: translateX(-60%);
}
58% {
opacity: 0;
transform: translateX(-60%);
}
62% {
transform: translateX(0);
opacity: 0;
}
to {
opacity: 1;
}
}
<div class="example1">
<h3>text</h3>
</div>
For more on animation syntax and examples, I recommend MDN, a well curated documentation library, joint effort of Mozilla, Google, Microsoft and many, many others. Arguably, its most useful feature is linking, in the Specifications section, at the bottom, currently applying standards for the respective property or method, so you don't have to waste time tracking them yourself.
You can use more keyframes percentage to control better your animation in stead of using just two keyframes (from/to).
Below a quick example:
.example1 {
height: 50px;
overflow: hidden;
position: relative;
}
.example1 h3 {
position: absolute;
width: 100%;
height: 100%;
margin: 0;
color: white;
line-height: 50px;
animation: example1 10s linear infinite;te
}
#keyframes example1 {
0% {
margin-left: 60%;
width: 300%;
opacity: 0;
}
50% {
opacity: 1;
}
100% {
margin-left: 35%;
width: 100%;
opacity: 0;
}
}
body {
background-color: black;
}
<div class="example1">
<h3>text</h3>
</div>
Instead of animating the margin-left style you should animate the left style, example:
.example1 {
height: 50px;
width: 400px;
overflow: hidden;
position: relative;
margin: 0 auto;
}
.example1 h3 {
position: absolute;
top: 0;
left: 100%;
line-height: 50px;
animation: example1 10s linear infinite;
}
#keyframes example1 {
from {
left: 100%;
}
to {
left: -10%;
}
}
<div class="example1">
<h3>text</h3>
</div>
I have an animation where a div slides out the view, however when the animation is completed, the div just returns to its origin position in the view. How do I totally remove the div or hide it after the animation ends using just CSS?
Here is the markup:
<div class="container">
<div class="slide-box" id="slide-box""></div>
</div>
and the css:
.slide-box {
position: relative;
width: 100px;
height: 100px;
background-image: url(../pics/red.png);
background-position: center;
background-size: cover;
background-repeat: no-repeat;
animation: slide 5s linear 1;
}
#keyframes slide {
0% {
left: 0;
}
20% {
left: 20%;
}
40% {
left: 40%;
}
60% {
left: 60%;
}
80% {
left: 80%;
}
100% {
left: 100%;
overflow: hidden;
visibility: hidden;
}
}
I don't want it to fade out over the duration of the animation, i just want it to disappear once it hits 100% in the keyframe. Thanks ahead of time!
Use the animation-fill-mode option. Set it to forwards and the animation ends at it's final state and stay like that.
Altered based upon comments Set opacity fade to just last 1% of animation... simplified keyframes. Added a jquery option to literally remove the div from the DOM. CSS alone won't alter the markup, where jQuery will.
Although you can't animate the display property. If you want the div totally gone, after the opacity fades to zero, you can then add the display property to remove the div. If you don't wait for opacity to end, the div will just vanish without any transition.
/*
This jquery is added to really remove
the div. But it'll essentially be
VISUALLY gone at the end of the
animation. You can not use, or
delete the jquery, and you really
won't see any difference unless
you inspect the DOM after the animation.
This function is bound to animation
and will fire when animation ends.
No need to "guess" at timeout settings.
This REMOVES the div opposed to merely
setting it's style to display: none;
*/
$('.slide-box').bind('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function(e) { $(this).remove(); });
.slide-box {
display: block;
position: relative;
left: 0%;
opacity: 1;
width: 100px;
height: 100px;
background: #a00;
animation: slide 1s 1 linear forwards;
/*
animation-name: slide;
animation-duration: 1s;
animation-iteration-count: 1;
animation-timing-function: linear;
animation-fill-mode: forwards;
*/
}
#keyframes slide {
0% {
left: 0%;
opacity: 1;
}
99% {
left: 99%;
opacity: 1;
}
100% {
left: 100%;
opacity: 0;
display: none;
}
}
#-webkit-keyframes slide {
0% {
left: 0%;
opacity: 1;
}
99% {
left: 99%;
opacity: 1;
}
100% {
left: 100%;
opacity: 0;
display: none;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="slide-box" id="slide-box"></div>
</div>
animation: slide 5s linear forwards;
at 100%
opacity: 0;
display: none;
Try this.
Working fiddle: https://jsfiddle.net/jbtfdjyy/1/
UPDATE: JS mani
var slideBox = document.getElementById('slide-box');
setTimeout(function(){
slideBox.style.display = 'none';
}, 5000);
Try this. https://jsfiddle.net/jbtfdjyy/2/
Add something at 99% or so to your keyframes, and set opacity to 1 in that. If you have opacity: 1 at the start, then it will stay that way until 99%. Only at 100% will it change.
It's not technically fired at 100%. If you want that, I'd recommend using some JavaScript here, but this will at least give the illusion you want.
#keyframes slide {
0% {
left: 0;
}
20% {
left: 20%;
}
40% {
left: 40%;
}
60% {
left: 60%;
}
80% {
left: 80%;
}
99% {
opacity: 1;
}
100% {
left: 100%;
overflow: hidden;
opacity: 0;
display: none;
visibility: hidden;
}
}
UPDATE:
As per your request, here is a JavaScript version. Keep in mind, there are endless ways to accomplish such a task. I am using vanilla JS (no jQuery, etc.), and using ES6 syntax.
What we do here is set a timeout, and at the end of that timeout I broadcast an event animation_end. That event listener will handle the end of the animation (in this case, it adds a class which will handle the fading out). This is much more granular than you need it to be, you could simply do the adding of the class within the setTimeout, but I think it is slightly better this way as you can abstract you can do other things with events such as animation start, etc.
Here is the fiddle: https://jsfiddle.net/vmyzyd6p/
HTML:
<div class="container">
<div class="slide-box" id="slide-box""></div>
</div>
CSS:
.slide-box {
position: relative;
width: 100px;
height: 100px;
background-color: blue;
animation: slide 3s linear 1;
-webkit-transition: opacity 2s ease-in-out;
-moz-transition: opacity 2s ease-in-out;
transition: opacity 2s ease-in-out;
}
.animationEnd {
opacity: 0;
}
#keyframes slide {
0% {
left: 0;
}
20% {
left: 20%;
}
40% {
left: 40%;
}
60% {
left: 60%;
}
80% {
left: 80%;
}
100% {
left: 100%;
}
}
JavaScript:
// Create a function that handles the `animation_end` event
const animationEnd = () => {
// Grab the slidebox element
let slideBox = document.getElementById('slide-box');
// Get the class of the slidebox element
let slideClass = slideBox.getAttribute('class');
// Add the animation end class appended to the previous class
slideBox.setAttribute('class', slideClass + ' animationEnd');
};
// Create the animation end event
let animationEndEvent = new Event('animation_end');
// Cross browser implementation of adding the event listener
if (document.addEventListener) {
document.addEventListener('animation_end', animationEnd, false);
} else {
document.attachEvent('animation_end', animationEnd);
}
// Set the timeout with the same duration as the animation.
setTimeout(() => {
// Broadcast the animation end event
document.dispatchEvent(animationEndEvent);
}, 3000);
I am currently having a problem with CSS animations. A random background is called from an array, shows up and changes and so on. I applied two animation for the image caption id, a slide in and a delayed slide out. The slide in and out runs well for the first time, but when the second background shows up, the caption just appears to the screen without any animation.
This is my test page and below is my code.
HTML code:
<script type="text/javascript">
function loadRandomImage(imgs) {
var index = Math.floor(Math.random() * imgs.length);
console.log("loadRandomImages(): index = "+ index);
$.backstretch(imgs[index].url, {duration: 30000, fade: 1200});
$("#caption").html(imgs[index].caption);
}
var images = new Array(); //array of imgs objects
images[0] = {url: "https://s-media-cache-ak0.pinimg.com/736x/a5/47/45/a5474577f4a4ae93c85db719d0cbafd4.jpg", caption: "Caption0"};
images[1] = {url: "https://s-media-cache-ak0.pinimg.com/736x/e6/41/74/e64174e355f78a0f07e951bcec62ca96.jpg", caption: "Caption1"};
images[2] = {url: "https://media.giphy.com/media/3o7abHrsGbV10rCeze/giphy.gif", caption:"Caption2"};
images[3] = {url: "https://media.giphy.com/media/Bbt5FxRiArl3a/giphy.gif", caption:"Caption3"};
// Preload
setTimeout(loadRandomImage, 1000, images);
// Change images every 3 seconds
setInterval(loadRandomImage, 30000, images);
</script>
<div id="pattern"></div>
<div id="pattern2"></div>
<div id="caption"></div>
CSS code:
#caption {
position: relative;
font: 1.5em Trebuchet, sans-serif;
text-align: center;
margin-left: 75%;
z-index: 56;
color: #ffffff;
background: rgba(0, 0, 0, 0.7);
padding: 8px;
animation: slidein 3s, slideout 3s 27s;
}
#caption:empty
{
display: none;
}
#keyframes slidein {
0% {
margin-left: 100%;
width:100%;
visibility:hidden;
opacity: 0;
}
100% {
margin-left: 75%;
width:100%;
opacity: 1;
visibility:visible;
}
}
#keyframes slideout {
0% {
margin-left: 75%;
width:100%;
opacity: 1;
visibility:visible;
}
100% {
margin-left: 100%;
width:100%;
opacity:0;
visibility:hidden;
}
}
CSS animations have iteration count (animation-iteration-count) as only 1 when no value is given for that property. Here since you've not specified any value, the animation executes only once (that is on page load). There is no pure CSS way to re-trigger an animation once it has completed its cycle. It has to be removed from the element and then re-attached for it to start all over again.
So, for your case here is what you have to do - (a) Set the animations on #caption using JS on page load as it makes it easier to remove and re-add them (b) Upon completion of the slideout animation, remove both the animations from the element (that is, set animation-name: none) and also set html of #caption to none because :empty selector would only then hide it. (c) As soon as the next image is set on the element (using loadRandomImage function), set the animations back on the element. This would re-trigger the animation and so during each image switch, the caption would slide-in and out.
Note: I've changed some parts in the HTML and JS that are not relevant to this answer (like removing the two div and replacing them with 1, avoiding the $.backstretch and loading image using css() etc. But these are only auxiliary items and will not affect the crux of this answer (which is, to remove and add the animations).
function loadRandomImage(imgs) {
var index = Math.floor(Math.random() * imgs.length);
$('#img').css('background-image', 'url(' + images[index].url + ')');
$('#caption').css({
'animation-name': 'slidein, slideout',
'animation-duration': '3s, 3s',
'animation-delay': '0s, 7s'
});
$("#caption").html(imgs[index].caption);
}
var images = new Array(); //array of imgs objects
images[0] = {
url: "http://lorempixel.com/100/100/nature/1",
caption: "Caption0"
};
images[1] = {
url: "http://lorempixel.com/100/100/nature/2",
caption: "Caption1"
};
images[2] = {
url: "http://lorempixel.com/100/100/nature/3",
caption: "Caption2"
};
images[3] = {
url: "http://lorempixel.com/100/100/nature/4",
caption: "Caption3"
};
// Preload
setTimeout(loadRandomImage, 1000, images);
$('#caption').on('animationend', function(e) {
if (e.originalEvent.animationName == 'slideout') {
$('#caption').css('animation-name', 'none');
$('#caption').html('');
setTimeout(function() { /* dummy timeout to make sure browser sees animation as none before adding it again */
loadRandomImage(images);
}, 0);
}
});
#caption {
position: relative;
font: 1.5em Trebuchet, sans-serif;
text-align: center;
margin-left: 75%;
z-index: 56;
color: #ffffff;
background: rgba(0, 0, 0, 0.7);
padding: 8px;
}
#caption:empty {
display: none;
}
#keyframes slidein {
0% {
margin-left: 100%;
width: 100%;
visibility: hidden;
opacity: 0;
}
100% {
margin-left: 75%;
width: 100%;
opacity: 1;
visibility: visible;
}
}
#keyframes slideout {
0% {
margin-left: 75%;
width: 100%;
opacity: 1;
visibility: visible;
}
100% {
margin-left: 100%;
width: 100%;
opacity: 0;
visibility: hidden;
}
}
/* Just for demo */
#img {
height: 100px;
width: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="img"></div>
<div id="caption"></div>
The animationend event still requires vendor prefixes in some browsers.
You need to use a callback, which is explained here:
How do create perpetual animation without freezing?
I think the animation direction needs to be altered.
These are the possibilities:
animation-direction: normal|reverse|alternate|alternate-reverse|initial|inherit;
I think you need to do one of these:
alternate
The animation will be played as normal every odd time (1,3,5,etc..) and in reverse direction every even time (2,4,6,etc...)
alternate-reverse
The animation will be played in reverse direction every odd time (1,3,5,etc..) and in a normal direction every even time (2,4,6,etc...)
At the moment it is set as
animation-direction: initial, initial;
Seen here: http://www.w3schools.com/cssref/css3_pr_animation-direction.asp
Rather than the Javascript suggestions already provided, you could do a straight CSS solution.
Just set animation-iteration-count to "infinite" (to continuously alternate the 2 elements, or an integer for a set number of repeats)
If you want staggered / alternating animations:
Use an animation-delay (matching the animation-duration) on the second element so it doesn't appear until the first element animation has completed
Build a delay onto the end of your animation (revert to original state # 50%) so that the first element stays hidden while the second animates.