How to detect a CSS transition with JS - javascript

EDIT
I tried animationstart and animationend. And what I found is that animationstart triggers right away then when keyframe reaches 100% animationend triggers and says the animation is finished. What I wanted to know is it possible to monitor what is happening in between or inside the animation? Like monitor each keyframe? Example as on this example I am running the animation for 4 images so when each image slides in can I monitor that and console.log("incoming image or something").
Is it possible to monitor each keyframe like when an image is sliding in?
I am trying to make image carousel. I have set it up with css animation so transition is happening in a loop with the css. Then after that I added two button's nextBtn and prevBtn. And they are doing their trick of sliding through the images. But I have a problem cant use both functionality I get displacement issues if I try to use both functionality if I press next to many times it messes it up basically, while the css is doing the looping animation effect. So I tried to disable the buttons when a transition has started with the eventlistener "transitionstart" but the problem with this is the javascript cant "hear or listen" if the css is doing the transition animation. But If i physically press on the button then js fires up the eventlistener off transitionstart. so how can I make javascript "hear/listen" to when the css file does the animation
here is some of the js transitionstart eventlistener code
slideContainer.addEventListener('transitionstart', () => {
console.log('transition has started') // it cant hear and is not listening when movement animation transition is comming from the css file but it fires up if i physically press the next button
document.getElementById("prev").setAttribute('disabled', true);
document.getElementById("next").setAttribute('disabled', true);
})
so how do you detect a css animation transition with javascript?
the html element I wrote as:
<div id="slider">
<figure>
<img src="./images/image-product-4.jpg" id="lastClone" alt="product-4" />
<img src="./images/image-product-1.jpg" id="product-1" alt="product-1" />
<img src="./images/image-product-2.jpg" id="product-2" alt="product-2" />
<img src="./images/image-product-3.jpg" id="product-3" alt="product-3" />
<img src="./images/image-product-4.jpg" id="product-4" alt="product-4" />
<img src="./images/image-product-1.jpg" id="firstClone" alt="product-1" />
</figure>
<img id="next" class="next pointer" src="./images/icon-next.svg" alt="next-img">
<img id="prev" class="previous pointer" src="./images/icon-previous.svg" alt="previous-img">
</div>
as on the beginning of my js file I have the following logic to skip the first id="lastClone" image
const slideContainer = document.querySelector('figure');
const slideImages = document.querySelectorAll('figure img');
// counter
let counter = 1;
let size = slideImages[0].clientWidth;
slideContainer.style.transform = 'translateX(' + (-size * counter) + 'px)';
// then here I want to listen for transitionstart
slideContainer.addEventListener('transitionstart', () => {
console.log('transition has started') // it cant hear and is not listening when movement happens from the css file
document.getElementById("prev").setAttribute('disabled', true);
document.getElementById("next").setAttribute('disabled', true);
})
// but it cant detect if the transition is done by the css animation
and here is my css
#slider {
overflow: hidden;
}
#slider figure {
width: 600%;
/* width: 100%; */
display: flex;
margin: 0;
left: 0;
animation: 50s slider infinite;
/* top: 50px; */
}
#slider figure img {
float: left;
width: 20%;
}
#keyframes slider {
0% { left: 0; }
20% { left: 0; }
25% { left: -100%; }
45% { left: -100%; }
50% { left: -200%; }
70% { left: -200%; }
75% { left: -300%; }
95% { left: -300%; }
100% { left: -400% }
}
figure {
position: relative;
height: 20rem;
overflow: hidden;
}
figure img {
object-fit: fill;
height: 100%;
}
Live example of my code:
https://jsfiddle.net/CustomHaven/51mLatkr/34/
EDIT
I tried animationstart and animationend. And what I found is that animationstart triggers right away then when keyframe reaches 100% animationend triggers and says the animation is finished. What I wanted to know is it possible to monitor what is happening in between or inside the animation? Like monitor each keyframe? Example as on this example I am running the animation for 4 images so when each image slides in can I monitor that and console.log("incoming image or something").
Is it possible to monitor each keyframe like when an image is sliding in?

