CSS Animation - Steps - to Animate Bookmark Star - javascript

I have the following code:
let animation = document.getElementById('fave');
animation.addEventListener('click', function() {
$(animation).toggleClass('animate');
});
.fave {
width: 70px;
height: 50px;
position: relative;
overflow: hidden;
}
.fave img {
position: absolute;
top: 0;
left: 0;
cursor: pointer;
animation: test_animate_reverse 1s steps(55);
}
.fave .animate {
animation: test_animate 1s steps(55);
left: -3519px;
}
#keyframes test_animate {
from {left: 0;}
to {left: -3519px;}
}
#keyframes test_animate_reverse {
from {left: -3519px;}
to {left: 0;}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="fave"><img src="https://cssanimation.rocks/images/posts/steps/twitter_fave_rectangle.png" id="fave"></section>
The target image is: https://cssanimation.rocks/images/posts/steps/twitter_fave_rectangle.png (albeit already modified so that all the images are positioned horizontally).
The result is quite satisfactory already. However, I have concerns:
As can probably be seen, my star always animates from the last frame of said image to the first frame whenever I refresh the browser window. If possible, I'd like it to not do that when I first refresh the window and only reverse-animate when I toggle it from 'active' to 'not active'.
I feel like using two #keyframes just to reverse an animation that is exactly the same is kind of inefficient. Is there a way to achieve the same effect without having to make an additional reverse #keyframes?
Is there a way for me to achieve the same effect without specifying the size of section explicitly when said section does not have a parent?
When I click quickly a few times on said image, if possible, I'd like it to finish its current animation first before proceeding to the next one. With my code now, preceding animations are immediately ended when a new animation is run.
EDIT
I've tried to not use the reverse #keyframes by changing to the following:
.fave img {
position: absolute;
top: 0;
left: 0;
cursor: pointer;
animation: test_animate .7s steps(55);
animation-direction: reverse;
}
What happened is the animation completely vanished.

