how to revese a css-animation after trigger it? - javascript

Good evening, I'm a beginner front-end developer who is trying to implement sketches of Pinterest for training.
I've found this gif for the signup/login page but I have a major issue for implementing animation, I don't have any idea for reversing the animation when the user clicks on the signup button can anybody tell me how can I reverse an animation?
function animation() {
var element = document.getElementById("containerForm")
element.classList.add("slide")
}
.containerForm {
width:50px;height:50px;background-color:red;
}
.slide {
animation: slide 2s ease-in-out;
position: relative;
animation-fill-mode: forwards;
}
#keyframes slide {
0% {
transform: translateX(0);
}
100% {
transform: translateX(100%);
overflow: hidden;
visibility: visible;
}
}
<div class="containerForm" id="containerForm">
<form></form>
</div>
<button onclick="animation()">click</button>
but as I've said I don't have an idea for the second step
Link of gif

you can add another css class and make use of the animation-direction property.
ie
.slide-back{
animation: slide 2s ease-in-out;
position: relative;
animation-direction: reverse;
}

function animation() {
var element = document.getElementById("containerForm")
element.classList.add("slide")
}
function reverse() {
var element = document.getElementById("containerForm")
element.classList.remove("slide")
}
.containerForm {
width:50px;
height:50px;
background-color:red;
transform: translateX(0);
transition: transform 2s;
}
.slide {
transform: translateX(100%);
}
<div class="containerForm" id="containerForm">
<form></form>
</div>
<button onclick="animation()">click</button>
<button onclick="reverse()">click</button>

transition works too:
example:
*{margin:0;}
#tst {
display: grid;
grid-template-columns: repeat(2, 1fr);
min-height: 100vh;
background: #555;
}
label {
margin: auto;
appearance: button;
cursor: pointer;
min-width: 6em;
text-align: center;
}
#a,
#b {/*hides radios */
position: absolute;
right: 100vw;
}
[for="a"],
#c {
grid-row: 1;
grid-column: 1;
}
#c {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto 1fr;
background: white;
border: solid;
transition: 0.5s;
font-size:2vw;
}
#a:checked~#c {
transform: translatex(0)
}
#b:checked~#c {
transform: translatex(100%)
}
h1 {
margin: auto;
}
#c p[class] {
margin: auto;
grid-column: 1;
grid-row: 2;
transition: 0.25s;
background: inherit;
color: #164fb7;
font-size: 3vw;
}
#c p.b {
opacity: 0;
color: tomato;
}
#b:checked~#c p.b {
opacity: 1
}
/* there were no js nor animation nor absolute positionning ;) */
<div id="tst">
<input id="a" type=radio name=toggle>
<input id="b" type=radio name=toggle>
<label for="a">Left</label>
<label for="b">Right</label>
<div id="c">
<h1>here or there ?</h1>
<p class="a">Standing on the left</p>
<p class="b">Standing on the right</p>
</div>
</div>

Instead of adding a class I suggest using the animation-play-state property and adding event listeners:
one click listener to the button
one animationiteration to the div
simply change the play state from paused to running
Let me show you what I mean:
const element = document.getElementById("containerForm");
const btn = document.querySelector("button");
function animation() {
element.style.animationPlayState = "running";
}
function stopAnimation() {
element.style.animationPlayState = "paused";
}
btn.addEventListener("click", animation);
element.addEventListener("animationiteration", stopAnimation);
.containerForm {
width: 50px;
height: 50px;
background-color: red;
animation: slide 2s ease-in-out infinite alternate paused;
}
#keyframes slide {
0% {
transform: translateX(0);
}
100% {
transform: translateX(100%);
}
<div class="containerForm" id="containerForm">
<form></form>
</div>
<button>click</button>

Related

Scroll to CSS keyframe animation using JavaScript