you can try :
element.ontransitionstart = () => {
console.log('Started transitioning');
};
with element is : getElementById ....

Related

Uneven intervals with setInterval function due to other code running between intervals;

I am trying to have a div do a simple slide into a parent div in a React project using pure JS and am having problems with the smoothness of the slide. When I console log, I can see that when the code (slideIn) runs, between setInterval calls, React runs other code which take up more time than the specified intervals. Therefore, the intervals are not even, which seems to be causing the jerkiness in the slide.
I have tried requestAnimationFrame also, but the result is the same.
The challenge seems to be to make the slideIn continuous without having react run other code while running it, but how does one do that?
<div className="outer-box">
<div className="sliding-box"></div>
</div>
.outer-box {
width: 300px;
height: 200px;
position: relative;
}
.sliding-box {
width: 100%;
height: 100%;
position: absolute;
top: 0;
}
slideIn() {
const moveElemment = document.getElementById('sliding-box');
const pos = -100;
if (moveElemment) {
const id = setInterval(frame, 10);
function frame() {
if (pos == 0) {
clearInterval(id);
} else {
pos++;
moveElemment.setAttribute('style', `left: ${pos}%`);
}
}
}
}
Perphas you could take advantage of CSS transitions to achieve smoother animation that is decoupled from the JS thread, to resolve your problem? For example, you could update your CSS with a transition rule and additional selector as follows:
.sliding-box {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: -100px; // Initial position of sliding-box
transition: left 1s linear; //Specify the animation behaviour
}
.sliding-box.in {
left: 0px; // Position of sliding-box after animation
}
with simplified JS to trigger the transition animation as follows:
slideIn() {
const moveElemment = document.getElementById('sliding-box');
if (moveElemment) {
// When this selector is added, it triggers the animation
// transition from left:-100px to left:0px over a 1 second
// interval
moveElemment.classList.add('in');
}
}

Changing image on hover and back using fade

I'm trying to change an image on hover and back again.
The idea is that when I hover over an image, it fades into a different image and when my mouse leaves, the image fades back to the original.
Here is what I have tried so far, using jQuery:
<img src="https://www.shareicon.net/data/128x128/2015/08/17/86675_cat_256x256.png" />
<script>
$("img").hover(function(event) {
event.preventDefault();
console.log("hover");
$("img").fadeOut(400, function() {
$("img").attr("src", "http://files.softicons.com/download/animal-icons/meow-icon-set-by-iconka/png/128x128/cat_purr.png")
}).fadeIn(400, function() {
$("img").attr("src", "https://www.shareicon.net/data/128x128/2015/08/17/86675_cat_256x256.png")
});
});
</script>
You can actually do this with plain CSS and it would be more efficient.
Just create a div, put both images inside, absolute position so one is on top of another, and when hover apply opacity: 0 with a transition to the front image.
You can achieve this with position absolute, z-index, and hover pseudo selector.
.container{
width: 300px;
height: 300px;
position: relative;
}
img{
position: absolute;
top: 0;
left: 0;
}
.img-top{
z-index: 999999;
transition: 0.3s linear all;
}
.img-top:hover{
opacity: 0;
}
<div class="container">
<img class="img-bottom" src="https://www.cesarsway.com/sites/newcesarsway/files/d6/images/askthevet/checklist.jpg" alt="">
<img class="img-top" src="https://i.ebayimg.com/images/g/k2gAAOSwT5tWKhVS/s-l300.jpg" alt="">
</div>

How to add transition when changing img src on hover?