Why not use the code from the actual tutorial where you got the image. It uses transition rather than animation and seems neater.
It will automatically reverse the animation too with the transition applied to the element.
You can set a disabled flag and use setTimeout() to prevent multiple clicks before the animation has finished.
var click_disabled = false;
$('.fave').click(function() {
if (click_disabled) {
return; // do nothing
}
$(this).toggleClass('faved');
// Set correct aria-label
var label = $(this).attr('aria-label') == 'Favourite' ? 'Unfavourite' : 'Favourite';
$(this).attr('aria-label',label);
click_disabled = true;
// Timeout value should match transition length
setTimeout(function(){
click_disabled = false;
}, 1000);
});
.fave {
background: none;
border: 0;
padding: 0;
width: 70px;
height: 45px;
background: url(https://res.cloudinary.com/shanomurphy/image/upload/v1547543273/fave_ltre0q.png) no-repeat;
background-position: 0 0;
transition: background 1s steps(55);
outline: 0;
cursor: pointer;
}
.fave.faved {
background-position: -3519px 0;
}
<button class="fave" aria-label="Favourite"></button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Related

setTimeout and display none with a fader timer- How to do it chronologically?

I am sitting with a project in need of an overlay which fades out when hovered upon and goes to display: none (not visibility: hidden, it does need to be display: none).
The setup is a big confusing, but I will try to explain it:
The overlay comes up when I hover a menu point under my mega menu. When I move the cursor to the overlay it should naturally dissapear and the menu close.
This works very well with this code:
var element = document.getElementById("overlayed");
function mouseOver() {
element.classList.add("mystyle");
setTimeout(function() {
element.classList.remove("mystyle");
}, 500);
}
push {
position: absolute;
top: 50%;
}
.overlayerstwo {
position: fixed;
width: 100%;
top: 30%;
left: 0;
right: 0;
bottom: 0;
background: #111;
opacity: 0.5;
z-index: 2;
display: block;
visibility: visible;
}
.mystyle {
display: none;
animation-name: fadeOut;
animation-duration: .5s;
}
#keyframes fadeOut {
0% {
opacity: .5
}
100% {
opacity: 0;
}
}
.mystyler {
display: none;
}
<h1>Here is something. Overlay comes back when hovering me!</h1>
<div class="overlayerstwo" id="overlayed" onmouseover="mouseOver()"></div>
<div class="push">
<p>Here is an item being overlayed</p>
</div>
With this setup the overlay dissapears right away. I am trying to merge it with the fadeOut keyframe animation before it goes black. I have tried different tactics, like adding a second timeout event but all it does is loop through and end up showing the overlay permanently after.
So the order I want to achieve is as follows:
Add a class that fires the keyframe animation fadeOut for .5 sec
Remove keyframe animation class
Add display: block class
Remove display: block class (essentially resetting it, so you can get the overlay up again by hovering its triggerpoint)
So my question is, how do I get all of these to fire every time I hover over the overlay?
One of the things I tried was this:
var element = document.getElementById("overlayed");
element.classList.add("mystyle");
setTimeout(function(){
var element = document.getElementById("overlayed");
element.classList.remove("mystyle");
}, 500);
setTimeout(function(){
var element = document.getElementById("overlayed");
element.classList.add("mystyletwo");
}, 500);
setTimeout(function(){
var element = document.getElementById("overlayed");
element.classList.remove("mystyletwo");
}, 510);
With the css
.mystyle{
animation-name: fadeOut;
animation-duration: .5s;
}
.mystyletwo{
display: block;
}
Which did not work. I hope someone can help me figure out how to get it to work!
if the timeline will be like this: visible -> hover -> animation -> opacity to 0 -> display: none
using CSS with JS logic:
element.addEventListener("mouseover", function() {
element.style.opacity = "0";
element.style.transition = "all 0.3s";
// when finish the animation then call display none
setTimeout(function() {
element.style.display = "none";
}, 300); // put the same number (milliseconds) of duration of transition (or more, not less)
});
using this method you don't need to complex your code...
the trick really is because we use element.style
that is only put the CSS, but technically...
if there is a transition Javascript don't know it,
so it will run the setTimeout() directly after adding styles,
so now CSS will do the animation but javascript will quietly continue the code (which in our case, says that after 300 seconds add display: none;)

How to make an element reset its position after mouseout event in javascript

