So recently I had my exams and unfortunately failed because of CSS animation. One of the tasks was to make CSS animation with the squares.
I can't remember the exact question and task but it was like this:
Make three squares and let the first one go for 2 seconds to the right
Wait for the second square to do the same thing, without returning back.
The third one should do the same thing
After the third square touches the right side, they all should go back to the first place.
Does anyone have an idea how I can make squares to go back to the first place?
.row {
margin-bottom: 10px;
}
.row div {
display: inline-block;
padding: 50px;
background-color: red;
position: relative;
}
#first {
animation: first 2s linear forwards 0ms,
back 2s linear alternate 5s;
}
#second {
animation: first 2s linear forwards 2s;
}
#third {
animation: first 2s linear forwards 4s;
}
#keyframes first {
0% {
left: 0;
}
100% {
left: 100%;
}
}
#keyframes back {
0% {
right: 0%;
}
100% {
right: 100%;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Animation testing</title>
</head>
<body>
<div class="row">
<div id="first"></div>
</div>
<div class="row">
<div id="second"></div>
</div>
<div class="row">
<div id="third"></div>
</div>
</body>
</html>
Interesting task. Today I learned something. Actually my first animation ever :)
To move the squares to the right:
I have used your existing and already correctly working first, second, and third keyframes with the same timings.
The first starts at 0s and takes 2 seconds, the second starts after two seconds and takes two seconds, so the third after 4 seconds.
To return the squares:
I have defined another back keyframe.
To start the back keyframe, I have added back 2s linear forwards 6s to all elements as a second animation.
The second animation takes 2 seconds and starts after 6 seconds when all others are finished (3 * 2 seconds each).
Note: You could also reverse the positions in the back keyframe and use one of the alternatives to forwards instead, see https://www.w3schools.com/css/css3_animations.asp.
.row {
margin-bottom: 10px;
}
.row div {
display: inline-block;
padding: 50px;
background-color: red;
position: relative;
}
#first {
animation: first 2s linear forwards 0s,
back 2s linear forwards 6s;
}
#second {
animation: second 2s linear forwards 2s,
back 2s linear forwards 6s;
}
#third {
animation: third 2s linear forwards 4s,
back 2s linear forwards 6s;
}
#keyframes first {
0% {
left: 0;
}
100% {
left: 100%;
}
}
#keyframes second{
0% {
left: 0;
}
100% {
left: 100%;
}
}
#keyframes third{
0% {
left: 0;
}
100% {
left: 100%;
}
}
#keyframes back{
0% {
left: 100%;
}
100% {
left: 0;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Animation testing</title>
</head>
<body>
<div class="row">
<div id="first"></div>
</div>
<div class="row">
<div id="second"></div>
</div>
<div class="row">
<div id="third"></div>
</div>
</body>
</html>
Try this, it may work.
.move-me {
display: inline-block;
padding: 20px;
color: white;
position: relative;
margin: 0 0 10px 0;
}
.move-me-1 {
animation: move-in-steps 8s steps(4) infinite;
}
.move-me-2 {
animation: move-in-steps 8s steps(4, start) infinite;
}
.move-me-3 {
animation: move-in-steps 8s infinite;
}
body {
padding: 20px;
}
#keyframes move-in-steps {
0% {
left: 0;
background: blue;
}
100% {
left: 100%;
background: red;
}
}
<div class="move-me move-me-1">steps(4, end)</div>
<br>
<div class="move-me move-me-2">steps(4, start)</div>
<br>
<div class="move-me move-me-3">no steps</div>
Related
I want to have two animations applied to an element. These animations will execute sequentially infinite number of times. I want to use pure CSS without JS.
#keyframes show {
from,
to {
z-index: 100;
}
}
#keyframes wait {
from,
to {
}
}
.block {
position: absolute;
z-index: -100;
width: 100px;
height: 100px;
border: 1px solid black;
animation: 1s show infinite, 1s wait infinite;
}
.block-a {
background-color: red;
animation-delay: 0s, 1s;
}
.block-b {
background-color: purple;
animation-delay: 1s, 2s;
}
.block-c {
background-color: yellow;
animation-delay: 2s, 3s;
}
<div class="container">
<div class="block block-a">1</div>
<div class="block block-b">2</div>
<div class="block block-c">3</div>
</div>
Here is my current solution on codepen: https://codepen.io/olafvolafka/pen/oNpPeqj
The issue is the animation stops after the last animation and doesn't repeat.
Here below you will see an implementation of A Haworth's Comment to enforce the z-index at the end of each animation iteration to return to the same value it was at the start (this case: -100).
Doing this is with the keyframe 50% setting the z-index at the front (100) . So that when each animation ends the properties are identical to when it began.
The animation is also set to cycle/repeat every 3 seconds rather than every 1 second as per your original code. This is that each iteration of the animation should run and complete before being called again; so 3 blocks means it runs for 3s. Each block having 1second as per your delay values in each blocks own class CSS code.
I have removed the wait animation because it simply didn't do anything. If you want an animation to wait there are various ways of doing this, not least with keyframes and animation-delay.
#keyframes show {
from {
z-index: -100;
}
50% {
z-index: 100;
}
to {
z-index: -100;
}
}
.block {
position: absolute;
z-index: -100;
width: 100px;
height: 100px;
border: 1px solid black;
animation: 3s show infinite;
}
.block-a {
background-color: red;
animation-delay: 0s;
}
.block-b {
background-color: purple;
animation-delay: 1s;
}
.block-c {
background-color: yellow;
animation-delay: 2s;
}
<div class="container">
<div class="block block-a">1</div>
<div class="block block-b">2</div>
<div class="block block-c">3</div>
</div>
Using the #keyframes in CSS I can get animations where the properties are changed gradually over the animation-duration. But I want something to change the properties instantly. So that throughout 0% to 25% property of a tag would be one and then it would instantly change, not gradually. How do I do that?
.move-me {
display: inline-block;
padding: 20px;
color: white;
position: relative;
margin: 0 0 10px 0;
}
.move-me-1 {
animation: move-in-steps 8s steps(4) infinite;
}
.move-me-2 {
animation: move-in-steps 8s steps(4, start) infinite;
}
.move-me-3 {
animation: move-in-steps 8s infinite;
}
body {
padding: 20px;
}
#keyframes move-in-steps {
0% {
left: 0;
background: blue;
}
100% {
left: 100%;
background: red;
}
}
<div class="move-me move-me-1">steps(4, end)</div>
<br>
<div class="move-me move-me-2">steps(4, start)</div>
<br>
<div class="move-me move-me-3">no steps</div>
what you need might be steps() in css animation
The code snippet I refer from this page
https://css-tricks.com/using-multi-step-animations-transitions/
I'm trying to make a pure css top to bottom infinite photo banner (without any margins) with ability to use scrsets for larger displays and zooming (css background url is not an option for this case).
I can't figure it out how to calculate all the numbers that is necessary for the animation, can someone explain it to me, please?
1.1. What do I have to change if I add more images to the div?
The first frame is not moving (second frame suddenly "eats" the first one), why is it happening and how to fix it?
What am I doing wrong?
This is what I'm done so far:
#container {
width: auto;
height: auto;
overflow: hidden;
background: white;
margin: 0;
}
.photobanner {
height: 466px;
width: 350px;
margin-bottom: 0;
background-color: blue;
}
.photobanner img{
display: block;
}
.first {
-webkit-animation: bannermove 30s linear infinite;
-moz-animation: bannermove 30s linear infinite;
-ms-animation: bannermove 30s linear infinite;
-o-animation: bannermove 30s linear infinite;
animation: bannermove 30s linear infinite;
}
#keyframes "bannermove" {
0% {
margin-bottom: 0px;
}
100% {
margin-bottom: -466px;
}
}
#-moz-keyframes bannermove {
0% {
margin-bottom: 0px;
}
100% {
margin-bottom: -466px;
}
}
#-webkit-keyframes "bannermove" {
0% {
margin-bottom: 0px;
}
100% {
margin-bottom: -466px;
}
}
#-ms-keyframes "bannermove" {
0% {
margin-bottom: 0px;
}
100% {
margin-bottom: -466px;
}
}
#-o-keyframes "bannermove" {
0% {
margin-bottom: 0px;
}
100% {
margin-bottom: -466px;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<div id="container">
<!-- Each image is 350px by 233px -->
<div class="photobanner">
<img class="first" src="https://dummyimage.com/350x233/000/fff.png&text=1" alt="" />
<img src="https://dummyimage.com/350x233/000/fff.png&text=1" alt="" />
<img src="https://dummyimage.com/350x233/000/fff.png&text=2" alt="" />
<img src="https://dummyimage.com/350x233/000/fff.png&text=1" alt="" />
</div>
</div>
</body>
</html>
Take a look at this example I have created. I am using 3 separate images.
For this to work, I used images which are all of the same size.
Each image is 350 x 150 so from that I can determine the height/width ratio to be 0.4285
The ratio value can be used as padding to specify the height of the carousel - This trick can be used to create a responsive carousel:
.carousel {
height: 0;
overflow: hidden;
padding-bottom: 43%;
}
This will allow the carousel to scale in proportion with the images.
Since we want the carousel to be infinite scrolling, it needs to have a duplicate of the first slide at the bottom. This will allow the animation to continue seamlessly.
The animation itself is manipulating the transform value between 0% and 75%. I am using 75 here because there are a total of 4 images in the carousel and we want the animation to loop at the 3rd quarter of the progression.
If we have 3 images, we would need to change this value to 66.66%
I am trying to achieve a CSS only slider.
When hovering left and right arrows, the slider has to slide. Of course.
I tried something using animation-play-state, animation-fill-mode (to keep the positions) and animation-direction but I'm not able to fully make it work.
Starting with animation-play-state: paused, hovering the arrows changes it to running.
On hover of the right arrow, everything is fine. We can hover, leave, hover again.
But, as soon as I hover the left arrow (that changes the animation-direction to reverse), it's broken.
Simplified snippet:
.wrapper {
overflow: hidden;
position: relative;
width: 500px;
}
.arrows {
z-index: 2;
position: absolute;
top: 0;
height: 100%;
background: #ddd;
opacity: 0.66;
}
.arrows:hover {
opacity: 1;
}
.arrow-l {
left: 0;
}
.arrow-r {
right: 0;
}
.sliding {
height: 160px;
width: 2000px;
background: linear-gradient(to bottom right, transparent 49.9%, gray 50.1%);
animation: slide 2s linear;
animation-play-state: paused;
animation-fill-mode: both;
}
.arrows:hover~.sliding {
animation-play-state: running;
}
.arrow-l:hover~.sliding {
animation-direction: reverse;
}
#keyframes slide {
0% {
transform: translate(0px, 0);
}
100% {
transform: translate(-1500px, 0);
}
}
<div class="wrapper">
<div class="arrows arrow-l">[ ← ]</div>
<div class="arrows arrow-r">[ → ]</div>
<div class="sliding"></div>
</div>
Can someone help me understand what is happening, and correct this unwanted behaviour?
The main issue here is that changing the direction will keep the current state of the animation BUT it will consider the new direction. Let's take an easy example:
Suppose you have an animation from left:0 to left:100%. If you first run the animation untill left:80% and then you change the direction to reverse you will have left:20%!
Why?
Because with the default direction you reached the 80% (left:80%) of the animation and 80% of the same animation with reverse direction is simply left:20%.
Hover on reverse and you will see that the position of the box is jumping to switch to the new state considering the new direction. It's obvious when the animation ends and you will be switching between the first and last state:
.sliding {
width:100px;
height:100px;
background:red;
left:0%;
position:relative;
animation:slide 5s linear forwards;
animation-play-state:paused;
}
.arrows {
margin:20px;
}
.arrow-r:hover~.sliding {
animation-play-state: running;
}
.arrow-l:hover~.sliding {
animation-direction: reverse;
}
#keyframes slide {
0% {
left: 0%;
}
100% {
left: 100%;
}
}
<div class="wrapper">
<div class="arrows arrow-r">move normal</div>
<div class="arrows arrow-l">reverse !!</div>
<div class="sliding"></div>
</div>
There is no fix for this since it's the default behavior of animation, but instead you can rely on transition to obtain a similar effect. The trick is to play with the duration that you increase/decrease to create the needed effect.
Here is an idea:
.wrapper {
overflow: hidden;
position: relative;
width: 500px;
}
.arrows {
z-index: 2;
position: absolute;
top: 0;
height: 100%;
background: #ddd;
opacity: 0.66;
}
.arrows:hover {
opacity: 1;
}
.arrow-l {
left: 0;
}
.arrow-r {
right: 0;
}
.sliding {
height: 160px;
width: 2000px;
background: linear-gradient(to bottom right, transparent 49.9%, gray 50.1%);
transition:all 2000s linear; /*This will block the current state*/
}
.arrow-r:hover ~ .sliding {
transform: translate(-1500px, 0);
transition:all 2s;
}
.arrow-l:hover ~ .sliding {
transform: translate(0px, 0);
transition:all 2s;
}
<div class="wrapper">
<div class="arrows arrow-l">[ ← ]</div>
<div class="arrows arrow-r">[ → ]</div>
<div class="sliding"></div>
</div>
On my element, I have a CSS animation running as long as it has a certain class (wiggle), and a transition as soon as it has a different one (right):
<div class="outer">
<div class="inner wiggle"></div>
</div>
#keyframes wiggle {
from {
left: 10%;
}
50% {
left: 30%;
}
to {
left: 10%;
}
}
.inner {
left: 0;
&.wiggle {
animation: wiggle 2s infinite;
}
&.right {
left: 90%;
transition: left 2s;
}
}
Now, if remove the wiggle class and add right at the same time, the transition doesn't play out; left: 90% applies immediately. However, if there's a delay between removing the former and adding the latter, the transition will happen as expected.
Here's a JSFiddle illustrating the issue.
It looks like when coming from an animation, values (such as left in this case) don't have an explicit value to transition from, so they're just rendered to their final state.
Is this expected behavior, i.e. is it part of a specification? Or are browsers free how to handle that case?
I've tested on the lastest versions of Firefox and Chromium.
Clarification: I'm not mainly looking for workarounds, especially not complicated ones, but more for a reason why exactly browsers behave like they do.
I think this may be a bug in browser rendering or so, but If you want a solution I can give you one alternative method with transform
A working fiddle for you:
$('#toggle').click(() => {
$('.inner').removeClass('wiggle').addClass('right');
});
#keyframes wiggle {
from {
left: 10%;
}
50% {
left: 30%;
}
to {
left: 10%;
}
}
.outer {
height: 5em;
background-color: black;
position: relative;
}
.inner {
height: 100%;
width: 10%;
position: absolute;
transform: translate(0%);
background-color: green;
transition: transform 2s ease-in-out;
}
.inner.wiggle {
animation: wiggle 2s infinite;
}
.inner.right {
transform: translate(900%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>
Animated
</h2>
<div class="outer">
<div class="inner wiggle"></div>
</div>
<h2>
Not animated
</h2>
<div class="outer">
<div class="inner"></div>
</div>
<hr>
<button id="toggle">
move right
</button>
I hope this was helpful for you.
Its look it is the expected behavior. I think when you are adding the right class with left:90%, its not able to pick the starting value for the left css property. As an alternate you can create another keyframe for the .right class
$('#toggle').click(() => {
$('.inner').removeClass('wiggle').addClass('right');
});
#keyframes wiggle {
0% {
left: 10%;
}
50% {
left: 30%;
}
100% {
left: 10%;
}
}
#keyframes right {
100% {
left: 90%;
}
}
.outer {
height: 5em;
background-color: black;
position: relative;
}
.inner {
height: 100%;
width: 10%;
position: absolute;
left: 0;
background-color: green;
transition: left 2s;
}
.wiggle {
animation: wiggle 2s infinite;
}
.right {
animation: right 2s forwards;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>
Animated
</h2>
<div class="outer">
<div class="inner wiggle"></div>
</div>
<h2>
Not animated
</h2>
<div class="outer">
<div class="inner"></div>
</div>
<hr>
<button id="toggle">
move right
</button>
This workaround might help you, the idea is to use the css variables, the idea is to set the animation with an alternate function, so in this way we will only need From and To... on the other hand we need to set up and event for every iteration, in that way we know when an iteration ends,
So when we click the button you can change the variable value and remove the class...
$('#toggle').click(() => {
$('.inner').addClass('right');
});
let flag = false;
$(".inner").on("animationiteration webkitAnimationIteration oAnimationIteration MSAnimationIteration", function(){
flag && $(".inner").removeClass('wiggle');
if($(".inner").hasClass('right')) flag = true;
});
:root {
--from: 10%;
--to: 30%;
}
#keyframes wiggle {
from {
left: var(--from);
}
to {
left: var(--to);
}
}
.outer {
height: 5em;
background-color: black;
position: relative;
}
.inner {
height: 100%;
width: 10%;
position: absolute;
transform: translate(0%);
background-color: green;
transition: transform 2s ease-in-out;
left:90%;
}
.inner.wiggle {
left:10%;
animation: wiggle 1s infinite;
animation-direction: alternate;
}
.inner.right {
--to:90%;
animation-direction: normal;
animation-duration:2s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>
Animated
</h2>
<div class="outer">
<div class="inner wiggle"></div>
</div>
<hr>
<button id="toggle">
move right
</button>
Consider that this has a bug when the animation is moving back to the start point...