I am trying to scroll animate a logo using CSS keyframes.
I want the animation to scroll to each keyframe whenever a button click is triggered.
Based on the scroll value from JS, I have added the keyframes. I want to scroll when the button is clicked and stop when the scroll value is like 0.200000, then continue to scroll to 0.400000.
<div class="animate-container">
<a class="service" href="#service">Service</a>
<div class="animate-logo">
<img src="google.png" />
</div>
</div>
html {
scroll-behavior: smooth;
}
body {
min-height: 1000vh;
}
.animate-container {
width: 100%;
height: auto;
}
.animate-logo {
display: flex;
justify-content: space-around;
align-items: center;
}
.animate-logo>img {
width: 250px;
position: fixed;
top: 50%;
/* left: 50%; */
/* margin-top: -50px;
margin-left: -50px; */
animation: standard 1s ease-out infinite;
animation-play-state: paused;
animation-delay: calc(var(--scroll) * -1s);
animation-iteration-count: 1;
animation-fill-mode: both;
}
#keyframes standard {
0% {
transform: rotate(-360deg);
}
20% {
transform: rotate(360deg) translateX(-200%) ;
}
50% {
transform: translateX(200%);
}
60% {
transform: translateY(-200%);
}
80% {
transform: translateX(-200%) rotate(-360deg);
}
100% {
transform: translateX(-200%);
}
}
window.addEventListener(
"scroll",
() => {
document.body.style.setProperty(
"--scroll",
window.pageYOffset / (document.body.offsetHeight - window.innerHeight)
);
},
false
);

how to make script load after onload

I am trying to make my progress bar load (animate) after the onload loader animation has finished, here is a link to an example of the progress bars animating normally: JSFiddle
& here is an example with the loader onload added: JSFiddle you can see how the progress bar animation doesn't function properly in this example.
Originally I thought the progress bar animation was happening behind the onload loader but if I lower the seconds for the loader I can see the progress bar animation doesn't function at all
Any help is appreciated thanks!
You are triggering the load bar animation on page load, whereas you need to move the trigger to run after your loading animation finishes.
let $radios
const radioChange = () => {
let progress_value = 0
$radios.filter(':checked').each( function() {
progress_value += Number($(this).data('progress'))
})
console.log(progress_value)
$(".progress-value").width(progress_value + '%')
}
$(document).ready(function() {
$radios = $('input[type="radio"]')
$radios.change(radioChange);
})
var myVar;
function myFunction() {
myVar = setTimeout(showPage, 500);
}
function showPage() {
document.getElementById("loader").style.display = "none";
document.getElementById("myDiv").style.display = "block";
setTimeout( () => $radios.first().change(), 20 )
}
.progress {
background: rgba(255, 255, 255, 0.1);
justify-content: flex-start;
border-radius: 100px;
align-items: center;
position: relative;
display: flex;
height: 10px;
width: 100%;
margin-bottom: 10px;
}
.progress-value {
box-shadow: 0 10px 40px -10px #fff;
border-radius: 100px;
background: #0d6efd;
height: 30px;
width: 0;
transition: width 2s;
}
/* Center the loader */
#loader {
position: absolute;
left: 47%;
top: 44%;
z-index: 1;
width: 120px;
height: 120px;
border: 16px solid #333;
border-radius: 50%;
border-top: 16px solid #3498db;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
#media(max-width:768px){
#loader{
left:35% !important;
top:40% !important;
}
}
#-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
#keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Add animation to "page content" */
.animate-bottom {
position: relative;
-webkit-animation-name: animatebottom;
-webkit-animation-duration: 1s;
animation-name: animatebottom;
animation-duration: 1s
}
#-webkit-keyframes animatebottom {
from { bottom:-100px; opacity:0 }
to { bottom:0px; opacity:1 }
}
#keyframes animatebottom {
from{ bottom:-100px; opacity:0 }
to{ bottom:0; opacity:1 }
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/js/bootstrap.bundle.min.js"></script>
<body onload="myFunction()" style="margin:0;">
<div id="loader"></div>
<div class="whole animate-bottom" id="myDiv" style="display:none;">
<div class="wrappy">
<br><br>
<div class="progress">
<div class="progress-value"></div>
</div>
</div>
<div class="row">
<div class="col-6">
<input type="radio" style="display:none;" id="js1" data-price="146.99" value="option1a" name="ONE" data-progress="50" checked>
<label for="js1" onclick="">
Option 1a (Default 50%)
</label>
</div>
<div class="col-6">
<input type="radio" style="display:none;" id="js2" data-price="123.99" value="option2a" name="ONE" data-progress="75">
<label for="js2" onclick="">
Option 2a (75%)
</label>
</div>
</div>
</div>
</body>

Vue transition within a transition ending the transition in the wrong place