trying to make a button like this: https://gyazo.com/9afbd559c15bb707a2d1b24ac790cf7a. The problem with the code right now is that it works as it is supposed to on the first time; but after that, instead of going from left to right as intented, it goes from right to left to right.
HTML
<div class="btn-slide block relative mx-auto" style="overflow: hidden; width: 12rem;">
<span class="z-10">View Pricing</span>
<span class="slide-bg block absolute transition" style="background-color: rgba(0,0,0,.1); z-index: -1; top: 0; left:-10rem; width: 10rem; height: 3rem;"></span>
</div>
Javascript
const btns = document.querySelectorAll(".btn-slide");
const slide = document.getElementsByClassName('slide-bg');
btns.forEach(function(btn) {
btn.addEventListener('mouseout', function () {
slide[0].style.transform = 'translateX(230%)';
slide[0].style.transform = 'none';
})
btn.addEventListener('mouseover', function() {
slide[0].style.transform = 'translateX(80%)';
}, true)
})
Unless you have to compute a value in JavaScript (like the height of an element).
Use CSS classes as modifiers (is-hidden, is-folded, is-collapsed, ...).
Using JavaScript, only add/remove/toggle the class
yourElement.addEventListener(
"mouseenter",
function (event)
{
yourElement.classList.remove("is-collapsed");
}
);
yourElement.addEventListener(
"mouseleave",
function (event)
{
yourElement.classList.add("is-collapsed");
}
);
is-collapsed is only an exemple, name it according to your class naming standard.
You're probably going to need a bit more code than what you're showing, as you have two mutually exclusive CSS things you want to do: transition that background across the "button" on mouseenter/mouseout, which is animated, and then reset the background to its start position, which should absolutely not be animated. So you need to not just toggle the background, you also need to toggle whether or not to animation those changes.
function setupAnimation(container) {
const fg = container.querySelector('.label');
const bg = container.querySelector('.slide-bg');
const stop = evt => evt.stopPropagation();
// step one: make label text inert. This is critical.
fg.addEventListener('mouseenter', stop);
fg.addEventListener('mouseout', stop);
// mouse enter: start the slide in animation
container.addEventListener('mouseenter', evt => {
bg.classList.add('animate');
bg.classList.add('slide-in');
});
// mouse out: start the slide-out animation
container.addEventListener('mouseout', evt => {
bg.classList.remove('slide-in');
bg.classList.add('slide-out');
});
// when the slide-out transition is done,
// reset the CSS with animations _turned off_
bg.addEventListener('transitionend', evt => {
if (bg.classList.contains('slide-out')) {
bg.classList.remove('animate');
bg.classList.remove('slide-out');
}
});
}
setupAnimation(document.querySelector('.slide'));
.slide {
position: relative;
overflow: hidden;
width: 12rem;
height: 1.25rem;
cursor: pointer;
border: 1px solid black;
text-align: center;
}
.slide span {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.slide-bg {
background-color: rgba(0,0,0,.1);
transform: translate(-100%, 0);
transition: none;
z-index: 0;
}
.slide-bg.animate {
transition: transform 0.5s ease-in-out;
}
.slide-bg.slide-in {
transform: translate(0%, 0);
}
.slide-bg.slide-out {
transform: translate(100%, 0);
}
<div class="slide">
<span class="label">View Pricing</span>
<span class="slide-bg"></span>
</div>
And thanks to browsers being finicky with rapid succession mouseenter/mouseout events, depending on how fast you move the cursor this may not even be enough: you might very well still need a "step" tracker so that your JS knows which part of your total animation is currently active, and not trigger the mouseout code if, by the time the slide-in transition ends, the cursor is in fact (still) over the top container (or, again).
I advice you use the .on event listener
$('').on("mouseentre","elem",function(){$('').toggleclass('.classname')})
$('').on("mouseleave","elem",function(){$('').toggleclass('.classname')})
Then you can toggle css classes to your element in the function
toggle class adds the css of a class to your jquery selection, you can do it multiple times and have keyframes for animation in the css class
Keyframes are great way to implement animation and are supported on every browers

Background color changing it's height onload

I've been reading for couple hours from now, and probably I have problem even with asking right question.
What I would like to achieve is: changing the main page background height from 0 to 100% in let's say 10s, so after 1 second background color got 10% page height, after 2 seconds 20% of page height and so on. It should start to change after page load.
It could be jquery, css, or some external library, just want it to work.
Something like this?
body {
width: 100vw;
height: 100vh;
position: relative;
&::before {
content: "";
display: block;
position: fixed;
width: 100%;
background: red;
height: 0;
z-index: 0;
animation-fill-mode: forwards;
animation-name: expand;
animation-duration: 10s;
}
}
#keyframes expand {
from { height: 0; }
to { height: 100%; }
}
So basically, you add another layer underneath your content, which animates to the height of your page for 10s (the animation-duration)
Working JSFiddle: https://jsfiddle.net/y4kpcmjc/2/
From the official jquery docs
The .animate() method allows us to create animation effects on any numeric CSS property. The only required parameter is a plain object of CSS properties. This object is similar to the one that can be sent to the .css() method, except that the range of properties is more restrictive.
Here is the example
<img id="image" src="..." />
...
<script>
$(document).ready(function() {
$('#image').css('height', '0');
$('#image').animate({
height: "100%"
}, 10000, function() {
//Finished loading
});
})
</script>

How to let a navigation bar fadeout to the top after fading in?

