Webkit Animation interferes with jQuery function - javascript

I'm using a jQuery function for a parallax background inside a div.
When the page loads, I have some css webkit animations that animate the background.
However, after the page has finished loading, my jQuery function that animates the parallax effect on the background doesn't work.
Here is the code I have:
$(document).ready(function(){
$('#square').mousemove(function(e) {
var x = -(e.pageX + this.offsetLeft) / 4;
var y = -(e.pageY + this.offsetTop) / 4;
$(this).css('background-position', x + 'px ' + y + 'px');
});
});
#square { height: 700px;
width: 500px;
display: inline-block;
margin-left: 100px;
position: absolute;
right: 37%;
top: 15%;
background: transparent;
-webkit-animation-name: image-fadein;
-webkit-animation-delay: .8s;
-webkit-animation-duration: 1s;
-webkit-animation-iteration-count: 1;
-webkit-animation-timing-function: ease-in-out;
-webkit-animation-fill-mode: forwards;
#-webkit-keyframes image-fadein {
0% { background: transparent; }
25% { background: #f2efef; }
50% { background: #333; }
100% { background-image: url(https://destinyguides.files.wordpress.com/2014/08/destiny-wallpaper-3.jpg);
background-size: cover no-repeat;
background-position: 35% 30%; }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<div id="square">
<span class="l1"></span>
<span class="l2"></span>
<span class="l3"></span>
<span class="l4"></span>
</div>
I should mention that the jQuery function DOES work when I remove the webkit animations completely from the div element and just leave the height, width, display, margin, position, and background.
Does anyone know why it seems that the webkit animations are interfering with the jQuery code?

This is because properties that have been animated with a keyframe rule cannot be overridden by inline css rules, or at least not by any method I have tested.
You could
Move the animation styles to a class
Add the class to the element
Add an animationend listener to listen for the end of the animation
At the end of the animation remove the animation class and reset the background-image and other styles.
$(document).ready(function(){
$('#square').mousemove(function(e) {
var x = -(e.pageX + this.offsetLeft) / 4;
var y = -(e.pageY + this.offsetTop) / 4;
$(this).css("background-position",x + 'px ' + y + 'px');
}).on("animationend",function(e){
//You can access animation-name value by
//e.originalEvent.animationName
$(this).removeClass("animated").css({
backgroundImage:"url(https://destinyguides.files.wordpress.com/2014/08/destiny-wallpaper-3.jpg)",
backgroundSize: 'cover no-repeat',
backgroundPosition: '35% 30%'
});
});
});
#square {
width: 80%;
height:100%;
position: absolute;
top: 0px;
left:0px;
background: transparent;
}
.animated {
-webkit-animation-name: image-fadein;
-webkit-animation-delay: .8s;
-webkit-animation-duration: 1s;
-webkit-animation-iteration-count: 1;
-webkit-animation-timing-function: ease-in-out;
-webkit-animation-fill-mode: forwards;
}
#-webkit-keyframes image-fadein {
0% { background: transparent; }
25% { background: #f2efef; }
50% { background: #333; }
100% { background-image: url(https://destinyguides.files.wordpress.com/2014/08/destiny-wallpaper-3.jpg);
background-size: cover no-repeat;
background-position: 35% 30%; }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="square" class="animated">
<span class="l1"></span>
<span class="l2"></span>
<span class="l3"></span>
<span class="l4"></span>
</div>
You could also iterate over the styleSheets collection to find the keyframes rule ("image-fadein"), from there find the last keyframe rule ("100%"), and modify the styles from there.
Demo
$(document).ready(function(){
var KFSRule = findKFSRule("image-fadein");
var KFRule = KFSRule && KFSRule.findRule("100%");
$('#square').mousemove(function(e) {
var x = -(e.pageX + this.offsetLeft) / 4;
var y = -(e.pageY + this.offsetTop) / 4;
if(KFRule){
KFRule.style.backgroundPosition = x + 'px ' + y + 'px';
}
});
});
function findKFSRule(ruleName) {
var foundRule = null;
var sheets = [].slice.call(document.styleSheets);
sheets.forEach(function(sheet){
var rules = [].slice.call(sheet.cssRules);
rules.forEach(function(rule){
if(rule.type == CSSRule.WEBKIT_KEYFRAMES_RULE && rule.name==ruleName){
foundRule = rule;
}
});
});
return foundRule;
}
#square {
width: 80%;
height:100%;
position: absolute;
top: 0px;
left:0px;
background: transparent;
-webkit-animation-name: image-fadein;
-webkit-animation-delay: .8s;
-webkit-animation-duration: 1s;
-webkit-animation-iteration-count: 1;
-webkit-animation-timing-function: ease-in-out;
-webkit-animation-fill-mode: forwards;
}
#-webkit-keyframes image-fadein {
0% { background: transparent; }
25% { background: #f2efef; }
50% { background: #333; }
100% { background-image: url(https://destinyguides.files.wordpress.com/2014/08/destiny-wallpaper-3.jpg);
background-size: cover no-repeat;
background-position: 35% 30%; }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="square">
<span class="l1"></span>
<span class="l2"></span>
<span class="l3"></span>
<span class="l4"></span>
</div>
Note though that you cannot iterate over a style sheets css rules if it is an external stylesheet. So your styles will have to be embedded in the page, ie <style></style>
If you need them to be defined in an external style sheet you may need to find another work around utilizing maybe CSSStyleSheet.deleteRule,CSSStyleSheet.insertRule or other methods.

Related

Create "bobblehead" animation jquery

A bobblehead effect would be a "U" animation shape in my mind with slightly shorter stems.
I've tried using various arcs/semi-circles to create a bobblehead effect but nothing is working correctly.
I must use transform with translate due to it being an SVG. I am also using animejs but I cannot see a method to achieve this on that library either. jQuery animation steps seems the most simple?
This is the effect I'm looking to achieve:
[![enter image description here][1]][1]
Using this code:
function loopBobble() {
var end = 180;
$({
counter: 0
}).animate({
counter: end
},{
duration: 1000,
easing: "swing",
step: function(t, fx) {
var a = t / 60; // from degrees to radians
var x = Math.cos(a) * 10;
var y = Math.sin(a) * 10;
$('#bobble').attr('style', 'transform: translateX(' + x + 'px) translateY(' + y + 'px);');
if (t == end) {
loopBobble();
}
}
});
}
loopBobble();
The best I am able to achieve with the creepy face is this result:
[![enter image description here][2]][2]
Is my approach correct? I would have assumed a "U" shape animation would be built into animejs or jquery. I cannot find much online. I am no mathematician
How about css only?
.head {
background-color: #FA0;
border-radius: 50%;
width: 100px;
height: 100px;
left: 0px;
top: 0px;
position: absolute;
animation-name: xOffset;
animation-duration: 1s;
animation:
xOffset 1s ease-in-out infinite,
yOffset .5s ease-in-out infinite;
}
#keyframes xOffset {
50% { left: 50px; }
100% { left: 0px; }
}
#keyframes yOffset {
50% { top: 25px; }
100% { top: 0px; }
}
<div class="head"></div>
transform: translate-Version
You'll have to add a wrapper in your csv to apply separated easing-times on x and y. Otherwise different easing-times are not possible using transform since transform is animated as a whole.
.head {
background-color: #FA0;
border-radius: 50%;
width: 100px;
height: 100px;
animation-name: xOffset;
animation-duration: 1s;
animation: xOffset 1s ease-in-out infinite;
}
.wrapper {
animation: yOffset .5s ease-in-out infinite;
}
#keyframes xOffset {
50% { transform: translateX(50px); }
100% { transform: translateX(0px); }
}
#keyframes yOffset {
50% { transform: translateY(25px); }
100% { transform: translateY(0px); }
}
<div class="wrapper">
<div class="head"></div>
</div>

CSS transition fade in only the background not the child divs

I have this situation:
setTimeout(function() {
// Set BG image
var bg_content = document.querySelector('.content_top');
bg_content.style.background = "linear-gradient(0deg,#000 0,rgba(0,0,0,.7) 35%,rgba(0,0,0,.4) 50%,rgba(0,0,0,0) 100%),url(https://upload.wikimedia.org/wikipedia/commons/8/8f/Example_image.svg) no-repeat";
bg_content.style.backgroundSize = "cover";
bg_content.style.backgroundPosition = "center";
bg_content.classList.add("fade-in");
}, 1500);
.fade-in {
opacity: 1;
animation-name: fadeInOpacity;
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 0.5s;
}
#keyframes fadeInOpacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.main_header {
color: blue;
text-align: center;
font-size: 30px;
}
.content_top {
height: 300px;
}
<div class="content_top">
<div class="main_header"><span class="vertical_line"></span>
<p data-transkey="main_header_notrans"><span class="tino">Some header</span> <br> some text</p>
</div>
</div>
.content_top has a background-image, which I want to fade in when the page loads, but I do not want the .main_header to be affected aswell. Currently this leads to a flicker effect of the text in .main_header and looks bad.
Here is a working example: JsFiddle
Move the background to a new div inside of the .content_top element. This will create a new layer which we can animate without affecting the content.
Give .content_top and .main_header a position: relative value. This will make the .content_top a relative container, and give .main_header the possibility to use the z-index.
In the snippet below I've added a new element: .main_bg. This element will get the background image and the animation.
Give the .main_bg element a position: absolute;. This will allow you to overlay elements on top of each other, in this case .main_bg and .main_header.
setTimeout(function() {
// Set BG image
var bg_content = document.querySelector('.main_bg');
bg_content.style.background = "linear-gradient(0deg,#000 0,rgba(0,0,0,.7) 35%,rgba(0,0,0,.4) 50%,rgba(0,0,0,0) 100%),url(https://upload.wikimedia.org/wikipedia/commons/8/8f/Example_image.svg) no-repeat";
bg_content.style.backgroundSize = "cover";
bg_content.style.backgroundPosition = "center";
bg_content.classList.add("fade-in");
}, 1500);
.fade-in {
opacity: 1;
animation-name: fadeInOpacity;
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 0.5s;
}
#keyframes fadeInOpacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.main_bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.main_header {
position: relative;
color: blue;
text-align: center;
font-size: 30px;
z-index: 1;
}
.content_top {
height: 300px;
position: relative;
}
<div class="content_top">
<div class="main_bg"></div>
<div class="main_header"><span class="vertical_line"></span>
<p data-transkey="main_header_notrans"><span class="tino">Some header</span> <br> some text</p>
</div>
</div>

Animating a diagonal line from corner to corner

I am trying to animate a diagonal line across the page from one corner to another. The line should be diagonal no matter the format of the screen. I figured (or so I think) that I have to use transform: rotate() in CSS. Using jquery or Javascript, I tried returning and calculating the degree at which the line has to rotate for the given screen format. That argument should be passed to rotate().
I've tried the following with jQuery and Javascript:
<script>
$('#move').css('transform', 'rotate(-' + Math.atan2($(window).width(), $(window).height()) + 'rad)').show();
</script>
or
<script>
document.querySelector('#move').style.transform = Math.atan2($(window).width(), $(window).height())+'rad';
</script>
And with CSS and HTML:
<style>
#move {
width: 0;
height: 4px;
background: red;
position: relative;
animation: mymove 3s;
animation-fill-mode: forwards;
transform-origin: top left;
}
#keyframes mymove {
from {top: 0; transform: rotate(0deg);}
to {width:100%; background-color: blue;}
}
</style>
<body>
<div id="move"></div>
</body>
The code draws a line across the screen, but it is not rotated.
How can that be fixed?
You have to put your <script> to the very bottom of <body>, so the code works after your DOM is loaded.
const move = document.querySelector('#move')
const angle = Math.atan2(document.documentElement.clientHeight, document.documentElement.clientWidth);
const width = document.documentElement.clientWidth / Math.cos(angle);
move.style.setProperty('--a', angle + 'rad');
move.style.setProperty('--w', width + 'px');
html, body, #move {margin:0; padding:0}
#move {
width: 0;
height: 4px;
background: red;
position: relative;
animation: mymove 3s;
animation-fill-mode: forwards;
transform: rotate(var(--a));
transform-origin: top left;
}
#keyframes mymove {
to {
width: var(--w);
background-color: blue;
}
}
<div id="move"></div>

