I'm trying to create the following effect for any element using only jQuery/plugins:
In particular it should use a transform for the scale rather than width and height animation and be usable on any DOM element.
Is there a plugin available for jQuery which will achieve this effect? It should be quite simple: duplicate the dom object with clone(), reposition the clone over the original absolutely then animate a scale transform and opacity on the new element. However, I suspect it's not as simple as this.
Any ideas?
You don't need jQuery to accomplish that animation. You can use CSS3 animations and transform properties. Check out the following example I created:
http://jsbin.com/purik/1/
HTML:
<div class="logos">
<div class="logo"></div>
<div class="logo animated"></div>
</div>
CSS:
.logos {
position: relative;
}
.logo {
width: 100px;
height: 70px;
background: #CC0000 url(http://www.w3schools.com/images/w3logo.png) 50% 50% no-repeat;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.logo.animated {
position: absolute;
left: 0;
top: 0;
animation: scale-fadeout 2s infinite;
-webkit-animation: scale-fadeout 2s infinite;
}
#keyframes scale-fadeout {
0% {
transform: scale(1);
opacity: 1;
}
5% {
opacity: 1;
transform: scale(1.05);
}
100% {
opacity: 0;
transform: scale(1.35);
}
}
#-webkit-keyframes scale-fadeout {
0% {
-webkit-transform: scale(1);
opacity: 1;
}
5% {
opacity: 1;
-webkit-transform: scale(1.05);
}
100% {
opacity: 0;
-webkit-transform: scale(1.35);
}
}
This works if the parent element is position: relative, and the element itself is position: absolute.
Clones the element and then animates it to change the size, change the values of left and top, and the set opacity: 0.
Fiddle: http://jsfiddle.net/Ej38P/1/
Related
I'm trying to find a way to speed up the transform (flip about the y axis) in 0.05 seconds. Basically, the image flips in 0.05 seconds. The flip animation however does not change despite what I did in CSS. Please help
CSS
<style>
.a {
width: 50px;
height: 50px;
position: relative;
animation-name: box;
animation-duration: 10s;
transition: transform 0.05s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
#keyframes box {
0% { left: var(--rando0); top: var(--rando1); transform: rotateY(180deg);}
25% { transform: rotateY(180deg) left: var(--rando2); top: var(--rando3);}
50% { left: var(--rando4); top: var(--rando5); transform: rotateY(180deg);}
75% { transform: rotateY(180deg) left: var(--rando6); top: var(--rando7);}
100% { left: var(--rando8); top: var(--rando9); transform: rotateY(180deg);}
}
HTML
<img src="image.gif" alt="prgm" class='a left' class='character'>
JS
<script>
const root = document.querySelector(":root"); // we first get the root element
for(let i = 0; i < 10; i++) {
root.style.setProperty(`--rando${i}`, `${Math.floor(Math.random() * 200) + 1}px`);
}
</script>
Thanks
You can have two animations running at the same time. This snippet keeps the left/top animation at 10s and introduces a rotate animation at 0.5s. (At 0.05s the rotation gives very flashing result which didn't seem to be likely what you wanted).
const root = document.querySelector(":root"); // we first get the root element
for (let i = 0; i < 10; i++) {
root.style.setProperty(`--rando${i}`, `${Math.floor(Math.random() * 200) + 1}px`);
}
.a {
width: 50px;
height: 50px;
position: relative;
animation-name: box, rotate;
animation-duration: 10s, 0.5s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
#keyframes rotate {
0%,
49.99%,
100% {
transform: rotateY(0);
}
50%,
99.99% {
transform: rotateY(180deg);
}
}
#keyframes box {
0% {
left: var(--rando0);
top: var(--rando1);
}
25% {
left: var(--rando2);
top: var(--rando3);
}
50% {
left: var(--rando4);
top: var(--rando5);
}
75% {
left: var(--rando6);
top: var(--rando7);
}
100% {
left: var(--rando8);
top: var(--rando9);
}
}
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRzhbV48pXypX9otxEVYrZ1etEOZqym7693twATGzSGqg&s" alt="prgm" class='a left' class='character'>
UPDATE: the requirement was clarified - the image is to flip instantaneously but every half second goes back to its initial orientation.
The keyframes named rotate have been changed so that it stays at 0degrees rotation for half the animation time, flips 180degrees and stays at that for the second half.
Hello and thank you in advance for reading my question.
GOAL: Set image so that once it's scrolled into view it transitions smoothly into a set position - but still reacts to :hover. Using #keyframes and a little JavaScript, I set the image to opacity: 0 and it's final opacity to opacity: .85. Then I added a hover effect in CSS to make it's opacity: 1
The issue is once it's finished with it's transition - it disappears - reverting to it's original opacity which is zero. I managed to make it freeze at .85 with animation-fill-mode: forwards, rather than animation-fill-mode: none, but then it won't respond to :hover
And here's a test snippet of the problem in action:
let observer_img = new IntersectionObserver(updates => {
updates.forEach(update => {
if (update.isIntersecting) {
update.target.classList.add('shift_frame_center_img');
} else {
update.target.classList.remove('shift_frame_center_img');
}
});
}, { threshold: 0 });
[...document.querySelectorAll('.features-img-wrapper img')].forEach(element => observer_img.observe(element));
body {
width: 100%;
height: 100vh;
background-color: lightgrey;
}
/* CHILD */
.features-img-wrapper img {
width: 10rem;
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 8rem;
opacity: 0;
transition: all .5s;
}
/* APPEND-CHILD */
.shift_frame_center_img {
animation: center_img 1s 0.5s none;
}
/* CHILD ON HOVER */
.features-img-wrapper img:hover {
opacity: 1;
transform: scale(1.035);
}
/* KEYFRAMES */
#keyframes center_img {
0% {
transform: translateY(20rem);
}
100% {
transform: translateY(0);
opacity: .85;
}
}
<body>
<div class="features-img-wrapper">
<img src="https://synapse.it/wp-content/uploads/2020/12/test.png">
</div>
</body>
If I could get a hand with this that would be wonderful, I'm a bit of a beginner and have already spent a few hours on this, all feedback welcome. Thank you very much.
Solution 1
To understand why the hover effect was not working with the animation-fill-mode: forwards, read this answer.
You can fix that by adding !important property to the hover styles:
.features-img-wrapper img:hover {
opacity: 1 !important;
transform: scale(1.035) !important;
}
The problem, in this case, is that the transition will not work for hover.
Solution 2
You could remove the animation entirely and add the final state styles to the shift_frame_center_img class.
But you would still need to use the !important property because of the CSS Specificity.
let observer_img = new IntersectionObserver(updates => {
updates.forEach(update => {
if (update.isIntersecting) {
update.target.classList.add('shift_frame_center_img');
} else {
update.target.classList.remove('shift_frame_center_img');
}
});
}, { threshold: 0 });
[...document.querySelectorAll('.features-img-wrapper img')].forEach(element => observer_img.observe(element));
body {
width: 100%;
height: 100vh;
background-color: lightgrey;
}
/* CHILD */
.features-img-wrapper img {
width: 10rem;
transform: translateY(20rem);
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 8rem;
opacity: 0;
transition: all .5s;
}
/* APPEND-CHILD */
.shift_frame_center_img {
transform: none !important;
opacity: .85 !important;
}
/* CHILD ON HOVER */
.features-img-wrapper img:hover {
opacity: 1 !important;
transform: scale(1.035) !important;
}
<body>
<div class="features-img-wrapper">
<img src="https://synapse.it/wp-content/uploads/2020/12/test.png">
</div>
</body>
This snippet removes the need for fill-mode forwards by setting the img to have opacity 1 as its initial state so it will revert to that at the end of the animation.
The animation itself is altered to take 1.5s rather than 1s with the first third simply setting the img opacity to 0 so it can't be seen. This gives the delay effect.
let observer_img = new IntersectionObserver(updates => {
updates.forEach(update => {
if (update.isIntersecting) {
update.target.classList.add('shift_frame_center_img');
} else {
update.target.classList.remove('shift_frame_center_img');
}
});
}, { threshold: 0 });
[...document.querySelectorAll('.features-img-wrapper img')].forEach(element => observer_img.observe(element));
body {
width: 100%;
height: 100vh;
background-color: lightgrey;
}
/* CHILD */
.features-img-wrapper img {
width: 10rem;
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 8rem;
opacity: 0;
transition: all .5s;
opacity: 1;
}
/* APPEND-CHILD */
.features-img-wrapper img {
animation: center_img 1.5s 0s none;
}
/* CHILD ON HOVER */
.shift_frame_center_img:hover {
opacity: 1;
transform: translateY(0) scale(1.035);
}
/* KEYFRAMES */
#keyframes center_img {
0% {
transform: translateY(20rem) scale(1);
opacity: 0;
}
33.33% {
transform: translateY(20rem) scale(1);
opacity: 0;
}
100% {
transform: translateY(0) scale(1);
opacity: .85;
}
}
<body>
<div class="features-img-wrapper">
<img src="https://synapse.it/wp-content/uploads/2020/12/test.png">
</div>
</body>
Note: as each transform setting will reset anything that isn't included both tranlateY and scale are included in each setting.
Outside the SO snippet system it was possible to leave the animation settings untouched by chaining another animation to the front which ran for 0.5s and just set the img to opacity: 0. This did not work in the snippet system (it got into a loop of flashing on and off) hence the introduction of one but extended animation.
So, I have created a CSS3 animation that is supposed to fade out an element by setting its opacity from 1 to 0 and at the last frames change the position to absolute and display to none. But on Safari it will only maintain the opacity, position and display are not set to the final values.
#-webkit-keyframes impressum-fade-out {
0% {
opacity: 1;
display: block;
position: relative;
}
99% {
opacity: 0;
position: relative;
}
100% {
opacity: 0;
display: none;
position: absolute;
}
}
It seems to work on Chrome but not on Safari (I tried version 8). Apparently, position and display do not work properly with animation-fill-mode: forwards...
JSFiddle: http://jsfiddle.net/uhtL12gv/
EDIT For Bounty: I am aware of workarounds with Javascript and transitionend events. But I am wondering why Browsers lack support for this? Does the specification state that fillmode forwards doesnt apply to some attributes like position or is this a bug in the browsers? Because I couldnt find anything in the bug trackers.. If anybody has some insight, I would really appreciate it
As Suggested in the comments, you can adjust the height.
EDIT: Animation Reference Links Added.
Display property is not animatable.
Position property is not
animatable.
List of all CSS properties and if and how they are
animatable.
$('.block').click(function() { $(this).toggleClass('active') });
#-webkit-keyframes impressum-fade-out {
0% {
opacity: 1;
}
99% {
opacity: 0;
}
100% {
opacity: 0;
height:0;
}
}
.block {
width: 100px;
height: 100px;
background: blue;
}
.block2 {
width: 100px;
height: 100px;
background: red;
}
.block.active {
-webkit-animation-name: impressum-fade-out;
animation-name: impressum-fade-out;
-webkit-animation-duration: 500ms;
animation-duration: 500ms;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="block"></div>
<div class="block2"></div>
I would suggest you the cross-browser solution based on CSS3 Transitions and transitionend event:
JSFiddle
$('.block').one('click', function() {
var $this = $(this);
$this.one('webkitTransitionEnd transitionend', function() {
$this.addClass('block_hidden');
$this.removeClass('block_transition');
});
$this.addClass('block_transition');
});
.block {
width: 100px;
height: 100px;
background: blue;
-webkit-transition: opacity 0.5s;
transition: opacity 0.5s;
}
.block_2 {
background: red;
}
.block_transition {
opacity: 0;
}
.block_hidden {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="block"></div>
<div class="block block_2"></div>
I am trying to animate a div element (slide and fade) with a button click. At first, the element is not visible to a user. When the button is clicked, it will slide to right and fade in. Once the button is clicked again, it will slide to left and fade out. I come up with two solutions, with css and with JQuery.
In the first one, I used JQuery. You can find the example in this JSFiddle 1.
HTML
<button id="my-button">Click me!</button>
<div id="my-modal"></div>
CSS
#my-modal {
opacity: 1;
position: fixed;
top: 50px;
left: 0;
left: -250px;
width: 250px;
height: 100%;
background-color: red;
}
JQuery
$("#my-button").click(function () {
var $modal = $("#my-modal");
$modal.stop(true, true).animate({
left: "toggle",
opacity: "toggle"
}, 1000);
});
Here, everything seems working but it does directly opposite of what I want. It first fades out, and with the second click, it fades in. It is because that the opacity of the element is 1, but if I turn it to 0, nothing happens.
Secondly, I tried to do that with css animation by using key-frames (changing opacity from 0 to 1) but it has also problem. It starts the animation exactly the way I want. However, when I click the button again, it disappears immediately. Here is the JSFiddle 2.
HTML
<button id="my-button">Click me!</button>
<div id="my-modal"></div>
CSS
#my-modal {
opacity: 0;
position: fixed;
top: 50px;
left: 0;
left: -250px;
width: 250px;
height: 100%;
background-color: red;
-moz-transition: all 1s ease;
-webkit-transition: all 1s ease;
-o-transition: all 1s ease;
transition: all 1s ease;
}
.move-my-modal {
-moz-transform: translate(250px, 0px);
-webkit-transform: translate(250px, 0px);
-ms-transform: translate(250px, 0px);
-o-transform: translate(250px, 0px);
}
.animate-opacity {
-webkit-animation: toggle-opacity 1s ease;
-moz-animation: toggle-opacity 1s ease;
-o-animation: toggle-opacity 1s ease;
animation: toggle-opacity 1s ease;
-webkit-animation-fill-mode: forwards;
}
#-webkit-keyframes toggle-opacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#-moz-keyframes toggle-opacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#-o-keyframes toggle-opacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#keyframes toggle-opacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
JQuery
$("#my-button").click(function () {
var $modal = $("#my-modal");
$modal.toggleClass("move-my-modal");
$modal.toggleClass("animate-opacity");
});
To this end, I have these questions;
1) What are the problems with these two approaches? Is there something that I missed or forgot to use? How can I correct them to meet the requirements that I mentioned at the beginning.
2) Which one is the better way to make this action? Is there any cons or pros of these approaches?
3) Is there any other way to make this action? I am new on this area and I might not notice a simpler way.
You can toggle an .active class to the element and use CSS transitions.
This way, if the browser is old enough to not support animations, it will still work but it won't slow down computers that do not handle animations well.
$("#my-button").click(function () {
$("#my-modal").toggleClass('active');
});
#my-modal.active {
opacity: 1;
left: 0;
}
$("#my-button").click(function () {
$("#my-modal").toggleClass('active');
});
#my-modal {
opacity: 0;
position: fixed;
top: 50px;
left: -250px;
width: 250px;
height: 100%;
background-color: red;
transition: all 1s linear;
}
#my-modal.active {
opacity: 1;
left: 0;
}
<button id="my-button">Click me!</button>
<div id="my-modal"></div>
<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I would like to create an animation in jQuery or preferable pure javascript that makes a div "dangle". I have attached an animated gif that shows the animation. I don't know how recreate this, if it is something I can use an existing jquery easing / animation for or javascript + css animation or how. I also thought about canvas, but that would limit my ability to manipulate content etc.
RESULT:
Thanks to #peirix for helping me out with the CSS animation. Here is the result I was hoping to achieve. http://jsfiddle.net/zeg61pb7/7/
CSS
#box {
width:30px;
height:30px;
position:absolute;
top:100px;
left:100px;
text-indent: 90px;
background-color:#aaaaaa;
transform-origin: top center;
-webkit-transform-origin: top center;
-webkit-animation: dangle 2s infinite;
-webkit-border-top-left-radius: 50%;
-webkit-border-top-right-radius: 50%;
-moz-border-radius-topleft: 50%;
-moz-border-radius-topright: 50%;
border-top-left-radius: 50%;
border-top-right-radius: 50%;
}
#box:after {
position: absolute;
height: 5px;
width: 5px;
background: #aaaaaa;
top: -4px;
left: 12px;
content: '';
border-radius: 50%;
}
.dims {
position: absolute;
height: 10px;
width: 10px;
background: #aaaaaa;
top: 125px;
left: 110px;
border-radius: 50%;
-webkit-animation: movee 2s infinite;
}
#-webkit-keyframes dangle {
0% { -webkit-transform: rotate(0deg); }
5% { -webkit-transform: rotate(30deg); }
10% { -webkit-transform: rotate(-28deg); }
15% { -webkit-transform: rotate(26deg); }
20% { -webkit-transform: rotate(-24deg); }
25% { -webkit-transform: rotate(22deg); }
30% { -webkit-transform: rotate(-20deg); }
35% { -webkit-transform: rotate(18deg); }
40% { -webkit-transform: rotate(-16deg); }
45% { -webkit-transform: rotate(12deg); }
50% { -webkit-transform: rotate(-10deg); }
55% { -webkit-transform: rotate(8deg); }
60% { -webkit-transform: rotate(-6deg); }
65% { -webkit-transform: rotate(0deg); }
}
#-webkit-keyframes movee {
9% { left: 110px; }
10% { left: 120px; }
15% { left: 100px; }
20% { left: 114px; }
25% { left: 106px; }
30% { left: 113px; }
35% { left: 107px; }
40% { left: 111px; }
45% { left: 109px; }
50% { left: 110px; }
}
Well. You don't really need javascript for that. All you need is some CSS love. I made a quick fiddle to show the basics. Just play around with the numbers a bit to get what you want.
http://jsfiddle.net/zeg61pb7/3/
One note, though. Keyframes is still in need of -prefix for webkit browsers (chrome, safari, safari on ios, android etc), so you need to write it once with, and once without the prefix to hit all browsers. (Even IE10 and IE11 supports this)
You can have a try with css3.
Here is an interesting demo in Github.
Hope it helps you.
Indeed CSS3 can work some magic here, but you would still need Javascript to start and stop the animations, on hover or click events, for example.
I've made a small JSFiddle. Try and hover the red box. I've used webkit-prefixes, but you should be able to switch that easily with moz or ms.
The key differences to other suggestions here are
use animation-iteration-count: 1 to make it dangle once and then stop.
use $.on('<prefix>animationStop') to remove the animation class. this hack is needed to restart the animation later on.
I created a Fiddle with an example of how it can be done.
It depends on the transit-Plugin for jQuery.
var count = 0;
var deg = 45;
var minus = 5;
var interval = setInterval(function(){
$ $('#box').transition({
rotate: deg + 'deg',
transformOrigin: 'center top'
}).transition({
rotate: '-'+deg+'deg',
transformOrigin: 'center top'
});
if(count === 5){
clearInterval(interval);
$('#box').transition({ rotate: '0deg' })
}
if(deg > 10){
deg = deg-(minus+5);
}
count++;
}, 300);
A big plus is, that you can chain different transitions and transforms to your element.
But it`s an additional Plugin which must be loaded.