I know how to make the navigation bar fading into the viewport from the top.
$(document).scroll(function () {
var x = $(window).scrollTop();
console.log(x)
if (x > 699) {
$("header").addClass("fix");
} else {
$("header").removeClass("fix");
}
});
.fix {
position: fixed;
background:#fff;
-webkit-animation: test .5s linear;
}
.fix + main {
padding-top: 100px;
}
#-webkit-keyframes test {
from { top:-100px }
to { top:0 }
}
When it removes the class, it just disappears.
How can i make fade out back to the top?
I log it into console only for testing. (Yes, i wrote the code, it's not copy paste.)
There is no need to use keyframes here, a simple transition will do the trick
You need to put the position fixed and the original top value on the header itself and only update the animated value when scrolling.
The issue you had before was you had position fixed on the fix class, as soon as you remove the fix class, your element is no longer fixed so it will disappear without any animations. In other words, it can only animate if you had the fix class on it.
https://jsfiddle.net/19qdtL3L/
I edited the scroll value so it will show up sooner
$(document).scroll(function() {
var x = $(window).scrollTop();
console.log(x)
if (x > 300) {
$("header").addClass("fix");
} else {
$("header").removeClass("fix");
}
});
header {
top: -100px;
position: fixed;
transition: top 0.5s;
}
.fix {
background: green;
top: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header>header element</header>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br> <br><br><br><br><br> <br><br><br><br><br>
<br>sdfdsf
Your actual keyframe is only going one way : down (top: -100px to top: 0). What you want to do can't work like this.
You could do this without a keyframe, only with a transition :
$('button').on('click',function(){
$('div').toggleClass('shown');
});
div{
position: static;
top: -50px;
left: 0;
width: 100%;
height: 50px;
background-color: red;
transition: all .5s;
}
div.shown{
top: 0;
}
button{
margin-top:100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
<button>Click me</button>

After resetting transition, div stays visible; no new transition

I'm trying to make a <div> display and then fade out, on button click.
This works so long as the user waits for the fade to complete between <button> presses.
My problem is, if the <button> is clicked while the fade is ongoing, the <div> needs to immediately reappear, and then fade out.
I've managed to get it to immediately reappear, but now it doesn't fade out again.
To get an easier idea of what I'm doing, take a look at the JSFiddle I've setup.
Can anyone help me get this to fade out if clicked whilst already fading out?
I'm only targeting webkit.
<div id="saved">Saved!</div>
<button id="save">Save</button>
function save()
{
// Little "Saved!" div
var div = document.getElementById('saved');
// If still showing from previous save
if(div.style.visibility === 'visible')
{
resetTransition();
div.style.visibility = 'visible';
//div.style.opacity = 0;
console.log('reset');
}
// On transition end
div.addEventListener('webkitTransitionEnd', resetTransition);
function resetTransition()
{
// Disable transitions
div.className = 'notransition';
// Hide the div and reset the opacity
div.style.visibility = 'hidden';
div.style.opacity = 1;
// Need time to let CSS changes (^) refresh
setTimeout(function()
{
// Re-enable transitions
div.className = '';
// Remove the event listener by way of cloning
var dolly = div.cloneNode(true);
div.parentNode.replaceChild(dolly, div);
}, 1);
}
// Show the div and fade out - on timer due to "if still showing" needing
// to process first
setTimeout(function()
{
div.style.visibility = 'visible';
div.style.opacity = 0;
}, 1);
}
document.getElementById('save').addEventListener('click', save);
div#saved
{
-webkit-transition: opacity 1.25s ease-out;
-webkit-transition-delay: 0.75s;
background-color: #FFC;
/* Courtesy of http://fatcow.com/free-icons */
background-image: url('http://i.imgur.com/JMlclKE.png');
background-position: 3px 4px;
background-repeat: no-repeat;
border: 1px solid #333;
border-radius: 6px;
left: 5px;
opacity: 1;
padding: 10px 4px 10px 52px;
position: absolute;
top: 5px;
visibility: hidden;
width: 68px;
}
.notransition
{
-webkit-transition: none !important;
-webkit-transition-delay: none !important;
}
button
{
position: absolute;
top: 100px;
}
I updated your fiddle, moving the cloning to the top and clearing the timeout.
// Little "Saved!" div
clearTimeout(save.t);
var dolly = document.getElementById('saved');
// Remove the event listener by way of cloning
var div = dolly.cloneNode(true);
dolly.parentNode.replaceChild(div, dolly);
/* etc til */
save.t = setTimeout(/* */);

Categories

Resources