start second animation css at position of first animation css

I need to chain two animations in my interface HTML/CSS on user event (here just a click on the document). The first animation start correctly, but when I want to restart the second animation nothing move ?
I know if i remove the .rotaiotn class and with a timeout put other animation class for the element, the second animation start from the first position of the element.
I want to know if exist a solution to start the second animation from the position of the blue ball after the first animation ?
document.addEventListener('click', startAnimation, false);
var isFisrtAnim = false;
function startAnimation(evt) {
var elt = document.querySelector('#blue_ball');
if (!isFisrtAnim) {
elt.setAttribute('class', 'rotation');
} else {
elt.setAttribute('class', 'rotation2');
}
elt.addEventListener("animationend", animationAtEnd, false);
}
function animationAtEnd(evt) {
evt.preventDefault();
isFisrtAnim = !isFisrtAnim;
var elt = evt.target;
// todo here get new position of elt to start another animation
// from the new position after first animation
var new_margin_top = window.getComputedStyle(elt).getPropertyValue('margin-top');
var new_margin_left = window.getComputedStyle(elt).getPropertyValue('margin-left');
console.log('At end new margin-top : ' + new_margin_top + ' - new margin-left : ' + new_margin_left);
// positions are the same of start element ? they are not modify ?
}
#circleNav {
background: rgba(215, 229, 231, 0.4) !important;
margin-top: 100px;
margin-left: 120px;
border-radius: 50%;
width: 335px;
height: 335px;
border: 2px solid #0e6694;
}
img {
max-width: 100%;
}
#blue_ball {
position: absolute;
margin-top: -350px;
margin-left: 165px;
width: 70px;
height: 70px;
border: none;
z-index: 5;
transform-origin: 120px 180px;
}
.rotation {
-webkit-animation: rotation 3s linear;
animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards !important;
}
#-webkit-keyframes rotation {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(240deg);
}
}
.rotation2 {
-webkit-animation: rotation 3s linear;
animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards !important;
}
#-webkit-keyframes rotation2 {
from {
-webkit-transform: rotate(240deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
<h2>
CLICK ON THE BODY TO START ANIMATION
</h2>
<h4>
When the Blue ball stop click an other time to start second animation, but don't work ?
</h4>
<div id="circleNav"></div>
<div id="blue_ball">
<a href="#">
<img id="btn_menu" src="http://mascaron.net/img/mini_rond_logo.png">
</a>
</div>
smaple code on jsfiddle
thanks in advance.
Just one question, in css:
.rotation2 {
-webkit-animation: rotation 3s linear;
animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards !important;
}
should not be:
.rotation2 {
-webkit-animation: rotation2 3s linear; /* <----- here, rotation2
animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards !important;
}
In js part, why not use elem.classList https://developer.mozilla.org/fr/docs/Web/API/Element/classList to manipulate css class property.

How do I animate div with background image along curved path but stop at X percentage

I have been able to animate a div with a background image as well as resize it along the path. However, I am trying to get this CSS-based animation to stop at a certain percentage of the progress.
The premise is to visually show a student her/his progress of completing a varying number of tasks (8 of 12 complete. 68%). That is not a problem with a straight progress bar, but I am looking to use an image of a mountain with a hiker moving along a path. I can get the hiker image from start to end with the following code, but I need it to stop based on the progress of the student.
I am trying to keep this as simple as I can, but do not have to use CSS.
.mtnBg
{
height:306px;
width:450px;
border:1px silver solid;
background-image: url(https://comps.canstockphoto.com/mountain-with-trail-and-sun-retro-style-eps-vector_csp43572145.jpg);
background-repeat: no-repeat;
background-size: 100%;
display:block;
opacity:.18;
z-index:-1;
}
.animSurround {
margin:0;
padding:0;
height:32px;
width:32px;
display:block;
position:relative;
left:140px;
bottom:50px;
border:1px none black;
animation: yAxis 2.8s 1 ease;
}
.anim {
background-image: url(https://www.tenstickers.co.uk/wall-stickers/img/preview/hiker-icon-sticker-8451.png);
background-repeat: no-repeat;
min-height:32px;
min-width:32px;
background-size: 100%;
animation-iteration-count:1;
animation: zoom-move 2.8s ease 1;
animation-fill-mode: forwards;
}
.anim::after {
/* Render dot, and animate along Y-axis */
min-height:96px;
min-width:96px;
}
#keyframes zoom-move {
0% {
transform: scale(3) translateX(calc(0px)) translateY(0px);
opacity: 0.50;
border-radius:32px;
background-color: rgba(256 , 256, 256, 1);
}
25% {
transform: scale(2.6) translateX(60px) translateY(-19px);
opacity: 1;
border-radius:32px;
background-color: rgba(256 , 256, 256, 1);
}
50% {
transform: scale(1.7) translateX(68px) translateY(-50px);
opacity: 1;
border-radius:32px;
background-color: rgba(256 , 256, 256, 1);
animation-play-state: paused;
}
93% {
background-color: rgba(256 , 256, 256, 1);
}
99% {
transform: scale(1.1) translateX(161px) translateY(-122px);
opacity: 1;
border-radius:32px;
background-color: rgba(76, 175, 80, 1);
}
100% {
transform: scale(1.1) translateX(161px) translateY(-122px);
opacity: 1;
border-radius:32px;
background-color: rgba(76, 175, 80, 1);
}
}
<div class="mtnBg"></div>
<div class="animSurround">
<div class="anim"></div>
</div>
Any help would be appreciated.
You can rely on the animation-play-state property. The is idea to convert the % value to the time when the animation should be paused. So you using JS/jQuery you run the animation and after this amount of time you set the property animation-play-state:
Here is an example with a simplied animation:
/* if we want the animation to run until 10%
we consider a duratioon of Xs and we should run until 0.1 * Xs
The duration will only affect the speed
so use a small value to simulate an instant change.
*/
var duration = 3;
function stop_animation(element, percent) {
var stop = (percent / 100) * duration; /* we get the value un second*/
stop *= 1000 /* we transform to milliseconds */
element.css('animation', 'anim ' + duration + 's linear');
setTimeout(function() {
element.css('animation-play-state', 'paused');
}, stop);
}
stop_animation($('.element').eq(0),50);
stop_animation($('.element').eq(1),20);
.container {
width: 200px;
height: 50px;
border: 1px solid;
border-left: 0;
background: linear-gradient(to right, #000 10%, transparent 11%) 0 0/20px 100%;
}
.element {
height: 100%;
width: 20px;
margin-left: 0;
background: red;
}
#keyframes anim {
from {
margin-left: 0;
}
to {
margin-left: calc(100% - 20px);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="element"></div>
</div>
<div class="container">
<div class="element"></div>
</div>

Categories