I'm learning browser rendering to understand render process and event loop. I always thought translate3d is faster by GPU render with new layer.
today I test in chrome watching by Performance tool tab. find below:
translate3d used 105ms
translateX only 49ms
#keyframes move {
100% {
transform: translateX(300px);
}
}
#keyframes move3d {
100% {
transform: translate3d(300px, 0, 0);
}
}
Related
I am creating a shoe shop website for CV. I have multiple items rendered on home page, with option to add to cart. When user clicks on add to cart, I want to animate the element's picture to go towards the cart which is in header. I am able to start the animation using element's relative position, but I can't figure out how to get elements with different relative positions to end up going to the same place? For now I can get them to go up and away, but I want them to precisely to the CART. (for example, like in Humble bundle page).
I see people providing solutions by using jquery's animate, but I my app is react-based, so I'm trying to avoid jquery if possible.
#keyframes item-to-card-animation{
0%{
position: relative;
opacity:100%;
top:0px;
left:0px;
transform: scale(1);
}
99%{
top:-1000px;
left:100px;
transform: scale(0.2);
z-index:100;
}
100%{
opacity:0%;
}
}
Ok, so if anyone stumbles upon this. I cloned an element in javascript, then put inline positions from javascript(since you can access it from there), then animated it using absolute positioning.
const bodyRect = document.body.getBoundingClientRect();
const elemRect = document.getElementById(this.state.itemToCart._id).getBoundingClientRect();
const top = elemRect.top - bodyRect.top;
const left = elemRect.left - bodyRect.left;
let cloneItem = document.getElementById(this.state.itemToCart._id).cloneNode(true);
cloneItem.style.position = "absolute";
cloneItem.style.top = top + "px";
cloneItem.style.left = left + "px";
cloneItem.classList.add('item-to-card-animation');
document.querySelector('#root').appendChild(cloneItem);
setTimeout(() => {
cloneItem.remove();
},1000)
#keyframes item-to-card-animation{
0%{
opacity:100%;
transform: scale(1);
}
99%{
top:-150px;
left:1150px;
transform: scale(0.2);
z-index:100;
}
100%{
opacity:0%;
}
}
I'm trying to make a starring night with twinkling stars in css3 + Javascript, however, my animation is consuming a lot of CPU, the main animation:
#for $i from 0 through 400 {
.star:nth-child(#{$i}) {
$star-size: (random() * (1-4) +4) + px;
top: (random(100)) + vh;
left: (random(100)) + vw;
width: $star-size;
height: $star-size;
animation: blinker 1.2s alternate infinite ease-in-out;
animation-delay: (random(30) / 10) + s;
transform: scale(0.2);
}
}
#keyframes blinker {
100% {
transform: scale(1);
}
}
the full code: https://jsfiddle.net/sam7krx0/
is there any way to make this code perform better?
Edit:
tried with translateZ(0) and with will-change: transform but the animation still being rendered by the CPU.
https://jsfiddle.net/8hn97kcx/2/
Edit 2:
It seems that firefox might be the problem, while testing on chrome the animation uses way less CPU.
Edit 3:
profile of the fiddle above running on firefox developer edition 69.0b4:
firefox profile
CPU usage:
Have you tried using the will-change property - this helps the browser know about the change and offload it to the compositor if possible.
The OP code was horrendously inefficient in that it uses 400+ uniquely generated selectors. So the bulk of the processing time involves maintaining the CSS animation loop and looking up 400+ classes on each alternation of said CSS animation. This is a rare case wherein class selectors are a burden and not useful. Since each s.star needs these unique styles, it would take less computing power to generate the CSS property values on a template literal and then assign it to the tag as an inline-style. (See Demo)
Besides doing away with ridiculously huge .class lists on a bloated stylesheet, the demo makes full use of a documentFragment. DOM operations are expensive on resources (imagine 400+ tags being appended to one location). Doing everything on the fragment, then finally to the DOM by 👍appending documentFragment just once and 400 .star are in the DOM👍. The OP code on the other hand 👎will append 400 s.star one at a time... that's 400+ DOM operations.👎
Also on the OP code it is deceiving as to the size of the actual CSS. SCSS, a post-processor is used, so what looks like 8 lines of weird looking CSS is actually 👎3200 lines of CSS👎 after it has been compiled and cached by the browser. The CSS in the demo is what it appears to be ...👍9 lines👍 for .star selector.
/**| documentFragment
- The only global variable points to a documentFragment not attached to the DOM.
- Use fragment as you would a document object when moving, creating, destroying,
appending, detaching, etc... HTML element tags from and to the DOM. Doing so will
greatly improve processing times when adding 400+ uniquely styled tags.
- When all .star tags have been created, modified, and appended to the fragment --
only the fragment itself needs to be appended to the DOM instead of 400 tags.
*/
var fragment = document.createDocumentFragment();
/**| randomRange(min, max, integer = false)
#Params: min [number].....: The minimum
max [number].....: The maximum
integer [boolean]: default is false which results will be floats.
If true then results will be integers.
Utility function that will return a random number from a given range of consecutive
numbers.
*/
const randomRange = (min, max, integer = false) => {
let numbers = integer ? {
min: Math.ceil(min),
max: Math.floor(max)
} : {
min: min,
max: max
};
return Math.random() * (numbers.max - numbers.min + 1) + numbers.min;
};
/**| starGenerator(limit)
#Params: limit [number]: The number of s.star to generate.
A generator function that creates s.star tags. Assigning individual tag properties
and setting randomly determined values would involve a ton of unique selectors.
To avoid a ton of lookups in a CSS stylesheet a mile long, it's easier to create and
maintain one template literal of the CSS properties interpolated with random values.
Each s.star would be assigned an inline-style of five CSS properties/values by one
statement via `.cssText` property.
*/
function* starGenerator(limit) {
let iteration = 0;
while (iteration < limit) {
iteration++;
const star = document.createElement("s");
star.classList.add("star");
let properties = `
width: ${randomRange(1, 4)}px;
height: ${randomRange(1, 4)}px;
top: ${randomRange(0, 100, true)}vh;
left: ${randomRange(0, 100, true)}vw;
animation-delay: ${randomRange(1, 30, true) / 10}s`;
star.style.cssText = properties;
yield star;
}
return fragment;
}
/**| nightfall(selector, limit = 400)
#Params: selector [string]: Target parent tag
limit [number].. : The maximum number of s.star to generate.
Interface function that facilitates DOM procedures with minimal presence in DOM.
*/
const nightfall = (selector, limit = 400) => {
const base = document.querySelector(selector);
base.classList.add('sky');
for (let star of starGenerator(limit)) {
fragment.appendChild(star);
}
return base.appendChild(fragment);
};
// Call nightfall() passing the selector "main"
nightfall("main");
.sky {
position: relative;
background: #000;
height: 100vh;
overflow: hidden;
}
.star {
display: block;
position: absolute;
animation: twinkle 1.2s alternate infinite ease-in-out;
transform: scale(0.2);
border-radius: 50%;
background: #fff;
box-shadow: 0 0 6px 1px #fff;
z-index: 2;
text-decoration: none;
}
#keyframes twinkle {
100% {
transform: scale(1);
}
}
<main></main>
That's because the rendering is done by CPU which can be a loose in performance. There is an option in CSS to run such an animation on GPU.
Your snippet adjusted
#for $i from 0 through 400 {
.star:nth-child(#{$i}) {
$star-size: (random() * (1-4) +4) + px;
transform: translateY((random(100)) + vh) translateX((random(100)) + vw) translateZ(0);
width: $star-size;
height: $star-size;
animation: blinker 1.2s alternate infinite ease-in-out;
animation-delay: (random(30) / 10) + s;
transform: scale(0.2);
}
}
#keyframes blinker {
100% {
transform: scale(1);
}
}
It's very important to add translateZ because only 3D renderings are done by GPU.
Doing animations on GPU is also called accelerated animations, please check this helpful article for more information about: https://www.sitepoint.com/introduction-to-hardware-acceleration-css-animations/
it's not only problem with you code.
it's also from your CPU ability, trying to upgrade your CPU and RAM to perform better.
sometimes you can't build mid - high animation in low spec computer.
I'm trying to get a div to move from one end of the screen to the other on a loop.
My javascript currently only attempts to move the div left but doesn't work.
var func = function() {
$("#bob").animate({"left": "-40px"}, 1000, function() {
$(this).animate({"left": "40px"}, 1000)
})
setTimeout(func, 2000);
}
Here is my jsfiddle:
http://jsfiddle.net/zsal/N48Eg/1/
Name your functions, and then use one as the completion callback in the other:
function goLeft() {
$('#bob').animate({'left': '-40px'}, 1000, goRight);
}
function goRight() {
$('#bob').animate({'left': '40px'}, 1000, goLeft);
}
goLeft();
So, when it's done going left, it should go right. When it's done going right, it should go left.
Disclaimer: Untested
P.S. You're missing jQuery in your Fiddle.
Your current fiddle doesn't work because you didn't include jQuery (from the Frameworks & Extensions drop-down on the left) and because you define the func() function but never actually call it. Fix those two things and it will work as shown here: http://jsfiddle.net/N48Eg/8/
Note, however, that your animation code is more complicated than it needs to be. Multiple animations on the same element will be queued automatically by jQuery, so you don't need to use a callback on the first one to start the second. And you can supply func as the callback on the second and avoid the setTimeout() completely:
var func = function() {
$("#bob").animate({"left": "-40px"}, 1000)
.animate({"left": "40px"}, 1000, func);
}
func();
Demo: http://jsfiddle.net/N48Eg/18/
You just haven't called your function...
var func = function() {
$("#bob").animate({"left": "-40px"}, 1000, function() {
$(this).animate({"left": "40px"}, 1000)
})
setTimeout(func, 2000); // added back
}
func();
Your updated fiddle
First of, if you want the motion to continue, you need to use setInterval instead of setTimeout
Also you need to either move the setInterval out of the scope of func, or call func to start the animation
lots of problems. Heres a fiddle with a solution.
you also forgot to position:relative your absolutely positioned elements container.
JSFIDDLE
you weren't calling your function for starters
i made a new one called moveBob()
Here's the pure CSS version. http://jsfiddle.net/zDSRd/
#bob
{
position:absolute;
animation: fly 2s linear 0s alternate infinite;
-webkit-animation: fly 2s linear 0s alternate infinite;
-moz-animation: fly 2s linear 0s alternate infinite;
-o-animation: fly 2s linear 0s alternate infinite;
-ms-animation: fly 2s linear 0s alternate infinite;
}
#keyframes fly {
from { transform: translateX(0px); }
to { transform: translateX(500px); }
}
#-webkit-keyframes fly {
from { -webkit-transform: translateX(0px); }
to { -webkit-transform: translateX(500px); }
}
#-moz-keyframes fly {
from { -moz-transform: translateX(0px); }
to { -moz-transform: translateX(500px); }
}
#-o-keyframes fly {
from { -o-transform: translateX(0px); }
to { -o-transform: translateX(500px); }
}
#-ms-keyframes fly {
from { -ms-transform: translateX(0px); }
to { -ms-transform: translateX(500px); }
}
I'm using CSS3 Animations, and I want to be able to move to a specific spot in the animation. For instance, if the CSS looks like this (and pretend that I used all the proper prefixes):
#keyframes fade_in_out_anim {
0% { opacity: 0; }
25% { opacity: 1; }
75% { opacity: 1; }
100% { opacity: 0; }
}
#fade_in_out {
animation: fade_in_out_anim 5s;
}
then I would like to be able to stop the animation, and move it to the 50% mark. I guess that the ideal JavaScript would look something like this:
var style = document.getElementById('fade_in_out').style;
style.animationPlayState = 'paused';
// Here comes the made up part...
style.animation.moveTo('50%'); // Or alternately...
style.animationPlayPosition = '50%';
Does anyone know of a way to make this happen (hopefully in Webkit)?
We can use the animation-delay property. Usually it delays animation for some time, and, if you set animation-delay: 2s;, animation will start two seconds after you applied the animation to the element. But, you also can use it to force it to start playing animation with a specific time-shift by using a negative value:
.element-animation{
animation: animationFrames ease 4s;
animation-delay: -2s;
}
http://default-value.com/blog/2012/10/start-css3-animation-from-specified-time-frame/
i am currently making my own 1-page portfolio website for school and i had this cool idea that i want to show how far ive become in some coding languages by using a progressbar, for example, c# = 60% and that would be 60% of a circle. i think i can do that bu using the internet but i would like it to start / end at 60 when i'm scrolling down and it should start the progressbar when it is on screen. i do not know and cannot find on how to trigger the code when the (in this case progressbar) is visible on screen.
note: i am a fairly new javascript programmer and a fairly new user so please explain if i did something wrong.
Here is a working example of triggering an animation when you scroll to 75% of an image's height using the Intersection Observer API:
const images = document.querySelectorAll('.animate-me');
const config = {
root: null, // viewport
rootMargin: '0px',
threshold: 0.75
};
let observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.intersectionRatio >= config.threshold) {
entry.target.classList.add("active");
}
});
}, config);
images.forEach(image => {
observer.observe(image);
});
.spacer {
height: 400px;
}
.animate-me.active {
animation: anim1 .7s ease-out;
}
#keyframes anim1 {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<div class="spacer">(Scroll down)</div>
<img src="https://picsum.photos/200" class="animate-me">
<div class="spacer"></div>
You should be able to translate this to your own use case, but please share more specifics if you are looking for something else.