Rows Image
In the above picture, I want the rows to move to the left infinitely.
Below is the component code:
<div id={id} className="row__posters">
{movies.map((movie) => (
<img
key={movie.id}
onClick={() => handleClick(movie)}
className={`row__poster ${isLargeRow && "row__posterLarge"}`}
src={`${base_url}${
isLargeRow ? movie.poster_path : movie.backdrop_path
}`}
loading="lazy"
alt={movie.name}
/>
))}
</div>
And here is the css for the component code:
.row {
color: white;
margin-left: 20px;
}
.row__posters {
display: flex;
overflow-y: hidden;
overflow-x: scroll;
padding: 20px;
}
.row__posters::-webkit-scrollbar {
display: none;
}
.row__poster {
max-height: 100px;
object-fit: contain;
margin-right: 10px;
transition: transform 450ms;
}
.row__poster:hover {
transform: scale(1.08);
opacity: 1;
}
.row__posterLarge {
/* overflow-x: scroll; */
max-height: 250px;
/* width: calc(250px * 20); */
animation: scroll 40% linear =infinite;
}
.row__posterLarge:hover {
transform: scale(1.09);
opacity: 1;
}
#keyframes scroll {
0% {
transform: translateX(0);
}
100% {
transform: translateX(calc(-250px * 10));
}
}
I want the large row to have an infinite autoplay slider and the other rows shouldn't be affected.
I tried (https://www.youtube.com/watch?v=3Z780EOzIQs) but nothing happened.
Then I tried react-slick third party (https://react-slick.neostack.com/docs/example/pause-on-hover) and it only broke the rows, it turned them into one column(left-aligned).
Do you have any ideas on how to implement this feature?
You can use react-slick for that. If you want to make it infinite scroll. You have to change the settings object. Which you pass inside the Slider Component.
Add these two inside the setting -
autoplay: true,
autoplaySpeed: 2000,
to make it infinite scroll you can use -
infinite: true,
You should also mention how many slides to show.
slidesToShow: 3,
slidesToScroll: 1,
Make sure those properties are these. And you have imported css file inside you component.
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
Related
CodePen
I am trying to replicate the letter flipping animation in Wordle. But I cannot manage the smooth chaining/sequencing. How can I fix it? (I guess I need to use the JS Promise feature, but yet to understand that concept.)
function myFunction() {
var tiles = document.getElementsByClassName("inner");
var myArray = Array.from(tiles);
myArray.map(function (tile) {
tile.classList.add("flip-in");
// tile.style.setProperty("--flipColor", "green");
tile.addEventListener(
"animationend",
() => {
tile.classList.remove("flip-in");
tile.style.backgroundColor = "green";
tile.classList.add("flip-out");
},
{
once: true
}
);
return;
});
}
var flipper = document.getElementById("flipper");
flipper.addEventListener("click", myFunction);
You've essentially done it but probably overengineered it a bit. The wordle animation is pretty simple to accomplish using only one animation.
First, let's take care of the CSS animation. Since we will only use one animation for the entire flip we can rename it "flip".
To simulate the card "flipping" we can adjust the scale on the height rather than flipping it. At the same time, we can also apply the background color change.
We can also remove the animation-delay styles. We will apply these dynamically in the JS.
#keyframes flip {
0% {
transform: scaleY(1);
}
50% {
background: white;
transform: scaleY(0);
}
100% {
transform: scaleY(1);
background: green;
}
}
We have to mark the animation as fill-mode: forwards
.flip {
animation: flip 500ms ease forwards;
}
Next, we can simplify the JS to only apply the class. Do some renaming to easier understand what everyone is and does. And here we can also dynamically apply the animation delay based on the index of the tile. This way we will support all different number of tiles.
function applyFlip() {
var tiles = document.getElementsByClassName("inner");
var tilesArray = Array.from(tiles);
tilesArray.map(function (tile, i) {
tile.classList.add("flip");
tile.style.animationDelay = `${i * 100}ms`;
});
}
var flipper = document.getElementById("flipper");
flipper.addEventListener("click", applyFlip);
Here's a working snippet:
function applyFlip() {
var tiles = document.getElementsByClassName("inner");
var tilesArray = Array.from(tiles);
tilesArray.map(function (tile, i) {
tile.classList.add("flip");
tile.style.animationDelay = `${i * 100}ms`;
});
}
var flipper = document.getElementById("flipper");
flipper.addEventListener("click", applyFlip);
.container {
width: 540px;
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-gap: 2px;
}
.inner {
display: flex;
justify-content: center;
align-items: center;
font-size: 40px;
color: black;
width: 100px;
height: 100px;
background: white;
border: 2px solid black;
border-radius: 6px;
}
button {
margin: 50px;
font-size: 24px;
padding: 4px;
}
.flip {
animation: flip 500ms ease forwards;
}
#keyframes flip {
0% {
transform: scaleY(1);
}
50% {
background: white;
transform: scaleY(0);
}
100% {
transform: scaleY(1);
background: green;
}
}
<div class="container">
<div class="inner">S</div>
<div class="inner">T</div>
<div class="inner">A</div>
<div class="inner">C</div>
<div class="inner">K</div>
</div>
<button id="flipper"> Flipper </button>
I am trying to create a slider component that slides text from right to left, and if the length of the text is longer than the width of the div element keep moving the text until the end of the text is reached.
The code I have just slides until the beginning of the text hits the left end of the div element, and I am trying to have it move until the end of the string hits the right side of the div. The slider component will have both strings which are shorter than the width, in which case the text should move until the left side of the div, if it is longer than the width it should move the end of the string hits the right side of the div.
Any pointers or suggestions on how I can move this text until the end of the text hits the right side of the div?
code:
.slider {
width: 100%;
overflow: hidden;
margin-left: 300px;
background-color: aqua;
}
.slider h2 {
animation: slide-left 10s;
}
#keyframes slide-left {
from {
margin-left: 100%;
}
to {
margin-left: 0%;
}
}
#keyframes slide-right {
to {
transform:translateX(0);
}
}
<div className="slider">
<h2>Hello world, I need a very long text to show how the text will move</h2>
</div>
UPDATE
Using a timer I managed to have an animation that stops when a condition is hit. I sense that the animation speeds-up at the end, so I will try a bit further.
.slider {
width: 100%;
overflow: hidden;
margin-left: 300px;
background-color: aqua;
}
.slider h2 {
animation: slide-left 30s;
animation-play-state: paused;
}
#keyframes slide-left {
from {
margin-left: 0%;
}
to {
margin-left: -1000%;
}
}
#keyframes slide-right {
to {
transform:translateX(0);
}
}
useEffect(() => {
if(executeTimer){
let interval = setInterval(() => {
let sliderElement = document.getElementById('slider');
let sliderWidth = sliderElement.clientWidth;
setCounter(counter + 1);
if(counter === 100){
document.getElementById("slider").style.animationPlayState = "running";
}
if(sliderWidth >= sliderElement.scrollWidth) {
setExecuteTimer(false);
document.getElementById("slider").style.animationPlayState = "paused";
}
},10);
return () => clearInterval(interval);
}
}, [executeTimer, counter]);
return (
<div className="slider" id="slider-container">
<h2 id="slider">Hello world, this is just a little bit longer; no it needs to be just a little bit longer</h2>
</div>
);
I have a similar need so here's the solution I've came up with.
transform: translateX(calc(-100% + 200px));
This did the trick for me.
Only issue is that the speed of the scrolling depends on the length of the text. It doesn't bother me so I won't be trying to 'fix' it.
:root {
--slider-width: 400px;
}
body {
background-color: gray;
}
.slider {
width: var(--slider-width);
height: 40px;
overflow: hidden;
background-color: blue;
white-space: nowrap;
}
.text {
font-size:26px;
display: inline-block;
animation: slide 20s linear infinite;
}
#keyframes slide {
0% {
transform: translateX(0%);
}
50% {
transform: translateX(calc(-100% + var(--slider-width)));
}
100% {
transform: translateX(0%);
}
}
<div class="slider">
<div class="text">
Hello world, I need a very long text to show how the text will move
</div>
</div>
I hope this will help you.
You could change the
margin-left: 0%;
to
margin-left: -200%;
Or some other value which at the very least is -100% or below. If the text may be 3x as wide as the screen then -300% would be needed.
Hello and thank you in advance for reading my question.
GOAL: Set image so that once it's scrolled into view it transitions smoothly into a set position - but still reacts to :hover. Using #keyframes and a little JavaScript, I set the image to opacity: 0 and it's final opacity to opacity: .85. Then I added a hover effect in CSS to make it's opacity: 1
The issue is once it's finished with it's transition - it disappears - reverting to it's original opacity which is zero. I managed to make it freeze at .85 with animation-fill-mode: forwards, rather than animation-fill-mode: none, but then it won't respond to :hover
And here's a test snippet of the problem in action:
let observer_img = new IntersectionObserver(updates => {
updates.forEach(update => {
if (update.isIntersecting) {
update.target.classList.add('shift_frame_center_img');
} else {
update.target.classList.remove('shift_frame_center_img');
}
});
}, { threshold: 0 });
[...document.querySelectorAll('.features-img-wrapper img')].forEach(element => observer_img.observe(element));
body {
width: 100%;
height: 100vh;
background-color: lightgrey;
}
/* CHILD */
.features-img-wrapper img {
width: 10rem;
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 8rem;
opacity: 0;
transition: all .5s;
}
/* APPEND-CHILD */
.shift_frame_center_img {
animation: center_img 1s 0.5s none;
}
/* CHILD ON HOVER */
.features-img-wrapper img:hover {
opacity: 1;
transform: scale(1.035);
}
/* KEYFRAMES */
#keyframes center_img {
0% {
transform: translateY(20rem);
}
100% {
transform: translateY(0);
opacity: .85;
}
}
<body>
<div class="features-img-wrapper">
<img src="https://synapse.it/wp-content/uploads/2020/12/test.png">
</div>
</body>
If I could get a hand with this that would be wonderful, I'm a bit of a beginner and have already spent a few hours on this, all feedback welcome. Thank you very much.
Solution 1
To understand why the hover effect was not working with the animation-fill-mode: forwards, read this answer.
You can fix that by adding !important property to the hover styles:
.features-img-wrapper img:hover {
opacity: 1 !important;
transform: scale(1.035) !important;
}
The problem, in this case, is that the transition will not work for hover.
Solution 2
You could remove the animation entirely and add the final state styles to the shift_frame_center_img class.
But you would still need to use the !important property because of the CSS Specificity.
let observer_img = new IntersectionObserver(updates => {
updates.forEach(update => {
if (update.isIntersecting) {
update.target.classList.add('shift_frame_center_img');
} else {
update.target.classList.remove('shift_frame_center_img');
}
});
}, { threshold: 0 });
[...document.querySelectorAll('.features-img-wrapper img')].forEach(element => observer_img.observe(element));
body {
width: 100%;
height: 100vh;
background-color: lightgrey;
}
/* CHILD */
.features-img-wrapper img {
width: 10rem;
transform: translateY(20rem);
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 8rem;
opacity: 0;
transition: all .5s;
}
/* APPEND-CHILD */
.shift_frame_center_img {
transform: none !important;
opacity: .85 !important;
}
/* CHILD ON HOVER */
.features-img-wrapper img:hover {
opacity: 1 !important;
transform: scale(1.035) !important;
}
<body>
<div class="features-img-wrapper">
<img src="https://synapse.it/wp-content/uploads/2020/12/test.png">
</div>
</body>
This snippet removes the need for fill-mode forwards by setting the img to have opacity 1 as its initial state so it will revert to that at the end of the animation.
The animation itself is altered to take 1.5s rather than 1s with the first third simply setting the img opacity to 0 so it can't be seen. This gives the delay effect.
let observer_img = new IntersectionObserver(updates => {
updates.forEach(update => {
if (update.isIntersecting) {
update.target.classList.add('shift_frame_center_img');
} else {
update.target.classList.remove('shift_frame_center_img');
}
});
}, { threshold: 0 });
[...document.querySelectorAll('.features-img-wrapper img')].forEach(element => observer_img.observe(element));
body {
width: 100%;
height: 100vh;
background-color: lightgrey;
}
/* CHILD */
.features-img-wrapper img {
width: 10rem;
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 8rem;
opacity: 0;
transition: all .5s;
opacity: 1;
}
/* APPEND-CHILD */
.features-img-wrapper img {
animation: center_img 1.5s 0s none;
}
/* CHILD ON HOVER */
.shift_frame_center_img:hover {
opacity: 1;
transform: translateY(0) scale(1.035);
}
/* KEYFRAMES */
#keyframes center_img {
0% {
transform: translateY(20rem) scale(1);
opacity: 0;
}
33.33% {
transform: translateY(20rem) scale(1);
opacity: 0;
}
100% {
transform: translateY(0) scale(1);
opacity: .85;
}
}
<body>
<div class="features-img-wrapper">
<img src="https://synapse.it/wp-content/uploads/2020/12/test.png">
</div>
</body>
Note: as each transform setting will reset anything that isn't included both tranlateY and scale are included in each setting.
Outside the SO snippet system it was possible to leave the animation settings untouched by chaining another animation to the front which ran for 0.5s and just set the img to opacity: 0. This did not work in the snippet system (it got into a loop of flashing on and off) hence the introduction of one but extended animation.
So I have an image viewer which has a zoom functionality, which works via the transform: scale() property.
Animating the zoom is no problem with transition: transform .3s.
To make the zoom on the mousewheel go to where the mousewheel is pointed, I calculated the correct position to set the new origin, but when I set it, it just jumps there with no animation.
What I have tried:
Setting transition for the transform-origin property → Doesn't work
Doing it manually in JS with setTimeout and slowly setting the transform-origin at the right position → plays the zoom animation and then jumps
Is there any way to animate both transform: scale() and transform-origin in one go?
Dupe
As the last question has been closed as a duplicate of How to have multiple CSS transitions on an element?, here is a snippet, to show you that this is not my question.
const img = document.querySelector('#container img');
let on = true;
const toggleEffect = () => {
if(on) {
img.style.transform = 'scale(2.5)';
img.style.transformOrigin = '80% 80%';
} else {
img.style.transform = 'scale(1.4)';
img.style.transformOrigin = '20% 20%';
}
on = !on;
};
#container {
width: 500px;
height: 300px;
overflow: hidden;
background-color: red;
}
#container img {
height: 100%;
width: 100%;
object-fit: contain;
transform: scale(1.4);
transform-origin: 20% 20%;
transition: transform .3s, transform-origin .3s;
}
<div id="container">
<img src="https://images.unsplash.com/photo-1482066490729-6f26115b60dc?ixlib=rb-1.2.1&auto=format&fit=crop&w=2004&q=80"/>
</div>
<button onclick="toggleEffect()">Toggle</button>
EDIT: Technically this is a duplicated. (Chrome Bug in some versions)
- Using both transition:
body, div {
width: 100%;
height: 100vh;
overflow: hidden;
}
div {
background-color: gray;
width: auto;
display: flex;
justify-content: center;
align-items: center;
font-size: 30px;
transform: scale(1.1);
transform-origin: 50% -30px -100px;
transition: transform-origin .2s ease-in-out, transform 4s ease-in-out;
}
div:hover {
transform: scale(1.7);
transform-origin: 100px 100px;
}
<div>Test</div>
- Using animation with#keyframes:
body,div {
width: 100%;
height: 100vh;
}
div {
width: auto;
display: flex;
justify-content: center;
align-items: center;
transform-origin: 0 0 0;
animation: scale-origin 3s infinite;
font-size: 30px;
}
#keyframes scale-origin {
0% {
transform: scale(.5);
transform-origin: 100px 100px 1000px;
}
100% {
transform: scale(1.1);
transform-origin: left 500px -30px
}
}
<div>Test</div>
For me the only way to get around this bug was to ensure a redraw of the element on each "animation" (in this case transition) frame as you can clearly see via getComputedStyle that the transform-origin is correctly transitioned!
Basically I added eventlisteners for the transitionstart and transitionend and on each animationframe toggle some style attribute that enforces a redraw (f.e. in my case margin-left from 0 to 1 to 0px until the animation is finished)
function forceRedraw(ts) {
this.style.marginLeft = this.style.marginLeft == '1px' ? '0px':'1px';
if (this.classList.contains('transitioning'))
requestAnimationFrame(forceRedraw.bind(this));
}
In my example I transition rotation and the transform-origin (from top left to bottom left) at the same time.
https://codepen.io/ftav/pen/QWvYEPj
Depending on which element you modify this might have more or less of a performance impact. It works fine for me. I just wish they would fix the bug and this workaround could go away.
After the slide animation (scale(1.3) to scale(1)) finishes and moving back to the slide I get this annoying jump.
I want that each active slide will be already in scale(1.3) without the jump.
$('.home-slider').slick({
slidesToScroll: 1,
slidesToShow: 1,
//arrows: true,
autoplay: true,
autoplaySpeed: 7000,
dots: false
})
body,
html {
height: 100%;
background: #333;
font-family: 'Roboto', sans-serif;
}
.slideshow {
position: relative;
z-index: 1;
height: 100%;
max-width: 700px;
margin: 50px auto;
}
.slideshow .item {
height: 100%;
position: relative;
z-index: 1;
}
.slideshow .item img {
width: 100%;
}
.slideshow .item.slick-active img {
-webkit-animation: ken-burns-out 8s 1 ease-in-out forwards;
animation: ken-burns-out 8s 1 ease-in-out forwards;
}
/*//The animation: from 1.3 scale to 1*/
#-webkit-keyframes ken-burns-out {
0% {
-webkit-transform: scale(1.3);
transform: scale(1.3)
}
to {
-webkit-transform: scale(1);
transform: scale(1)
}
}
#keyframes ken-burns-out {
0% {
-webkit-transform: scale(1.3);
transform: scale(1.3)
}
to {
-webkit-transform: scale(1);
transform: scale(1)
}
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick-theme.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.js"></script>
<div class="slideshow">
<div class="home-slider">
<div class="item">
<img src="https://images.unsplash.com/photo-1532386236358-a33d8a9434e3?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=978&q=80" />
</div>
<div class="item">
<img src="https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80" />
</div>
</div>
</div>
The problem happens because all of the images gets the same z-index.
My code doesn't work when you navigate from first slide to last slide (slide right), but it's something to start with.
first of all, delete the z-index from this selector: .slideshow .item.
Then, add transform to every image in order every image to start with this scale (maybe add class name to each image and then change the selector):
img {
transform: scale(1.3);
}
Add a function to get slick by index (there are cloned slicks elements so I use the selector that gets un-cloned slicks):
function getSlickByIndex(index) {
return $('.item:not(.slick-cloned)[data-slick-index="' + index + '"]');
}
Then, add init event (the logic makes the first slide to get the bigger zIndex=1 of all of his siblings that have zIndex=0), and beforeChange (the logic makes the next slick to get the bigger index and the others to get the smaller index):
$('.home-slider').on('init', function(event, slick){
getSlickByIndex(0).css('zIndex', '1');
}).on('beforeChange', function(event, slick, currentSlide, nextSlide){
getSlickByIndex(currentSlide).css('zIndex', '0');
getSlickByIndex(nextSlide).css('zIndex', '1');
});
Demo
img {
transform: scale(1.3);
}
body,
html {
height: 100%;
background: #333;
font-family: 'Roboto', sans-serif;
}
.slideshow {
position: relative;
z-index: 1;
height: 100%;
max-width: 700px;
margin: 50px auto;
}
.slideshow .item {
height: 100%;
position: relative;
z-index: 1;
}
.slideshow .item img {
width: 100%;
}
.slideshow .item.slick-active img {
-webkit-animation: ken-burns-out 8s 1 ease-in-out forwards;
animation: ken-burns-out 8s 1 ease-in-out forwards;
}
/*//The animation: from 1.3 scale to 1*/
#-webkit-keyframes ken-burns-out {
0% {
-webkit-transform: scale(1.3);
transform: scale(1.3)
}
to {
-webkit-transform: scale(1);
transform: scale(1)
}
}
#keyframes ken-burns-out {
0% {
-webkit-transform: scale(1.3);
transform: scale(1.3)
}
to {
-webkit-transform: scale(1);
transform: scale(1)
}
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.js"></script>
<div class="slideshow">
<div class="home-slider">
<div class="item">
<img src="https://images.unsplash.com/photo-1532386236358-a33d8a9434e3?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=978&q=80" />
</div>
<div class="item">
<img src="https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80" />
</div>
<div class="item">
<img src="https://images.unsplash.com/photo-1532386236358-a33d8a9434e3?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=978&q=80" />
</div>
<div class="item">
<img src="https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80" />
</div>
</div>
</div>
<script>
function getSlickByIndex(index) {
return $('.item:not(.slick-cloned)[data-slick-index="' + index + '"]');
}
$('.home-slider').on('init', function(event, slick){
getSlickByIndex(0).css('zIndex', '5555');
}).on('beforeChange', function(event, slick, currentSlide, nextSlide){
getSlickByIndex(currentSlide).css('zIndex', '0');
getSlickByIndex(nextSlide).css('zIndex', '5555');
});
$('.home-slider').slick({
slidesToScroll: 1,
slidesToShow: 1,
//arrows: true,
autoplay: true,
autoplaySpeed: 7000,
dots: false
});
</script>
This is a working fiddle: https://codepen.io/alonsh/pen/JQmZjj
Your images are starting with a scale of 1, then when they become active the animation starts them off at 1.3 which is what causes the jump. What you need to do is start all the images off at a scale(1.3) by adding this to the .item img css definition.
Doing only that causes the images to overflow onto one another. To combat that make sure the contents of each .item don't overflow by adding overflow: hidden which results in:
EDIT
Which results in code which still doesn't quite work correctly. We still need everything from the previous answer but we end up with the opposite issue where the images jump to the fully zoomed size when they're switched off.
This became a bit of a rabbit hole, but there is an animation-play-state property in css which we can use to pause the animation at the state it is in when an item becomes inactive, so I made the animation play on every .item element, which means that when it's scrolled away and the active class is lost, it will pause the animation where it is.
This almost gets us to the desired result, but then when an image is brought back into view, it resumes from where it has left off. It turns out there isn't a pretty way to get a css animation to restart, so what I'm doing is I've bound to the slide change event for slick and when a slide has changed (which I believe guarantees only the active slide is visible) I reset the .item animation. In order to do this in a way which doesn't interrupt the active slide I've added a class .animated which I can remove, then add back later in a setTimeout. The delay is needed in order for the animation to restart.
You'd hope that was the end, but you'd be wrong. THEN Slick considers a started swipe, which then lands back on the same image to be a slide change ("change") so I added a current slide variable to keep track of which slide we are on and only reset the .animated class if the slide did actually change. Important Note: in a real project I would wrap this currentSlide in some sort of class/object to track the state of an individual slideshow, because as it stands you couldn't have more than one slideshow on a single page without them interfering. But I wasn't going to write all of that for a simple example.
After all of this, we end up with slightly different CSS and a bit more JS to get a working result:
$('.home-slider').slick({
slidesToScroll: 1,
slidesToShow: 1,
//arrows: true,
autoplay: true,
autoplaySpeed: 7000,
dots: false
});
var currentSlide = 0;
$('.home-slider').on('afterChange', function(event, slick, newSlide){
var items = $('.home-slider .item');
if(currentSlide != newSlide){
currentSlide = newSlide;
items.removeClass('animated');
setTimeout(function(){
items.addClass('animated');
});
}
});
body,
html {
height: 100%;
background: #333;
font-family: 'Roboto', sans-serif;
}
.slideshow {
position: relative;
z-index: 1;
height: 100%;
max-width: 700px;
margin: 50px auto;
}
.slideshow .item {
height: 100%;
position: relative;
overflow: hidden;
}
.slideshow .item img {
width: 100%;
-webkit-transform: scale(1.3);
transform: scale(1.3);
}
.slideshow .item.animated img {
-webkit-animation: ken-burns-out 8s 1 ease-in-out forwards;
animation: ken-burns-out 8s 1 ease-in-out forwards;
animation-play-state: paused;
}
.slideshow .item.slick-active img {
animation-play-state: running;
}
/*//The animation: from 1.3 scale to 1*/
#-webkit-keyframes ken-burns-out {
0% {
-webkit-transform: scale(1.3);
transform: scale(1.3);
}
to {
-webkit-transform: scale(1);
transform: scale(1)
}
}
#keyframes ken-burns-out {
0% {
-webkit-transform: scale(1.3);
transform: scale(1.3)
}
to {
-webkit-transform: scale(1);
transform: scale(1)
}
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick-theme.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.js"></script>
<div class="slideshow">
<div class="home-slider">
<div class="item animated">
<img src="https://images.unsplash.com/photo-1532386236358-a33d8a9434e3?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=978&q=80" />
</div>
<div class="item animated">
<img src="https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80" />
</div>
</div>
</div>