How to manipulate CSS #keyframes through JavaScript? - javascript

I have a simple CSS animation:
<div id="saved-test">
<style type="text/css">
#saved-test {
width: 40px; height: 40px;
background: red;
position: fixed;
top: 0; left: 0;
animation-name: move-to-bottom;
animation-duration: 5s;
z-index: 1000;
}
#keyframes move-to-bottom {
to {
left: 400px;
top: 500px;
}
}
</style>
This works, and it moves as I want nicely. The issue I have, is that I want to set the destination of this element to be different. It will be "moving" to a bottom nav bar, which means the destination left/top positions will vary depending on screen size.
Is it possible to modify the left and top value in the keyframe via Javascript, so it goes to a set position that I set dynamically?

You can write the keyframe entirely with JavaScript as below, which gives you the ability to use dynamic values.
The Element interface's animate() method is a shortcut method which creates a new Animation, applies it to the element, then plays the animation. It returns the created Animation object instance. More and MDN's doc.
document.getElementById("saved-test").animate(
[
// étapes/keyframes
{
left: "0px",
top: "0px"
},
{
left: 400 + "px", // you can set it dynamically
top: 500 +"px" // you can set it dynamically
}
],
{
duration: 5000,
iterations: Infinity
}
);
#saved-test {
width: 40px;
height: 40px;
background: red;
position: fixed;
z-index: 1000;
}
<div id="saved-test">

Related

Better solution for animating width