I am trying to add a transition to a child div within another 'parent' div with its own transition, however there seems to be an issue with the child transition.
What appears to be happening is the child transition is getting confused with the parent transition and ending the transition in the wrong place.
The effect I am trying to get is when the button is clicked the Child Container A (in view) slides out left and Child Container B slides into view after Child Container A from the right.
I have replicated the issue here: https://codepen.io/BONDJAMES/pen/mdegmMe
How do I slide Child Container A out left, with Child Container B sliding into view after Child Container A, from the right, after a toggle?
HTML
<div id="app">
<div class="viewBlocks">
<transition name="slide">
<div class="left" v-if="!MaxView">
<div class="subContainer">
<div class="container">
...
</div>
</div>
</div>
</transition>
<transition name="slide">
<div class="right">
<div class="subContainer">
<button #click="toggleBtn">Toggle</button>
Parent DIV
<div class="container">
<transition name="first-slide">
<div v-if="!showMiniB" class="miniContainerA">
<button #click="slideDivs">Slide A out - B In</button>
Child Container A
</div>
</transition>
<transition name="second-slide">
<div v-if="showMiniB" class="miniContainerB">
<button #click="slideDivs">Slide B out - A</button>
Child Container B
</div>
</transition>
</div>
</div>
</div>
</transition>
</div>
</div>
CSS
body {
margin: 0;
}
* {
box-sizing: border-box;
}
.viewBlocks {
display: flex;
}
.viewBlocks > * {
flex: 1 1 0%;
overflow: hidden;
}
.viewBlocks .subContainer {
margin: 10px;
background-color: white;
min-height: 200px;
padding: 1rem;
/* prevent text wrapping during transition? */
min-width: 300px;
}
.viewBlocks .left {
background-color: blue;
}
.viewBlocks .right {
background-color: red;
}
.viewBlocks .container {
background-color: white;
}
.slide-leave-active, .slide-enter-active {
transition: 1s cubic-bezier(0.5, 0, 0.3, 1);
}
.slide-leave-to, .slide-enter {
flex-grow: 0;
}
.miniContainerA{
border: green 3px solid;
text-align: center;
height: 60px
}
.miniContainerB{
border: pink 3px solid;
text-align: center;
height: 60px
}
.first-slide-enter {
opacity: 0;
transform: translatex(-100%);
transition: all 0.7s ease-out;
}
.first-slide-enter-to {
opacity: 1;
transform: translatex(0);
transition: all 0.7s ease-out;
}
.first-slide-leave-to {
opacity: 0;
transform: translatex(-100%);
transition: all 0.7s ease-out;
}
.second-slide-enter {
opacity: 0;
transform: translatex(0);
transition: all 0.7s ease-out;
}
.second-slide-enter-to {
opacity: 1;
transform: translatex(-100%);
transition: all 0.7s ease-out;
}
.second-slide-leave-to {
opacity: 0;
transform: translatex(0);
transition: all 0.7s ease-out;
}
.second-slide-leave {
transform: translatex(-100%);
}
VUE
var app = new Vue({
el: '#app',
data: () => ({
MaxView: false,
showMiniB: false
}),
methods: {
toggleBtn(){
this.MaxView = !this.MaxView
},
slideDivs(){
this.showMiniB = !this.showMiniB
}
}
})
It's just a matter of adjusting the css a bit
for miniContainerA and miniContainerB (using just div in example below) you need to anchor to the top. You can do this by positioning the parent as absolute, and the children (miniContainers) relative
.viewBlocks .container {
background-color: white;
position: relative;
top: 0;
}
.viewBlocks .container div{
background-color: yellow;
position: absolute;
top: 0;
left:0;
width:100%;
}
then adjust your transition percentage (added 100% to your translatex values)
.second-slide-enter {
opacity: 0;
transform: translatex(100%);
transition: all 0.7s ease-out;
}
.second-slide-enter-to {
opacity: 1;
transform: translatex(0%);
transition: all 0.7s ease-out;
}
.second-slide-leave-to {
opacity: 0;
transform: translatex(100%);
transition: all 0.7s ease-out;
}
.second-slide-leave {
transform: translatex(0%);
}

Load each progress bar from 0 to its value in multiple progress bar animation