So I'm trying to add a different image when the original image is hovered over using javascript. The syntax I have is similar to this, which works great.
function imgHover() {
projectImage.src = '../img/img1.png';
}
function imgHover2() {
projectImage.src = '../img/img2.png';
}
projectImage.addEventListener('mouseover', imgHover);
projectImage.addEventListener('mouseleave', imgHover2);
Now I'm trying to find a way to make the image transition from one to the other (most likely using opacity.) Any suggestions on how to do this? I can't figure it out.
You can't create a transition effect changing just the src tag of an image.
One way of doing this is to create two image that is positioned absolute on top of each other with the top one having an opacity of 0.
If you need to change the hover image dynamically, you can still do that through javascript.
.image-wrapper {
position: relative;
}
.image-hover {
position: absolute;
top: 0;
left: 0;
opacity: 0;
transition: opacity 1s ease-out;
}
.image-hover:hover {
opacity: 1;
}
<div class="image-wrapper">
<img src="http://via.placeholder.com/350x150?text=normal" class="image" alt="normal" />
<img src="http://via.placeholder.com/350x150?text=hover" class="image-hover" alt="hover" />
</div>

How can I make this Jquery animate() with css3 animations?

This is my jfiddle
And this is my actual code
$card.animate({
left: "1000px"
}, 500, function(){
$card.hide(500);
});
(I dont know why 'left' didnt work on jfiddle) Basically ive got a container with 5 $cards there. When user swipes the card (already implemented) the animate() is triggered and the card slides to the rightand then disappears. How can I implement such thing in CSS animations instead of using Jquery? Ive read that CSS animations run faster (and I proved it on my mobile device, the hide() runs really slow)... Any help or advice will be appreciated
First of all, create a class that you can trigger via jQuery that will have the animation.
Then, using you have two options: transition or animation. Transitions are simpler and more direct, but you can do more with animations.
Here is how I would suggest to do it: a transition for the movement, and an animation to recreate the hide() function.
#keyframes hide {
99% { display: auto; }
100%{ display: none; opacity: 0; }
}
.myelement {
transition: all .5s;
position: absolute;
left: 0;
}
.myelement.toLeft {
left: 2000px;
animation: hide .5s 1 forwards;
}
To trigger it, simply do this:
$(".myelement").addClass("toLeft");
Here is a working JSFiddle.
And like #MohitBhardwaj said, it is necessary for you to set position to absolute, relative, or static in order for positioning (i.e., the left property) to work.
It's also important to note that a transition needs an initial value. I added left: 0 to do this. Otherwise, (with a CSS transition) it would simply jump to 2000px because there is no starting point.
Also, because 2000px as a left value is very large, I suggest you change the parent element's scroll to overflow: hidden, so that the extraneous scroll bar doesn't appear.
Your left didn't work, because you need to set position to a value other than static (which is default) for it to work.
As for using CSS, you can add a class instead of animating in jQuery. This class can change the transition which you can set in css as per your requirements.
var my_div = $('.myelement');
my_div.on('click', function() {
var $this = $(this);
$this.addClass("gone");
setTimeout(function(){
$this.hide();
}, 600 );
})
#mywrapper
{
overflow: hidden;
}
.myelement {
height: 200px;
width: 200px;
background-color: red;
opacity: 1;
position: relative;
transition: all 0.5s ease;
opacity: 1;
left: 0px;
}
.myelement.gone
{
left: 500px;
opacity: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="mywrapper">
<div class="myelement">
Click me please
</div>
</div>

jquery slideshow using background images

I have a div which currently has a static background image.
I need to create a slideshow of background images for this div.
I am able to achieve this by just setting a timeout and then changing the background image in the CSS but this is not very elegant.
I would ideally like to fade the background images out and in, but the div contains other page elements so I can not alter the opacity in any way.
Does anyone know of a good way to do this using jquery??
Here's some code which fades out/in but fades out the contents of the div too.
$("#slideshow").fadeOut(5000, function(){
$("#slideshow").css('background-image','url(myImage.jpg)');
$("#slideshow").fadeIn(5000);
});
HTML:
<div class="slideshow"></div>
CSS:
.slideshow
{
position: relative;
width: 350px;
height: 150px;
}
.slideshow img
{
position: absolute;
width: 350px;
height: 150px;
z-index:-1;
}
jQuery
var images=new Array('http://placehold.it/250x150','http://placehold.it/250x150/123456','http://placehold.it/250x150/dbca98');
var nextimage=0;
doSlideshow();
function doSlideshow()
{
if($('.slideshowimage').length!=0)
{
$('.slideshowimage').fadeOut(500,function(){slideshowFadeIn();$(this).remove()});
}
else
{
slideshowFadeIn();
}
}
function slideshowFadeIn()
{
$('.slideshow').prepend($('<img class="slideshowimage" src="'+images[nextimage++]+'" style="display:none">').fadeIn(500,function(){setTimeout(doSlideshow,1000);}));
if(nextimage>=images.length)
nextimage=0;
}
jsfiddle Demo
How about adding a thumbs pagination list, to update the background image on click, and then, a second or two, and it starts fading in and out with the next bg img automatically?
HTML:
<div class="slideshow">
<h1>Text</h1>
<input type="button" value="Hello" />
</div>
<ul>
<li><img src="http://placehold.it/50x50"></li>
<li><img src="http://placehold.it/50x50/123456"></li>
<li><img src="http://placehold.it/50x50/dbca98"></li>
</ul>
CSS:
.slideshow
{
position: relative;
width: 350px;
height: 150px;
}
.slideshow img
{
position: absolute;
width: 350px;
height: 150px;
z-index:-1;
}
ul {position: absolute; top: 125px; left: 75px;}
li {
float: left;
border: 1px solid #000;
margin: 15px;
}
Javascript:
var images=new Array('http://placehold.it/250x150','http://placehold.it/250x150/123456','http://placehold.it/250x150/dbca98');
var nextimage=0;
doSlideshow();
function doSlideshow()
{
if($('.slideshowimage').length!=0)
{
$('.slideshowimage').fadeOut(500,function(){slideshowFadeIn();$(this).remove()});
}
else
{
slideshowFadeIn();
}
}
function slideshowFadeIn()
{
$('.slideshow').prepend($('<img class="slideshowimage" src="'+images[nextimage++]+'" style="display:none">').fadeIn(500,function(){setTimeout(doSlideshow,1000);}));
if(nextimage>=images.length)
nextimage=0;
}
See it all together at http://jsfiddle.net/tatygrassini/R4ZHX/75/.
Instead of just changing the background image, you could first call
fadeOut()
then change source, and then call
fadeIn()
something like...
$('#image').fadeOut(500, function() {
$(this).attr('src', 'new-image.png')
.load(function() {
$(this).fadeIn();
});
});
To use a variety of images, there are a number of solutions, but you could simply iterate through a list of them.
You can create an positioned absolutely and with a slider plugin change the images contained in the div. Otherwize you have to sprite the background. I achieved this with the Jquery Tools tabs plugin.
$(".slidetabs").tabs(".images > div", {
// enable "cross-fading" effect
effect: 'fade',
fadeOutSpeed: "slow",
// start from the beginning after the last tab
rotate: true
// use the slideshow plugin. It accepts its own configuration
}).slideshow();
Here is a solution that not only addresses your problem, but will also solve some other problems as well. Create another DIV on your DOM as an overlay, and execute your fade functions on this DIV only. It will appear as though the content is fading in / out. This approach is also more performant, as you are only fading a single DIV instead of multiple elements. Here is an example:
$('#containeroverlay').width($('#container').width()).height($('#container').height()).fadeIn('normal', function() {
// Step 1: change your content underneath the hidden div
// Step 2: hide the overlay
$('#containeroverlay').fadeOut('normal');
})
Most importantly, this approach will work in IE6-8 without screwing up the font aliasing of elements you may have on the div.

Categories