EDIT: This is not the same as this post, How to reverse an animation on mouse out after hover. The difference being that in this case the state of the transition (how far it has progressed) is essential unlike in the aforementioned post that completely ignores it.
TL;DR: How to animate/transition an element back to it's original state after animation ends?
Hello,
I'm trying to make animate panels so that they "float" when hovered. My problem is that the mouse leaves the panel, instead of transitioning back to it's original state, it jumps instantly back.
A heavily simplified version of this can be found in the snippet available below.
body {
width: 100%;
height: 100vh;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
}
div {
width: 50px;
height: 50px;
background-color: red;
}
div:hover {
animation: float 2s infinite ease;
}
#keyframes float {
0%, 100% {
transform: none;
}
50% {
transform: translateY(-20px);
}
}
<html>
<head>
<title>animate to orignal position</title>
</head>
<body>
<div id='box'></div>
</body>
</html>
As you can see, floating it triggers a smooth animation that resembles a floating motion, however, it is abruptly interrupted as the mouse leaves the box and the animation stops.
So my question is: Is there a way to allow the box to transition back to it's original state, preferably without using JavaScript (although all suggestions are appreciated).
(This has probably been answered somewhere online and if that is the case, then I am truly sorry but I have been unable to find a proper solution to my problem. Please add duplicate if you find an applicable solution.)
Thanks.
You're going to have to use JavaScript and CSS Transitions:
var box = document.getElementById('box')
var timer
box.addEventListener('mouseenter', function () {
box.classList.add('up')
timer = setInterval(function () {
box.classList.toggle('up')
}, 1000)
})
box.addEventListener('mouseleave', function () {
clearInterval(timer)
box.classList.remove('up')
})
body {
width: 100%;
height: 100vh;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
}
div {
width: 50px;
height: 50px;
background-color: red;
transition: transform 1s ease;
}
div.up {
transform: translateY(-20px);
}
<html>
<head>
<title>animate to orignal position</title>
</head>
<body>
<div id='box'></div>
</body>
</html>
Related
How to stop/start CSS animation
Background-Info
I'm trying to make a loader for my website where when someone makes a search to my API it will popup the loader then after the table gets built it will stop the loading animation. I'm not good with javascript and I'm just trying to create this side project so I don't completely know how this stuff works. I did see another stack overflow post about this topic but it didn't apply to me because the way they called the CSS animation was different
I followed a tutorial for this loader here he shows how to stop it but he doesn't show how to start it, but it doesn't stop for me
What I tried
Like I was saying above I'm not good with javascript so I wasn't sure what i should try but like in the video I tried to make the CSS display = None and also i tried to remove the HTML entirely ( you can see it below in the code)
End goal
My end goal is to have a javascript function like start_loading() and stop_loading() I can call to stop and start the loading at any time
Code
function start_load() {
let spinnerWrapper = document.querySelector('.spinner-wrapper')
console.log(document.querySelector('.spinner-wrapper'))
window.addEventListener('load', function() {
spinnerWrapper.style.display = 'none';
// spinnerWrapper.parentElement.removeChild(spinnerWrapper)
});
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-size: 10px;
}
.spinner-wrapper {
width: 100%;
height: 100%;
/* background-color: #151515; */
position: absolute;
top: 0;
left: 0;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
}
.spinner {
position: relative;
width: 8rem;
height: 8rem;
border-radius: 50%;
}
.spinner::before,
.spinner:after {
content: "";
position: absolute;
border-radius: 50%;
}
.spinner:before {
width: 100%;
height: 100%;
background-image: linear-gradient(90deg, #212529 0%, white 100%);
animation: spin .5s infinite linear;
}
.spinner:after {
width: 90%;
height: 90%;
background-color: white;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
#keyframes spin {
to {
transform: rotate(360deg);
}
}
/*Simulate page content*/
.main-content {
width: 100%;
height: 100vh;
background: url("https://source.unsplash.com/random/4000x4000") center no-repeat;
background-size: cover;
}
<body onload="verifySession(), start_load()">
<div class="spinner-wrapper">
<div class="spinner">
</div>
</div>
const start_load = function () {
document.querySelector('.spinner-wrapper').style.display = "block"
}
const end_load= function () {
document.querySelector('.spinner-wrapper').style.display = "none"
}
You can change .spinner-wrapper by any class you want. Those function will set fisrt html tag have .spinner-wrapper class to display : block or display : none
Hope this help for you
Your question is not very clear on when you want to start and stop the loader but from my understanding you have an api and you want the loader to show when someone calls your api so in this particular case you want to work with DOM event listeners (at least when you start your search by a click of a button or when you press enter on your keyboard) you can read more on event listeners here:
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener and here:
https://www.w3schools.com/js/js_htmldom_eventlistener.asp
As for stopping the event you will want to call the stop function once data are returned from your API
I've created a little codesandbox for you with two buttons to start and stop the loader as a simple example of how to use event listeners which you can find here: https://codesandbox.io/s/happy-rain-e9w3mz
please tell me how to make an activity, when you press red square, the red square is removed, and the green one slowly decreases, my code doesn't work
function del() {
document.getElementById("del").style = "display:none";
}
.container {
width: 30vmin;
background: green;
transition: all 5s ease;
}
#del {
width: 10vmin;
height: 10vmin;
background: red;
}
<!DOCTYPE html>
<body>
<div class="container">
<div id="del" onclick="del()"></div>
</div>
</body>
</html>
There are two related factors here:
the container only has height because its child (the red square) has
height so when you make that 0vmin the green div also disappears as
it now has no content with height - this is not the same as setting its
style.height to 0
on clicking the red square it disappears immediately as required but
nothing is done about the container
This snippet adds two things: it gives a specific initial height to the container and it sets the container's opacity to 0 when the red square is clicked. Obviously you can change the effects you want (is it to go slowly smaller rather than slowly disappear for example?):
function del() {
document.getElementById("del").style = "display:none";
document.querySelector(".container").style.opacity = '0';
}
.container {
width: 30vmin;
background: green;
transition: all 5s ease;
height: 10vmin;
}
#del {
width: 10vmin;
height: 10vmin;
background: red;
}
<!DOCTYPE html>
<body>
<div class="container">
<div id="del" onclick="del()"></div>
</div>
</body>
</html>
Display: none can't be used with transitions. Try opacity
Also when your red box is removed from the UI, your .container has no height set and seems to disappear as well. In reality it's still there but just has 0 height
You need to set an opacity to the container element to use the transition and set a height to it so it doesn't lose the height when the #del element is removed. To make it easier I created an javascript event handler instead of your inline event handler.
document.querySelector('#del').addEventListener('click', (e) => {
e.currentTarget.style = "display:none";
e.currentTarget.parentElement.style = "opacity:0";
});
.container {
width: 30vmin;
height: 10vmin;
background: green;
opacity: 1;
transition: opacity 5s ease;
}
#del {
width: 10vmin;
height: 10vmin;
background: red;
}
<body>
<div class="container">
<div id="del"></div>
</div>
</body>
display: none; isn't affected by transitions: an element is either displayed or not. There are two properties that are affected by transitions that might interest you:
opacity: 0;
width: 0;
opacity is similar to display: hidden; but can range from 0.0 to 1.0 (from 0% to 100%).
width simply "hides horizontally" the element (it removes a dimension).
I suggest to use classes instead of ids and switch to the one that "deletes" the element (actually hides it).
function del() {
const delEl = document.getElementById("del");
delEl.style = "display:none";
const containerEl = document.getElementById("container");
containerEl.style = "width: 20vmin";
}
#container {
height: 10vmin;
width: 30vmin;
background: green;
transition: all 5s ease;
}
#del {
height: 10vmin;
width: 10vmin;
background: red;
}
<!DOCTYPE html>
<body>
<div id="container">
<div id="del" onclick="del()"></div>
</div>
</body>
</html>
On a desktop the div with class="content" will be visible when hovering on the div with class="button". There is also a callback so it automatically fades out when hovering somewhere else.
But, this is not working on a mobile device because it is not possible to hover. I tried different solutions like adding other pseudo-classes (:active, :focus) and tried some JavaScript / jQuery. I also found this question How to simulate hover effect on touch devices?. I think JS is the best way to solve this problem but I am not used to work with that.
Here is my HTML code:
<div class="home">
<div class="button">
<div class="content"></div>
</div>
</div>
CSS:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.home {
display: flex;
justify-content: center;
align-items: center;
background-color: #3d2885;
width: 100vw;
height: 100vh;
}
.button {
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
width: 50vmin;
height: 50vmin;
background-color: white;
border-radius: 50%;
}
.content {
width: 0vmin;
height: 0vmin;
background-color: lightgreen;
-webkit-transition: 0.5s ease-in-out;
transition: 0.5s ease-in-out;
}
.button:hover .content {
width: 25vmin;
height: 25vmin;
border-radius: 15%;
}
And I tried some jQuery:
$('.button').bind('touchstart', function() {
$(this).addClass('content');
});
$('.button').bind('touchend', function() {
$(this).removeClass('content');
});
Can anyone tell me how I can implement jQuery (or something else) so that a click event on a mobile device has the same effect as a hover effect on a desktop?
In this case I mean that the div with class="content" has a transition effect (growing) on clicking and a transition effect (shrinking) on clicking somewhere else.
Codepen example: https://codepen.io/elinehendrikse/pen/JJVRLm?editors=0110
Edit: See my answer below.
while waiting for setTimeout to runout, i thought it will be a good idea to add animation.
CSS:
.ws_addButton {border:1px black solid;border-radius:28px;}
.msg[data-status=toPublish] .ws_addButton {background-color:LightCoral;}
.msg[data-status=published] .ws_addButton {background-color:#7892c2; cursor:default;}
#keyframes loas_BG {
from {background: linear-gradient(to right, Initial 0%, transparent 100%);}
to {background: linear-gradient(to right, Initial 0%, transparent 0%);}
}
*I used Initial because i don't know the first color (blue or red)
And the JS that trigger it (need to run only once):
selectMSG.getElementsByClassName('ws_addButton')[0].style.animation = 'loas_BG '+ws_set_delay_basic+'s linear';
But it dosen't work (the animation dosen't start)), and I don't sure why.
tried to find information in google and here, but for now without luck.
<s>any idea how to solve it?</s>
Edit: See my answer below.
after a little more homework i tried this:
var ws_set_delay_basic = 5;
window.getComputedStyle(document.querySelector('#ws_addButton'), ':before').style.animation = 'mymove '+ws_set_delay_basic+'s';
div {
width: 100px;
height: 100px;
background: red;
position: relative;
}
div:before {
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
width: 0;
height: 100%;
background: gray;
opacity: 0.5;
/* animation: mymove 5s; */
}
#keyframes mymove {
from { width: 0; }
to { width: 100%; }
}
<div id="ws_addButton"></div>
As you see, I tried to select a Pseudo-Element, but without success.
Without js, I can add animation directly to it (=Pseudo-Element), but then I do not have a dynamic time.
how can I add animation to Pseudo-Element correctly?
I have a simple page containing 3 divs within a container like this:
<body>
<div id="mainContainer">
<div id="mainColumn1" class="bgColumn"></div>
<div id="mainColumn2" class="bgColumn"></div>
<div id="mainColumn3" class="bgColumn"></div>
</div>
</body>
They are meant to be 3 even columns that occupy entire page. Whenever you hover one of them it expands to 50%, and the others shrink to 25%.
It's hard to explain where the problem is so here's jFiddle:
http://jsfiddle.net/FWcC5/2/
If you move cursor quickly all over the place, you will notice white space appear on the right side. It happens in Firefox. Oddly enough in Chrome it behaves exactly as it should.
I tried using the same thing with flex-grid, which worked but the performance dropped drastically in Chrome.
Any help would be appreciated.
I'm not sure what the problem is with Firefox though I tried and can confirm there is an issue, however there is a better and less procedural way of achieving what you're currently doing.
You can shorten your javascript massively to:
$(document).ready(function () {
$('.bgColumn').hover(function(){
$('.bgColumn').width("25%").not($(this));
$(this).width("50%");
});
});
see fiddle
$(document).ready(function () {
$('.bgColumn').hover(function(){
$(this).width('50%');
$('.bgColumn').not(this).width('25%');
},
function(){
$('.bgColumn').width('33.3%');
});
});
html, body {
height: 100%;
margin: 0;
padding: 0;
background-repeat: no-repeat;
}
div {
position: relative;
background-position: center;
}
#mainContainer {
width: 100%;
height: 100%;
overflow: hidden;
white-space:nowrap;
}
.bgColumn {
position: relative;
background-repeat: no-repeat;
transition: all 0.1s linear;
height: 100%;
width: 33.333%;
display: inline-block;
}
#mainColumn1 {
background-color: gray;
float:left;
}
#mainColumn2 {
background-color: white;
float:left;
}
#mainColumn3 {
background-color: black;
float:right;
}