I'm trying to make some animations compatible with older version of Chrome, specifically 37.0.2062.94 (which is used inside of OBS - a streaming/recording software).
On newer versions of Chrome, everything works great. However, on these older versions, the animation fades in, but the reverse animation does not work. Perhaps animation-direction: reverse? I have tried vendor prefixes etc. as best as I can.
So I'd like to either:
1) Make this method work inside of old Chrome with the CSS animation
or
2) Use JQuery to simulate a fade out effect, making sure it is compatible with older versions of Chrome
Here is a link to the JSFiddle.
HTML
<div id="container">
<div id="one" class="box"></div>
<div id="two" class="box"></div>
<div id="three" class="box"></div>
<div id="four" class="box"></div>
</div>
CSS
* {
margin: 0;
padding: 0;
}
#one {
background: black;
}
#two {
background: blue;
}
#three {
background: green;
}
#four {
background: red;
}
.box {
margin: 10px;
}
.box.animate {
animation: box .4s ease-in;
-webkit-animation: box .4s ease-in;
width: 500px;
height: 500px;
display: block;
}
.box.animate.reverse {
animation-direction: reverse;
-webkit-animation-direction: reverse;
}
#keyframes box {
0% {
opacity: 0;
transform: translate(-10px,-10px);
}
100% {
opacity: 1;
transform: translate(0px,0px);
}
}
#-webkit-keyframes box {
0% {
opacity: 0;
-webkit-transform: translate(-10px,-10px);
}
100% {
opacity: 1;
-webkit-transform: translate(0px,0px);
}
}
JS
var $boxes = $('.box');
(function animateBox(i) {
$boxes.eq(i).addClass('animate').one('animationend', function () {
setTimeout(function () {
$(this).hide().show(0).addClass('reverse').one('animationend', function () {
$(this).removeClass('animate');
if(++i < $boxes.length) setTimeout(animateBox, 1000, i); // pause between animations
});
}.bind(this), 2000); // how long animation stays on
});
})(0);
Related
I managed to achieve this animation through CSS animations and React. but go stuck in flickering problem. I don't know why this is happening maybe 'cause I used setInterval or there is some problem with my css animations keyframes. help me to solve this problem. the flicker only occurs after some time. and after refreshing the page the animation works perfectly fine without flicker problem.
this is how the animation looks after refreshing the page and this is what I want too. (ignore the screen recorder watermark).
animation I want
but after sometime the animation starts flickering like this.
Flickering problem
here are the code snippets I wrote
jsx snippet
<div className="relative w-[280px] md:w-[350px] lg:w-[500px]">
<span>{"[ "}</span>
<p className="text_animate ml-2">
{dev ? "for" : "by"} Developers
</p>
<span className="absolute right-0 ">{" ]"}</span>
</div>
css snippet
.text_animate {
color: orange;
margin: 0 auto;
display: inline-block;
position: relative;
letter-spacing: .15em;
text-align: start;
animation: text-up 6s linear infinite;
cursor: none;
}
#keyframes text-up {
0% {
top:45px;
opacity: 0;
}
20% {
top:0;
opacity: 1;
}
35% {
top: 0;
opacity: 1;
}
50% {
top: -45px;
opacity: 0;
}
52% {
top: 45px;
opacity: 0;
}
70% {
top: 0;
opacity: 1;
}
85% {
top: 0;
opacity: 1;
}
100% {
top: -45px;
opacity: 0;
}
}
useState changing text
const [dev, setDev] = useState(true);
setInterval(() => {
setDev(!dev);
}, 3000);
If there is any better way to achieve this I would really love to learn so let me know that too.
Maybe you should put setInterval to useEffect, and remember to clear timer. Like this:
useEffect(() => {
const timer = setInterval(() => {
setDev(!dev);
}, 3000);
return () => {
clearInterval(timer);
}
}, []);
And there is a solution only using css to implement this, I will write a demo later.
EDIT:
Explain the above code:
useEffect with [] as second param will make sure run setInterval once when mount the component.
The clearInterval in return function will make sure engine GC the variables in setInterval callback functions when unmount the component, or the setInterval will still work even though you needn't it.
CSS only solution:
ul {
margin: 0;
padding: 0;
list-style-type: none;
}
li {
margin: 0;
padding: 0;
}
.scroll-container {
overflow: hidden;
height: calc(var(--line-h) * 1px);
line-height: calc(var(--line-h) * 1px);
font-size: 18px;
}
.scroll-container ul {
animation-name: move;
animation-duration: calc(var(--speed) * var(--lines));
animation-timing-function: steps(var(--lines));
animation-iteration-count: infinite;
}
.scroll-container ul li {
animation-name: li-move;
animation-duration: var(--speed);
animation-iteration-count: infinite;
}
#keyframes move {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(0, calc(var(--lines) * var(--line-h) * -1px));
}
}
#keyframes li-move {
0% {
transform: translate(0, 0);
}
50%,
100% {
transform: translate(0, calc(var(--line-h) * -1px));
}
}
<div
class="scroll-container"
style="--lines: 2; --line-h: 26; --speed: 3s"
>
<ul>
<li>For Developers</li>
<li>By Developers</li>
<!-- repeat first in tail for infinity -->
<li>For Developers</li>
</ul>
</div>
I leaned this from Chokcoco on CodePen but forget which post.
How can I change the function in this script from .click to .scroll (and still have the script working) so that the action is executed on scrolling instead of clicking?
The js code changes the posititon of 3 icons/images that are initially positioned behind another image/icon. Like this: https://prnt.sc/gCyTQDqS_dtD after a click on the image: https://prnt.sc/CjAbwM1D1Cvw
Thanks for your help :-)
<style>
.has-transform, .transform_target .et-pb-icon {
transition: all 400ms ease-in-out;
}
.toggle-transform-animation {
transform: none !important;
}
.transform_target {
cursor: pointer;
}
.toggle-active-target.et_pb_blurb .et-pb-icon {
background-color: transparent;
}
</style>
<script>
(function($) {
$(document).ready(function(){
$('.transform_target').click(function(){
$(this).toggleClass('toggle-active-target');
$('.has-transform').toggleClass('toggle-transform-animation');
});
});
})( jQuery );
</script>
Sadly I think the best solution is to change the entire approach. One option to react to scrolling is to use an intersection observer https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#result
See the little intersection observer demo below; the 2nd kitten will fade into view only when you scroll down
const one = document.querySelector(".one");
const two = document.querySelector(".two");
function handler(entries, observer) {
for (entry of entries) {
if (entry.isIntersecting) {
two.classList.add("show")
} else {
two.classList.remove("show")
}
}
}
let observer = new IntersectionObserver(handler);
observer.observe(two);
.kitten {
width: 100px;
height: 100px;
border-radius: 50%;
}
.two { opacity: 0; }
.two.show{
animation: fadeIn 5s;
animation-fill-mode: forwards;
}
#keyframes fadeIn {
0% {opacity:0;}
100% {opacity:1;}
}
#wrapper {
padding-top: 100vh;
padding-bottom: 100vh;
}
scroll me
<div id="wrapper">
<img class="kitten one" src="//placekitten.com/100/100">
<img class="kitten two" src="//placekitten.com/200/200">
</div>
I'm trying to make element dissapear at the end of animation but it doesn't work, can someone explain how to make exit animation with element dissappearing at the end of it?:
var test = document.getElementById("test");
test.addEventListener("click", displayOpacity);
function displayOpacity(event){
event.target.style.animation = "changeOpacity 1s linear";
if(event.target.style.opacity === 0){
event.target.style.display = "none";
}
}
.container .test {
text-align: center;
padding: 100px;
color: #fff;
background-color: #00f;
max-width: 500px;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
#-webkit-keyframes changeOpacity {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
#keyframes changeOpacity {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
<body>
<div class="container">
<div class="test" id="test">Custom Text</div>
</div>
<script src="main.js"></script>
</body>
Since you have tagged jQuery, wouldn't be it easier to do it with .fadeOut()? The display attribute of the element is being set to none just after the animation has ended.
$('#test').click(function(){
$(this).fadeOut();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='test'>Text</div>
Your issue is because the animation-fill-mode is not being respected as you're overwriting it by setting the animation rule directly on the element itself.
To fix this change your JS code to add a class on the element, and put the animation rule in there, along with the required fill mode:
var test = document.getElementById("test");
test.addEventListener("click", displayOpacity);
function displayOpacity(event) {
this.classList.add('changeOpacity');
}
.container .test {
text-align: center;
padding: 100px;
color: #fff;
background-color: #00f;
max-width: 500px;
}
.changeOpacity {
animation: changeOpacity 1s linear forwards;
}
#-webkit-keyframes changeOpacity {
0% { opacity: 1; }
100% { opacity: 0; }
}
#-webkit-keyframes changeOpacity {
0% { opacity: 1; }
100% { opacity: 0; }
}
#keyframes changeOpacity {
0% { opacity: 1; }
100% { opacity: 0; }
}
<div class="container">
<div id="test" class="test">
Test
</div>
</div>
The animation time is 1 second
event.target.style.animation = "changeOpacity 1s linear";
so just make a timeout
setTimeout(function(){
event.target.style.display = "none";
},1000)
I know there are other and more preferred methods, but I'm trying to give a div img a bounce effect using jQuery.
I'm trying to loop
$('#downarrow').animate({bottom:'4px'});
$('#downarrow').animate({bottom:'0px'});
Any help would be awesome. Thanks!
One very simple solution:
function bounceUp(){
$('#downarrow').animate({bottom:'4px'}, 1000, bounceDown);
}
function bounceDown(){
$('#downarrow').animate({bottom:'0px'}, 1000, bounceUp);
}
bounceUp();
An example: https://jsfiddle.net/DerekL/nd8kf61s/
You can use jQuery to addClass or toggleClass. But this approach using the css animation.
$(document).ready(function() {
$('.arrow').toggleClass('upp');
});
.arrow {
position: relative;
bottom: 0px;
}
.upp {
-webkit-animation: mymove 1.5s infinite;
/* Chrome, Safari, Opera */
animation: mymove 1.5s infinite;
}
/* Chrome, Safari, Opera */
#-webkit-keyframes mymove {
0% {
bottom: 10px;
}
50% {
bottom: 0px;
}
100% {
bottom: 10px
}
}
#keyframes mymove {
0% {
bottom: 10px;
}
50% {
bottom: 0px;
}
100% {
bottom: 10px
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="arrow">
hey
</div>
So, I have created a CSS3 animation that is supposed to fade out an element by setting its opacity from 1 to 0 and at the last frames change the position to absolute and display to none. But on Safari it will only maintain the opacity, position and display are not set to the final values.
#-webkit-keyframes impressum-fade-out {
0% {
opacity: 1;
display: block;
position: relative;
}
99% {
opacity: 0;
position: relative;
}
100% {
opacity: 0;
display: none;
position: absolute;
}
}
It seems to work on Chrome but not on Safari (I tried version 8). Apparently, position and display do not work properly with animation-fill-mode: forwards...
JSFiddle: http://jsfiddle.net/uhtL12gv/
EDIT For Bounty: I am aware of workarounds with Javascript and transitionend events. But I am wondering why Browsers lack support for this? Does the specification state that fillmode forwards doesnt apply to some attributes like position or is this a bug in the browsers? Because I couldnt find anything in the bug trackers.. If anybody has some insight, I would really appreciate it
As Suggested in the comments, you can adjust the height.
EDIT: Animation Reference Links Added.
Display property is not animatable.
Position property is not
animatable.
List of all CSS properties and if and how they are
animatable.
$('.block').click(function() { $(this).toggleClass('active') });
#-webkit-keyframes impressum-fade-out {
0% {
opacity: 1;
}
99% {
opacity: 0;
}
100% {
opacity: 0;
height:0;
}
}
.block {
width: 100px;
height: 100px;
background: blue;
}
.block2 {
width: 100px;
height: 100px;
background: red;
}
.block.active {
-webkit-animation-name: impressum-fade-out;
animation-name: impressum-fade-out;
-webkit-animation-duration: 500ms;
animation-duration: 500ms;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="block"></div>
<div class="block2"></div>
I would suggest you the cross-browser solution based on CSS3 Transitions and transitionend event:
JSFiddle
$('.block').one('click', function() {
var $this = $(this);
$this.one('webkitTransitionEnd transitionend', function() {
$this.addClass('block_hidden');
$this.removeClass('block_transition');
});
$this.addClass('block_transition');
});
.block {
width: 100px;
height: 100px;
background: blue;
-webkit-transition: opacity 0.5s;
transition: opacity 0.5s;
}
.block_2 {
background: red;
}
.block_transition {
opacity: 0;
}
.block_hidden {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="block"></div>
<div class="block block_2"></div>