I have a block over a text and i want to reveal the text and make the width of the block zero
I'm using gsap but as far as i know it is bad for performance to animate width,
and since i'm gonna use this animation quite a lot i'm worried to animate width
so is there is a better solution for my little problem ?
gsap.to('.block', {
duration: 1, width: 0, ease: Power4.easeIn}, 0.2);
h1 {
position: relative;
display: inline-block
}
.block {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
background: black;
width: 100%;
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.6/gsap.min.js"></script>
<h1>
hello world
<span class="block"></span>
</h1>
You can consider an animation using transform and have better performance
gsap.to('.block', {
duration: 1, transform: 'translateX(-100%)', ease: Power4.easeIn}, 0.2);
h1 {
position: relative;
display: inline-block;
overflow:hidden;
}
.block {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
background: black;
width: 100%;
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.6/gsap.min.js"></script>
<h1>
hello world
<span class="block"></span>
</h1>
The only thing I can think of to increase the performance while still using Gsap is to lower the duration of the width transition of the block, as well as lower the fps of the animation by adding gsap.ticker.fps('framerate') to the javascript.
the default framerate is 60 fps, so try changing it to anything lower than that. Though I'm not entirely sure if that would make a huge improvement.
gsap.ticker.fps(24);
//caps framerate at 24
gsap.to('.block', {duration: 0.5, width: 0, ease: Power4.easeIn}, 0.2);
h1 {
position: relative;
display: inline-block;
}
.block {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
background: black;
width: 100%;
height: 100%;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.6/gsap.min.js">
</script>
<h1>
hello world
<span class="block"></span>
</h1>
</body>
</html>
There definitely is a solution in animation properties of CSS. Using CSS instead of
JavaScript (JS) will delegate computing the animated values to the browser's layout engine instead of re-implementing them in your code.
At a high level your animation will be a from, to state where the from is full
width and to is 0 width. You express this with a #keyframe rule where you can animate ANY CSS property. This way you can combine #keyframes on different properties.
These are some good introductory notes about animations in CSS css-animation-101, using CSS animations
For you particular use case something like this should do
#keyframes unveil {
from {
width: 100%;
}
to {
width: 0%;
}
}
.block {
animation-name: unveil;
animation-duration: 1s;
animation-timing-function: ease-in;
}
Then you can either add the block class to the span directly in the HTML or use some JavaScript to toggle/add the class in response to an event.
You can use css animations:
function toggleAnimation() {
$('.block').toggleClass("animated");
}
h1 {
position: relative;
display: inline-block
}
.block {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
background: black;
width: 100%;
height: 100%;
}
#keyframes custom-animation {
from {
width: 100%;
}
to {
width: 0%;
}
}
.block.animated {
animation: custom-animation 1s ease-in 0.5s 1 normal forwards;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>
hello world
<span class="block"></span>
</h1>
<button onclick="toggleAnimation();">Toggle animation</button>
In my sample, the block needs the animated class to actually animates. For the demo, I used a button to add this class.

Conflicting javascript or too many mouseover events?

Currently, I have layered 4 images on top of a background image. When your mouse hovers over each image, it disappears until the user refreshes. I would like to create 26 clones of an image. Ideally, I could position each image copy and the jquery would autogenerate id names like so (#myid(n)) a.k.a #myid1, #myid2. As I am unable to pull this image cloning off so far, I have to copy and paste each block of code over and over again. However, once I added my sixth image, I encountered performance problems, and my code stopped working.
I have included two codepens. This codepen works with 4 image copies : https://codepen.io/narutofan389/collab/NWGpQWo
This codepen doesn't work with 6 copies: https://codepen.io/narutofan389/collab/MWapQyO
I have heard too many mouseover events can create performance issues. I am not sure if this is what the source of my issues. I am also trying on a separate codepen to test image cloning with separate ids. This is the code so far taken from another stack overflow answer:
html
<body>
<div id="sand"></div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
javascript
$(document).ready(function(){
for (var i = 0; i < 2; i++) {
var img = "<img src ='https://s3-us-west-2.amazonaws.com/s.cdpn.io/4405662/sandsmaller.png'
id='myid"+i+"'/>";
$("body #sand").append(img);
}
})
Again I am trying to generate different ids that I can position individually?
Since your cloning snippet is in jQuery, I hope a solution using it is acceptable.
First I had to add a #sand container missing from your markup, as it's where the code is appending the images. Also added a div wrapper to each image to mirror your codepen (although you might not need it), and added a sand class to the images.
Then, instead of adding an event for each element, I used Event delegation so I can attach just one handler to the wrapping element. I'm targeting all images inside the #sand container that are not already hidden.
And then simplified the css a bit removing redundant rules and moving common properties to the new classes.
for (let i = 1; i <= 6; i++) {
// Create the wrapping div
var $container = $("<div class='sand" + i + "'>");
// Create the img
var $img = $("<img src ='https://s3-us-west-2.amazonaws.com/s.cdpn.io/4405662/sandsmaller.png' class='sand' id='sand" + i + "'/>");
// Add image to container
$container.append($img);
// Add container to the document
$("body #sand").append($container);
}
// Listen when the mouse hovers an image
$('#sand').on('mouseenter', 'img.sand:not(.hide)', function() {
$(this).addClass('hide');
});
$('#sand').on('animationend', 'img.sand.hide', function() {
$(this).hide();
});
html {
background: url(https://i.postimg.cc/HWJvtDGx/lockcorrect.jpg) no-repeat center center fixed;
background-size: cover;
height: 100%;
overflow: hidden;
}
#bg {
position: fixed;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
}
#bg img {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
min-width: 50%;
min-height: 50%;
}
#-webkit-keyframes fade {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
#-moz-keyframes fade {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
#-o-keyframes fade {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
#keyframes fade {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.sand {
position: absolute;
height: 90vh;
}
#sand6 {
top: 0px;
right: 200px;
}
#sand5 {
top: 300px;
left: 500px;
}
#sand4 {
top: 300px;
right: 200px;
}
.hide {
animation: fade 3s;
animation-fill-mode: forwards;
}
#sand3 {
height: 100vh;
top: 0px;
left: 700px;
}
#sand2 {
height: 100vh;
top: 0px;
left: 300px;
}
#sand1 {
position: relative;
height: 100vh;
right: 30px;
}
<div id="bg">
<img src="https://i.postimg.cc/HWJvtDGx/lockcorrect.jpg
" alt="lock">
</div>
<div id="sand">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Moving the whole page to left and then right