I am trying to add animation in grouped progress bar that will load each progress bar from 0 to its value. e.g in my sample code below I want to first load red progress bar then load the green progress bar. How can I do that?
Please check the code in this jsfiddle.
html:
<div class="progress-bar-outer">
<div class="progress-bar-inner">
</div>
<div class="progress-bar-inner2">
</div>
</div>
css:
.progress-bar-outer {
width: 300px;
height: 40px;
flex: auto;
display: flex;
flex-direction: row;
border-radius: 0.5em;
overflow: hidden;
background-color: gray;
}
.progress-bar-inner {
/* You can change the `width` to change the amount of progress. */
width: 75%;
height: 100%;
background-color: red;
}
.progress-bar-inner2 {
/* You can change the `width` to change the amount of progress. */
width: 50%;
height: 100%;
background-color: green;
}
.progress-bar-outer div {
animation:loadbar 3s;
-webkit-animation:loadbar 3s;
}
#keyframes loadbar {
0% {width: 0%;left:0;right:0}
}
I would transition transform instead for better performance. Use translateX(-100%) with opacity: 0 to move them to their default, hidden position, then animate to translateX(0); opacity: 1; to put them in place. And just add an animation-delay to the green bar that matches the animation-duration
I made the bars semi-opaque to show when the animations fire.
.progress-bar-outer {
width: 300px;
height: 40px;
border-radius: 0.5em;
overflow: hidden;
background-color: gray;
display: flex;
}
.progress-bar-inner {
/* You can change the `width` to change the amount of progress. */
width: 75%;
background-color: red;
}
.progress-bar-inner2 {
/* You can change the `width` to change the amount of progress. */
width: 100%;
background-color: green;
}
.progress-bar-outer div {
transform: translateX(-100%);
animation: loadbar 3s forwards;
-webkit-animation: loadbar 3s forwards;
opacity: 0;
}
.progress-bar-outer .progress-bar-inner2 {
animation-delay: 3s;
}
#keyframes loadbar {
0% {
opacity: 1;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress -->
<div class="progress-bar-outer">
<div class="progress-bar-inner">
</div>
<div class="progress-bar-inner2">
</div>
</div>
Modified Michael Coker's answer to better reflect my interpretation of what you're asking for.
.progress-bar-outer {
width: 300px;
height: 40px;
border-radius: 0.5em;
overflow: hidden;
background-color: gray;
position: relative;
}
.progress-bar-inner {
/* You can change the `width` to change the amount of progress. */
width: 100%;
background-color: red;
z-index: 1;
}
.progress-bar-inner2 {
/* You can change the `width` to change the amount of progress. */
width: 100%;
background-color: green;
z-index: 2;
}
.progress-bar-outer div {
position: absolute;
top: 0; bottom: 0;
transform: translateX(-100%);
animation: loadbar 3s linear;
-webkit-animation: loadbar 3s linear;
opacity: 1;
}
.progress-bar-outer .progress-bar-inner2 {
animation-delay: 3s;
}
#keyframes loadbar {
100% {
transform: translateX(0);
}
}
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress -->
<div class="progress-bar-outer">
<div class="progress-bar-inner">
</div>
<div class="progress-bar-inner2">
</div>
</div>
Apply Transition to inner classes, add delays to secondary inner and use opacity to hide the element before transition begins.
.progress-bar-inner {
animation:loadbar 2s;
-webkit-animation:loadbar 2s;
}
.progress-bar-inner2 {
-webkit-animation: loadbar 2s ease 2s forwards;
animation: loadbar 2s ease 2s forwards
animation-delay: 2s;
-webkit-animation-delay: 2s;
opacity:0;
}
#keyframes loadbar {
0% { width: 0%;left:0;right:0}
1% { opacity: 1}
100% { opacity: 1}
}
See working example:
https://jsfiddle.net/dfkLexuv/10/

Div remains on the screen after animation

