so I have a simple side bar that I want to slide in and out using css animation, now the slide animation in is working the problem that I am facing is making the animation for the slideout to work.
Can I please get help on that..
Html(Sidebar)
<div class="SideBarMenu" id="SideBarMenu">
<div class="sidebar-menu-header">
<h2 class="nav-bleft-companyname">
Sofast<span class="nav-bleft-periodmark">Cart.</span>
</h2>
</div>
<hr />
<h4 class="sidebar-menuLink">MenuItem1</h4>
<h4 class="sidebar-menuLink">MenuItem2</h4>
<h4 class="sidebar-menuLink">MenuItem3</h4>
<h4 class="sidebar-menuLink">MenuItem4</h4>
<h4 class="sidebar-menuLink">MenuItem5</h4>
</div>
JS Function triggered to toggle menu
const OpenMenu = () => {
const menu = document.getElementById("SideBarMenu");
if (menu.style.display === "block") {
menu.classList.add("sidebar-closed");
menu.style.animation = "slideOut 0.4s backwards";
menu.style.display = "none";
} else {
menu.style.display = "block";
menu.style.animation = "slideIn 0.4s forwards";
menu.classList.remove("sidebar-closed");
}
};
Side Bar css
.SideBarMenu {
top: 0% !important;
z-index: 999;
position: fixed;
background-color: #333333;
height: 100vh;
color: white;
width: 20%;
transform: translateX(-350px);
padding: 2rem;
}
.sidebar-menuLink {
margin-top: 1rem;
}
#keyframes slideIn {
100% {
transform: translateX(0px);
}
}
#keyframes slideOut {
100% {
transform: translateX(-350px);
}
}
You can use css transition to achieve that. I also advise you to put all your styles in css classes, you don't need to apply the styles in javascript.
const animate = () => {
const elem = document.getElementById("my-elem");
if (!elem.classList.contains('elem-out')) {
elem.classList.add("elem-out");
} else {
elem.classList.remove("elem-out");
}
};
const btn = document.getElementById("my-btn");
btn.addEventListener("click", animate)
.elem {
width: 300px;
height: 50px;
background-color: red;
margin-bottom: 10px;
}
.elem:not(.elem-out) {
transition: transform 0.4s ease-in;
transform: translateX(0px);
}
.elem-out {
transition: transform 0.4s ease-out;
transform: translateX(-350px);
}
<div id="my-elem" class="elem"></div>
<button id="my-btn">toggle animate</button>
Do not change the display property, the transition will brake. There's no transition for propperty like display, if you want a fadeIn / fadeOut effect too, you can put a transition on opacity property
Related
I am trying to trigger two different animations by adding and removing two different css classes with two different css animations by using javascript to do so. However, the div does not preserve the previous animated state, and I need it to do so because of how I designed the UI. I am using forwards in the animations property, but the div performs the animation when it is clicked and then goes back to previous state and then performs the other animation.
const projects = document.getElementById('projects')
projects.addEventListener('click', () => {
if(projects.classList.contains('projects-animation') == true){
projects.classList.remove('projects-animation')
projects.classList.add('projects-animation2')
}
else{
console.log('animation2')
console.log(projects.classList)
projects.classList.remove('projects-animation2')
projects.classList.add('projects-animation')
}
})
.projects-container{
position: relative;
z-index: 1;
display: flex;
align-items: center;
grid-area: projects;
padding: 20px;
font-size: 100px;
background-color: hsl(4, 7%, 45%);
cursor: pointer;
}
.projects{
position: relative;
height: fit-content;
}
.projects-animation{
animation: projects 1s ease-in-out backwards;
}
.projects-animation2{
animation: projects2 1s ease-in-out backwards;
}
#keyframes projects {
100%{
transform: translate(50%,-250%);
}
}
#keyframes projects2 {
100%{
transform: translate(-50%, 250%);
}
}
<div class="projects-container">
<div id = "projects" class="projects">Projects</div>
</div>
Please check this one,
1: You need to add 0% as starting point for the second animation,
2: I have used smaller value as larger value moving the child div out of view port, if you want to keep the values then make the parent div large or position it accordingly
const projects = document.getElementById('projects')
projects.addEventListener('click', () => {
if(projects.classList.contains('projects-animation') == true){
projects.classList.remove('projects-animation')
projects.classList.add('projects-animation2')
}
else{
console.log('animation2')
console.log(projects.classList)
projects.classList.remove('projects-animation2')
projects.classList.add('projects-animation')
}
})
.projects-container{
position: relative;
z-index: 1;
display: flex;
align-items: center;
grid-area: projects;
padding: 20px;
font-size: 100px;
background-color: hsl(4, 7%, 45%);
cursor: pointer;
}
.projects{
position: relative;
height: fit-content;
}
.projects-animation{
animation: projects 1s ease-in-out forwards;
}
.projects-animation2{
animation: projects2 1s ease-in-out forwards;
}
#keyframes projects {
100%{
transform: translate(10%,-10%);
}
}
#keyframes projects2 {
0%{
transform: translate(10%,-10%);
}
100%{
transform: translate(0%, 0%);
}
}
<div class="projects-container">
<div id = "projects" class="projects">Projects</div>
</div>
I created a simple HTML game, which disappears under the screen when I click on a moving box.
However, the animation that disappears starts at the original location, not where it was clicked.
I think 0% of the remove #keyframes should have the location of the click, but I couldn't find a way
How shall I do it?
(function () {
const charactersGroup = document.querySelectorAll('.character');
const stage = document.querySelector('.stage')
const clickHandler = (e) => {
const target = e.target;
if (target.classList.contains('character')) {
target.classList.remove(`f${target.dataset.id}`);
target.classList.add('f0');
target.classList.add('remove');
setTimeout(() => { stage.removeChild(target) }, 2000);
}
}
stage.addEventListener('click', clickHandler);
}());
.stage {
overflow: hidden;
position: relative;
background: #eeeeaa;
width: 40vw;
height: 20vw;
}
#keyframes moving {
0% {
transform: translateX(0);
}
100% {
transform: translateX(30vw);
}
}
#keyframes remove {
0% {
transform: translate(0);
}
100% {
transform: translateY(60vw);
}
}
.character {
position: absolute;
width: 50px;
height: 50px;
background-repeat: no-repeat;
background-position: 50% 50%;
background-size: contain;
animation: moving infinite alternate;
}
.remove {
animation: remove 0.2s cubic-bezier(.68,-0.55,.27,1.55) forwards;
}
.f0 {
background-color: black;
animation-duration: 2s;
}
.f1 {
left: 5%;
bottom: 5%;
animation-duration: 2s;
background-color: red;
}
<div class="stage">
<div class="character f1" data-id="1"></div>
</div>
Change the first animation to consider left instead of translate then append both of them to the element initially and you simply toggle the animation-play-state when adding the remove class
(function() {
const charactersGroup = document.querySelectorAll('.character');
const stage = document.querySelector('.stage')
const clickHandler = (e) => {
const target = e.target;
if (target.classList.contains('character')) {
target.classList.add('remove');
setTimeout(() => {
stage.removeChild(target)
}, 2000);
}
}
stage.addEventListener('click', clickHandler);
}());
.stage {
overflow: hidden;
position: relative;
background: #eeeeaa;
width: 40vw;
height: 20vw;
}
#keyframes moving {
100% {
left:calc(95% - 50px);
}
}
#keyframes remove {
50% {
transform: translateY(-30vh);
}
100% {
transform: translateY(60vw);
}
}
.character {
position: absolute;
width: 50px;
height: 50px;
background:red;
left: 5%;
bottom: 5%;
animation:
moving 2s infinite alternate,
remove 1s cubic-bezier(.68, -0.55, .27, 1.55) forwards paused;
}
.remove {
animation-play-state:paused,running;
background: black;
}
<div class="stage">
<div class="character f1" data-id="1"></div>
</div>
If your use case is to deal with a lot of such boxes and complexity, it's better to go with handling everything with pure JS but I tried to make this work with minimal changes in JS and CSS.
I have added comments to the new JS lines.
Also taken the liberty to have a separate class with name moving for animation moving so that we can remove it on click.
(function () {
const charactersGroup = document.querySelectorAll('.character');
const stage = document.querySelector('.stage')
const clickHandler = (e) => {
const target = e.target;
if (target.classList.contains('character')) {
target.classList.remove(`f${target.dataset.id}`);
target.classList.add('f0');
// remove the moving animation
target.classList.remove('moving');
// Get offsetWidth which is the half of width to substract later while calculating left for the target i.e our box.
const offsetWidth = parseInt(getComputedStyle(target).width)/2;
// e.clientX gives us the x coordinate of the mouse pointer
// target.getBoundingClientRect().left gives us left position of the bounding rectangle and acts as a good offset to get the accurate left for our box.
target.style.left = `${e.clientX -target.getBoundingClientRect().left - offsetWidth}px`;
target.classList.add('remove');
setTimeout(() => { stage.removeChild(target) }, 2000);
}
}
stage.addEventListener('click', clickHandler);
}());
.stage {
overflow: hidden;
position: relative;
background: #eeeeaa;
width: 40vw;
height: 20vw;
}
#keyframes moving {
0% {
transform: translateX(0);
}
100% {
transform: translateX(30vw);
}
}
#keyframes remove {
0% {
transform: translate(0vh);
}
100% {
transform: translateY(60vw);
}
}
.character {
position: absolute;
width: 50px;
height: 50px;
background-repeat: no-repeat;
background-position: 50% 50%;
background-size: contain;
}
.moving{
animation: moving infinite alternate;
}
.remove {
animation: remove 0.2s cubic-bezier(.68,-0.55,.27,1.55) forwards;
}
.f0 {
background-color: black;
animation-duration: 2s;
}
.f1 {
left: 5%;
bottom: 5%;
animation-duration: 2s;
background-color: red;
}
<div class="stage">
<div class="character moving f1" data-id="1"></div>
</div>
What is the best way to have an object scale and then perform a bounce animation at that scale factor before going back to the original scale factor. I realize I could do something like scaling it to 2.2, then 1.8, then 2.0, but I'm looking for a way where you just have to perform the bounce animation on the scale factor because my scale factor will change.
Here is my example. Basically I want to combine the two to work like I said but as you can see the bounce animation performs based off the image size prior to scaling.
I need all sides of the image to bounce equally, like the example.
function myFunction() {
var image = document.getElementById('test');
image.style.WebkitTransform = ('scale(2,2)');
image.classList.remove('bounce');
image.offsetWidth = image.offsetWidth;
image.classList.add('bounce') ;
}
div#test {
position:relative;
display: block;
width: 50px;
height: 50px;
background-color: blue;
margin: 50px auto;
transition-duration: 1s;
}
.bounce {
animation: bounce 450ms;
animation-timing-function: linear;
}
#keyframes bounce{
25%{transform: scale(1.15);}
50%{transform: scale(0.9);}
75%{transform: scale(1.1);}
100%{transform: scale(1.0);}
}
<div id='test'> </div>
<button class = 'butt' onclick = 'myFunction()'>FIRST</button>
You can try the use of CSS variable in order to make the scale factor dynamic within the keyframe:
function myFunction(id,s) {
var image = document.querySelectorAll('.test')[id];
image.style.setProperty("--s", s);
image.classList.remove('bounce');
image.offsetWidth = image.offsetWidth;
image.classList.add('bounce');
}
div.test {
display: inline-block;
width: 50px;
height: 50px;
background-color: blue;
margin: 50px;
transform:scale(var(--s,1));
}
.bounce {
animation: bounce 450ms;
animation-timing-function: linear;
}
#keyframes bounce {
25% {
transform: scale(calc(var(--s,1) + 0.2));
}
50% {
transform: scale(calc(var(--s,1) - 0.1));
}
75% {
transform: scale(calc(var(--s,1) + 0.1));
}
100% {
transform: scale(var(--s,1));
}
}
<div class='test'> </div>
<div class='test'> </div>
<div class='test'> </div>
<div>
<button class='butt' onclick='myFunction(0,"2")'>first</button>
<button class='butt' onclick='myFunction(1,"3")'>Second</button>
<button class='butt' onclick='myFunction(2,"0.5")'>third</button>
<button class='butt' onclick='myFunction(1,"1")'>second again</button>
</div>
Dispatch each transform on a different wrapping element.
This way you can achieve several level of transforms, all relative to their parent wrapper.
Then you just need to set your animation to fire after a delay equal to the transition's duration:
btn.onclick = e => {
// in order to have two directions, we need to be a bit verbose in here...
const test = document.querySelector('.test');
const classList = test.classList;
const state = classList.contains('zoomed-in');
// first remove previous
classList.remove('zoomed-' + (state ? 'in' : 'out'));
// force reflow
test.offsetWidth;
// set new one
classList.add('zoomed-' + (state ? 'out' : 'in'));
};
div.test {
position: relative;
display: inline-block;
margin: 50px 50px;
}
div.test div{
width: 100%;
height: 100%;
transition: transform 1s;
}
div.test.zoomed-in .scaler {
transform: scale(2);
}
div.test.zoomed-in .bouncer,
div.test.zoomed-out .bouncer {
animation: bounce .25s 1s;/* transition's duration delay */
}
div.test .inner {
background-color: blue;
width: 50px;
height: 50px;
}
#keyframes bounce {
0% {
transform: scale(1.15);
}
33% {
transform: scale(0.9);
}
66% {
transform: scale(1.1);
}
100% {
transform: scale(1.0);
}
}
<div class="test">
<div class="scaler">
<div class="bouncer">
<div class="inner"></div>
</div>
</div>
</div>
<button id="btn">toggle zoom</button>
I'm want to disable all css transitions using JavaScript. I added transition: none to the body (via JavaScript), but the elements in the body still have a transition.
Of course I can loop through all elements, and add transition = 'none';, but I'm sure there's a better way of temporary disabling the css transition of all elements. Here's a sample code:
JSFiddle
var sample = document.getElementById('sample');
sample.addEventListener('click', function() {
if (document.body.style.transition === 'none') {
document.body.style.transition = '';
} else {
document.body.style.transition = 'none';
}
})
#sample {
width: 200px;
height: 100px;
background: lawngreen;
transition: transform 500ms ease;
}
#sample:hover {
transform: translateX(50px);
}
<div id="sample">Hover over me to move
<br />Click to disable transition</div>
Add a new class name to the body or parent tag. Set transitions with the new parent selector .animated #sample:
<body class="animated">
<div id="sample"></div>
</body>
... and the styles:
#sample {
width: 200px;
height: 100px;
background: lawngreen;
}
.animated #sample {
transition: transform 500ms ease;
}
.animated #sample:hover {
transform: translateX(50px);
}
To disable animations of all children just remove the .animated class from the body or parent tag.
Modified fiddle: https://jsfiddle.net/xjxauu0h/1/
you'll want to use a class on body so you can turn it on and off.
var sample = document.getElementById('sample');
document.body.classList.add('transitioner');
sample.addEventListener('click', function() {
if (document.body.classList && document.body.classList.length) {
document.body.classList.remove('transitioner');
} else {
document.body.classList.add('transitioner');
}
console.log(document.body.classList);
})
#sample {
width: 200px;
height: 100px;
background: lawngreen;
}
.transitioner *{
transition: transform 500ms ease;
}
#sample:hover {
transform: translateX(50px);
}
<div id="sample">Hover over me to move
<br />Click to disable transition</div>
var sample = $('#sample');
var body = $('body');
sample.click(function() {
body.toggleClass('notransition notransform');
});
#sample {
width: 200px;
height: 100px;
background: lawngreen;
transition: transform 500ms ease;
}
#sample:hover {
transform: translateX(50px);
}
.notransition.notransform #sample {
background: HotPink;
}
.notransition * {
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
-ms-transition: none !important;
transition: none !important;
}
.notransform * {
-webkit-transform: none !important;
-moz-transform: none !important;
-o-transform: none !important;
-ms-transform: none !important;
transform: none !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="sample">Hover over me to move
<br />Click to disable transition</div>
I made this
http://codepen.io/adamchenwei/pen/dOvJNX
and I try to apply a certain way of moving for a dom so it move for a fixed distance and stop, instead of animate and move through the whole width of the dom. However, I don't really want to fix the distance inside the css keyframe because I need to detect that distance dynamically, since my div that got animated ideally will change the width dynamically as well since that is not going always be 100% or any specific px fixed.
Is there way I can do that in JavaScript instead and not let css to take charge in this transform distance part?
Cross browser capacity will be great.
SCSS
.myItem {
height: 100px;
width: 501px;
background-color: beige;
animation: to-left-transition 300ms;
animation-iteration-count: 1;
animation-fill-mode: forwards;
animation-timing-function: ease-in-out;
}
#keyframes to-left-transition {
0% {
transform: translate(0);
}
100% {
transform: translate(100%);
}
}
HTML
<div class="myItem">
stuff here
</div>
Found out a better way. Soooooo much easier!
I should have been using transition instead of animation. As that give me the flexibility to adjust the animation accordingly.
Hope it helps someone else to save couple hours!
http://codepen.io/adamchenwei/pen/xRqYNj
HTML
<div class="myItem">
stuff here
</div>
CSS
.myItem {
position: absolute;
height: 100px;
width: 501px;
background-color: beige;
transition: transform 1s;
}
JS
setTimeout(function() {
document.getElementsByClassName('myItem')[0].style.transform="translateX(400px)";
console.log('ran');
}, 3000);
EDIT
Below is a method sugguested by Dennis Traub
setTimeout(function() {
console.log('ran');
$("head").append('<style type="text/css"></style>');
var new_stylesheet = $("head").children(':last');
new_stylesheet.html('.myItem{animation: to-left-transition 600ms;}');
}, 3000);
.myItem {
position: absolute;
height: 100px;
width: 501px;
background-color: beige;
animation-iteration-count: 1;
animation-fill-mode: forwards;
animation-timing-function: ease-in-out;
}
#keyframes to-left-transition {
0% {
transform: translate(0);
}
100% {
transform: translate(100%);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="item" class="myItem">
stuff here
</div>
Answer Before EDIT
Here is a good reference for something similar to what i think you are trying to accomplish.
Based on your dynamic input you could have a function that controls how far the div transitions. Still use your code for transition in the css, but compute how far you want in the jquery or JavaScript. Then call the css transition for how far or long you want to transition.
var boxOne = document.getElementsByClassName('box')[0],
$boxTwo = $('.box:eq(1)');
document.getElementsByClassName('toggleButton')[0].onclick = function() {
if(this.innerHTML === 'Play')
{
this.innerHTML = 'Pause';
boxOne.classList.add('horizTranslate');
} else {
this.innerHTML = 'Play';
var computedStyle = window.getComputedStyle(boxOne),
marginLeft = computedStyle.getPropertyValue('margin-left');
boxOne.style.marginLeft = marginLeft;
boxOne.classList.remove('horizTranslate');
}
}
$('.toggleButton:eq(1)').on('click', function() {
if($(this).html() === 'Play')
{
$(this).html('Pause');
$boxTwo.addClass('horizTranslate');
} else {
$(this).html('Play');
var computedStyle = $boxTwo.css('margin-left');
$boxTwo.removeClass('horizTranslate');
$boxTwo.css('margin-left', computedStyle);
}
});
.box {
margin: 30px;
height: 50px;
width: 50px;
background-color: blue;
}
.box.horizTranslate {
-webkit-transition: 3s;
-moz-transition: 3s;
-ms-transition: 3s;
-o-transition: 3s;
transition: 3s;
margin-left: 100% !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>Pure Javascript</h3>
<div class='box'></div>
<button class='toggleButton' value='play'>Play</button>
<h3>jQuery</h3>
<div class='box'></div>
<button class='toggleButton' value='play'>Play</button>
This code was written by Zach Saucier on codepen
This is a good reference for manipulating css with JS: https://css-tricks.com/controlling-css-animations-transitions-javascript/