i am looking for this kind of template . Moving the page to left and then page to right. Can anyone tell me how can i make this or is there any javascript example similar to this.
Create two <div>s, put them next to each other, make them take up the whole window, and change them as needed.
HTML:
<div class="left">left</div>
<div class="right">right</div>
CSS:
body {
margin: 0;
}
.left {
background-color: green;
bottom: 0;
left: 0;
position: fixed;
top: 0;
transition: width 1s;
width: 0;
}
.left.active {
width: 200px;
}
.right {
background-color: red;
bottom: 0;
left: 0;
position: fixed;
right: 0;
top: 0;
transition: left 1s;
}
.right.active {
left: 200px;
}
JS (width jQuery):
$('.right').on('click', function() {
$('.left').toggleClass('active');
$('.right').toggleClass('active');
});
And here's a fiddle.
Using .toggle(effect,options,duration) method to moving the page to left to right.
// Set the effect type
var effect = 'slide';
// Set the options for the effect type chosen
var options = { direction: 'right' };
// Set the duration (default: 400 milliseconds)
var duration = 700;
$('#Id').toggle(effect, options, duration);
Taken via this link
If you want it to animate smooth on all devices you should use css transitions and transforms. Hiding and showing would be as basic as toggling a class then.
The example in jsfiddle
<style media="screen">
.wrapper {
width: 100%;
overflow: hidden;
}
.menu {
height: 100vh;
width: 100px;
background: #ABC;
color: white;
position: absolute;
left:0;
transition: transform 0.3s;
transform: translateX(-100px);
}
.content {
transition: transform 0.3s;
}
.active .menu {
transform: translateX(0);
}
.active .content {
transform: translateX(100px);
}
</style>
<button class="toggle">Toggle</button>
<div class="wrapper">
<div class="menu">
My menu
</div>
<div class="content">
My content
</div>
</div>
<script type="text/javascript">
document.querySelector('.toggle').addEventListener('click', function(event) {
event.preventDefault();
document.querySelector('.wrapper').classList.toggle("active");
});
</script>
NB! Supported from IE10. IE 9 will support without the animation and you probably should add the needed -ms-, -webkit-, -moz-, etc prefixes to support the older browsers if needed for transition and transform properties.
Also I advise not animating body or html with this method and put the content of page in the wrapper (in .content in the examples case). Moving body and html directly may lead to unpleasant surprises later.

Cover entire page with layer

I have pretty complicated one page application, which loads abot 20 seconds.
During loaiding I would not like to show page to user.
So, I have created a layer with 100% height and 100% width, maximum z-index and position absolute. I append this layer before loading starts to the body.
$(loaderHTML).appendTo('body');
#mainLoader {
z-index: 1000;
width: 100%;
height: 100%;
background: rgb(32, 35, 42);
position: absolute;
top: 40px;
}
Layer does the job - it covers the whole page in the beginning, but then, when new elements are created on the page and height of the page becomes bigger, users see not covered elements at the bottom.
How can I make layer that covers whole page even if page changes it's height?
EDIT: absolute position doent't work, but fixed does. Dont't know why
#mainLoader {
z-index:1000 ;
width:100 %;
height:100 %;
background: rgb(32 ,35 ,42 );
position: fixed;
top: 0%;
left: 0%;
overflow: hidden;
}
try this
#mainLoader {
z-index: 9999;
background: rgb(32, 35, 42);
position: absolute;
top: 40px;
bottom: 0;
left: 0;
right: 0;
}

Show div expanding out from middle out in jquery

I want to show my div when the user generates the trigger. The animation which I want to use showing the div is such that the div is rendered starting from its centre and then gaining its height by expanding in both directions(up and down) gradually. Here is the snippet of what I have tried. The div starts rendering from left. What I want is it starts rendering from middle of its height.
$("#km1").click(function() {
$(".homePopup").animate({
width: "730px",
height: "200px"
}, 800);
})
.homePopup {
position: absolute;
z-index: 100;
width: 400px;
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Know more
<div class="homePopup"></div>
You could animate the margin as well to achieve this effect.
Set the initial margin-top and margin-bottom half of the final height; and margin-left and margin-right half of the final width. Then when you increase the width and height, decrease the margin as well.
$("#km1").click(function() {
$(".homePopup").animate({
width: "730px",
height: "200px",
margin: '0'
}, 800);
})
.homePopup {
position: absolute;
z-index: 100;
width: 0px;
margin: 100px 365px;
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Know more
<div class="homePopup"></div>
I divided the width and height by four to and added that to the left and top to obtain the center animation requested.
$("#km1").click(function() {
$(".homePopup").animate({
width: "730px",
height: "200px",
left: "0px",
top: "0px"
}, 800);
})
.homePopup {
position: absolute;
z-index: 100;
width: 400px;
background-color: red;
left: 182px;
top: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Know more
<div class="homePopup"></div>
You need to position the element in the middle from the beginning. I'm setting the left absolute position to 50%, then moving the element back -50% of itself so that it is in the middle.
Check out CSS transform:
http://css-tricks.com/almanac/properties/t/transform/
$("#km1").click(function() {
$(".homePopup").animate({
width: "730px",
height: "200px"
}, 800);
})
.homePopup {
position: absolute;
z-index: 100;
width: 0;
background-color: red;
left: 50%;
transform: translateX(-50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Know more
<div class="homePopup"></div>
******UPDATE******
Here is the css to run the animation from the middle of the window's height:
.homePopup {
position: absolute;
z-index: 100;
width: 0;
background-color: red;
top: 50%;
transform: translateY(-50%);
}

Categories