I'm building an app for Android in HTML. I made the NavigationDrawer in HTML, and with javascript I make it to show on button click, and dissapear on <p> click. I'm using keyframes for the animations. When I press the button, the animation works (I am using -webkit-transform: translateX), and when I click the button again, the animation works but the div doesn't hide. It remains on the screen, but I can click through it (like pointer-events: none;). What's the problem?
CSS:
#-webkit-keyframes sMenuClose {
from {
-webkit-transform: translateX(0%);
}
to {
-webkit-transform: translateX(-100%);
}
}
#-webkit-keyframes sMenuOpen {
from {
-webkit-transform: translateX(-100%);
}
to {
-webkit-transform: translateX(0%);
}
}
.slidemenu {
background: transparent;
height: 100%;
left: 0px;
pointer-events: none;
position: fixed;
top: 0px;
width: 100%;
z-index: 9991;
}
.slidemenu .menu {
background: #FFF;
border-right: 1px solid #000;
color: #333;
height: 100%;
overflow: visible;
pointer-events: visible;
position: absolute;
top: 0px;
-webkit-transform: translateX(-100%);
width: 80%;
}
.slidemenu .menu.hidden {
-webkit-animation-name: sMenuClose;
-webkit-animation-duration: 0.6s;
-webkit-animation-timing-function: ease;
-webkit-animation-delay: 0s;
-webkit-animation-iteration-count: 1;
-webkit-animation-direction: normal;
-webkit-animation-fill-mode: forwards;
-webkit-animation-play-state: running;
}
.slidemenu .menu.visible {
-webkit-animation-name: sMenuOpen;
-webkit-animation-duration: 0.6s;
-webkit-animation-timing-function: ease;
-webkit-animation-delay: 0s;
-webkit-animation-iteration-count: 1;
-webkit-animation-direction: normal;
-webkit-animation-fill-mode: forwards;
-webkit-animation-play-state: running;
}
HTML:
<html>
<head>
...
</head>
<body>
...
<div class="slidemenu">
<div class="menu">
<p>Some text</p>
</div>
</div>
</body>
</html>
JS:
window.onload = function() {
document.querySelector("body div#actionbar div.action ul li.menu a").addEventListener("click", function(e) {
e.preventDefault();
if(document.querySelector("body div.slidemenu div.menu").classList.contains("hidden"))
{
document.querySelector("body div.slidemenu div.menu").classList.remove("hidden");
}
document.querySelector("body div.slidemenu div.menu").classList.add("visible");
});
document.querySelector("p").addEventListener("click", function(e) {
e.preventDefault();
document.querySelector("body div.slidemenu div.menu").classList.remove("visible");
document.querySelector("body div.slidemenu div.menu").classList.add("hidden");
});
};
Can you help me?
I think you can get the effect you are after with a slightly simpler setup. This example is modified slightly to show a demo here but I think you should be able to convert this button back into your li menu item with ease. I made the slideout a light blue just so it is easier to see here as well.
function slideMenu_Toggle(){
var _selector = "body div.slidemenu div.menu";
document.querySelector(_selector).classList.toggle("visible");
}
window.onload = function() {
var _selector = ".slidemenu .menu";
document.querySelector(_selector).addEventListener("click", function(){
if( this.classList.contains("visible") ) { slideMenu_Toggle(); }
});
document.querySelector("#toggle").addEventListener("click", slideMenu_Toggle);
};
.slidemenu {
background: transparent;
height: 100%;
left: 0px;
pointer-events: none;
position: fixed;
top: 0px;
width: 100%;
z-index: 9991;
}
.slidemenu .menu {
border-right: 1px solid #000;
color: #333;
height: 100%;
overflow: visible;
position: absolute;
top: 0px;
width: 80%;
pointer-events: visible;
background: aliceblue;
-webkit-transition: transform .5s ease;
-webkit-transform: translateX(-100%);
}
.slidemenu .menu.visible {
-webkit-transform: translateX(0%);
}
<div style="text-align: right; margin-top: 3em;">
<button id="toggle" style="font-size: 2em;">toggle</button>
</div>
<div class="slidemenu">
<div class="menu">
<p>Some text</p>
</div>
</div>
Here is a workaround
<script language="JavaScript">
var TheDivParentContents
self.window.onload=getDivContents
function getDivContents(){
TheDivParentContents=document.getElementById("TheDivParent").innerHTML;
}
function OnClickHideDiv(){
document.getElementById("TheDivParent").innerHTML="";
}
function OnClickShowDiv(){
document.getElementById("TheDivParent").innerHTML=TheDivParentContents;
}
</script>
<body bgcolor="white">
<input script=JavaScript type=button onclick="OnClickShowDiv()" value="Show Div">
<input script=JavaScript type=button onclick="OnClickHideDiv()" value="Hide Div">
<span id=TheDivParent>
<div>
some text
</div>
</span>
</body>
Note that i place the div that i want to hide inside a Span tag. and that span tag will be used by the functions in the script to save the innerhtml of the div to a global variable.. Hope this works for you.

Categories

Resources