I'm looking for the best way to animate several divs onscreen. I tried jQuery, but it started getting skippy after I had > 5 elements on the screen. Raphael.js gave me the same problem. So, what is the best way to animate 5-6 divs on a screen at once? They're just moving horizontally across the screen.
Would CSS3's translate2d be good for this? I recall reading somewhere that you can severely optimize performance by using translate3d instead. Is that applicable in my case?
If your target browsers support CSS3, you can achieve much smoother animations using translate2d. If you need to animate all items together (i.e. the animation rules are the same for each one of them), you can just create a class
.animTarget{animation:translate3d(100, 0, 0)}
And then in your javascript code, say:
$("animation-target-selector").addClass('animTarget')
I have found that animating things like this is easier than doing something like:
$("animation-target-selector").css('animation', 'translate3d(100, 100, 0)');
Because it adds it to the style attribute of each and every dom element.
Related
It is possible to have 2 sticky elements on top of each other? Or use one of them as a background?
TLDR; I was able to make this work with a library (StickyKit) that does what I'm looking for, but performs badly with new async scrolling.
Example
JSFiddle with StickyKit - https://jsfiddle.net/cibulka/4nd3b0tt/ - (this does what I'm describing, but performs poorly, see below)
How I did it: I wrapped sticky elements in the 200% wrapper, and floated them to left. Then I moved 1 of them (margin-left: -100%) on top of the other. This way they are on top of each other, but still keep their height.
Why this does not work with position:sticky
One of many quirks with position:sticky is that it does not work if any of its parents is overflow:hidden. See this answer for more info: Why does `overflow:hidden` prevent `position:sticky` from working?
What I need to do here is to make the 2 elements overlay somehow without their container be overflow:hidden. Or should I do something else entirely?
What I'm using now
For the time being, I've ditched the "200% container" and set my image container (.sticky.bg, see the fiddle) to height:0. This makes images "stuck", but they do not become "relative" again once user scrolls to the bottom.
This is obviously not ideal.
Background
I was a happy user of StickyKit for a long time. Unfortunately, it does not work very well with asynchronous scrolling, which is employed by more and more browsers to improve performance. With the new Firefox Quantum (57), for example, StickyKit is pretty much unusable.
I've created an issue in StickyKit Github, but package seems to be abandonned by the author: https://github.com/leafo/sticky-kit/issues/252
Because of that, I am forced to deprecate StickyKit and move to native position:sticky (polyfilled with StickyFill). Unfortunately there is a couple of things position:sticky can't do and this is one of them.
There is also another issue I'm having with position:sticky: Position sticky: scrollable, when longer than viewport
What I'm looking for
A recommendation, basically, how to approach this issue. I'm up for using different JS/jQuery library, writing my own code or use some quirky CSS hack to hack position:sticky functionality.
Thanks in advance!
Introductory information:
I've made a fixed menu button to show the navigation menu when using a mobile device. For this application I'm using the Headroom.js script to make the button smaller when scrolling downwards to ensure that it doesn't block too much of the content. The animation/transition is applied by adding a class with the given changes.
In the original method i changed the size and look of the button by changing height/width of the parent element and padding of the child element with CSS (and css transition).
The new method, which I've read could/should be better according to various sites, is changing the size of the button by using transform: scale(). Note that i'm also moving the element a bit by also applying translate3d(20px,20px,0) in this method. However, it feels a bit smoother when scrolling using the transform: scale() method (could be a placebo effect though), but using chrome dev tools' timeline gives me seemingly inconclusive results.
Therefore a part of my question is also how I should evaluate the best method. Is timeline in Chrome Dev tools the best option, or is there a better way to do it? And which elements of the timeline should I base my choices on? and the other thing is, based on your interpretation of the images and/or tests combined with your knowledge, which method performs the best (or should perform the best in theory)?
Beneath you can see two examples of the timeline with each method.
Changing height/width and padding (original method):
Method using transform: scale() to change the size:
Also you can try the different methods in fiddles here:
link: Original method changing height/width and padding
link to new method: using transform:scale
Please ignore the poor layout of everything; especially the button. The ugly image inside the menu button is just to show, that there's an image included in the layout on my own page and to take that into performance considerations. The images in the back is also included since it's a webshop with a lot of images which could influence performance.
CSS for added class that makes the changes in the original method:
.mobile-nav.headroom--unpinned {
height: 40px;
width: 40px;
}
.headroom--unpinned .mobile-content{
padding-top:4px;
}
CSS for the added class using transform:scale():
.mobile-nav.headroom--unpinned {
transform:scale(.5) translate3d(20px,20px,0);
}
So to summarize my questions:
How do I evaluate which methods has the best performance, and which method would you say performs the best?
A final note: I know that the methods are different (animating different things and more elements in the original method) but these are the 2 options which i prefer as it is right now.
I believe you are missing the point, Chris: the reason why no other property but transform and opacity should ever be animated is because they don't trigger a repaint in anything else, even if the element is in the document flow (and because you can basically do anything with these two alone in like 95% of the cases).
From the "hit-on-performance" point of view, there are two types of animations:
those that trigger a repaint in other elements than the animated element
those that do not.
That's the main reason behind recommending animations by transform, opacity or position:relative;left|right|top|left. Because they don't actually move the element in flow, thus not triggering a repaint to every single other element in flow after the one being animated.
Now, if the said parent was positioned absolute (which I assume to be the case), it wouldn't have triggered a repaint to the rest of DOM anyway so the differences between that method and transform would have been minor. Inconclusive, as you put it. In theory, repainting two elements instead of one should be slower.
If you need to test, make 10k clones and trigger animation on all of them, with each method.
That will be conclusive.
If you really want to min-max this (as in spend absurd amounts of time on hardly noticeable improvements, as I do) you will find plenty of resources that will recommend:
replacing any .animate() with .velocity()
never animating anything but transform or opacity, although Velocity claims they animate anything without a hit on performance (i find that debatable/arguable, at best) - but it's a net improvement over .animate()
sticking to CSS transitions, if possible (basically if you don't need chains)
using Web Animations API
Personal advice: never count on synced CSS animations, especially when you have many of them. If you change tabs or the system does something extremely resource heavy for a while, your animations will be way off. If you need chains, chain.
I am using CSS animations to move two rectangle div tags across the screen. Each one is like a pole (taller than it is wide). The animations make each div rotate so it is at an angle before going back to pointing upwards.
One animation is triggered by the user, and the other is constantly moving itself towards the other div.
I have tried using getBoundingClientRect() to detect when the corner of one div intercepts the div that is moving towards it. I also used jQuery to get the .position() of them, but they return left: 0.
The div that is moving across the screen is done using the margin-left property.
Are there any methods I should be looking into or does anyone have a solution to a similar problem?
Thanks,
DH
You should use transform: translate to move them.
Also, since you're moving the elements in javascript you should just keep their state stored in memory and do your collision detection entirely in javascript.
There should be no need to use DOM APIs for this.
There's no method on the DOM for you to be able to detect overlapping objects. I would suggest using a geometric model of the scene and doing the trigonometry yourself to see when there is an intersection between the two boxes. Animating your objects explicitly using JS is also easier, since you wouldn't have to worry about getting out of sync with the browser's CSS animations or transitions.
You'd basically be looking for a line-line intersection.
I'm building an AngularJS app and am looking to do something a little tricky with animations that I'm not quite sure how to do. One aspect of the app entails animation between views in a panning manner, but the appearance of a single view needs to be maintained. For example, if there is a scene with a square in the center, on view-change that square would appear to leave the screen as if we were panning across (while other elements enter in), all without it feeling like the view has really changed.
I know that ng-animate provides a lot of powerful animation functionality, but I'm stumped on what the best way to maintain the appearance of a single view while transitioning between them is.
Does anyone have experience trying to do this or know of an animation library that would make this possible?
I'll update this question with possible solutions as I find them.
When a view is added, the following classes are added:
.ng-enter
.ng-enter.ng-enter-active
When a view is removed, the following classes are added:
.ng-leave
.ng-leave.ng-leave-active
You can attach CSS 3 transition styles to the classes to achieve the animation effect you want.
If I understand correctly, the 'leaving' animation should pan left to right, and fade-out, starting from a 0px offset. The 'entering' animation should also pan left to right, but fade-in, starting from a negative offset.
Here is an example:
Plunker Demo
JS FIddle Demo
I have a grid of div boxes that I will be animating. They will be moving across the screen after a user drags one of the boxes (to re-align into a grid).
Currently I am using JQuery to change the css left and top positions of all of the divs and running this on an interval.
It is laggy if there are more than 50 boxes. How do I make this less laggy? Is there an animation library that is better for this, or do I just need to limit it to 50 boxes?
Image of layout:
You have a few options to optimize the performance.
Newer browsers have requestAnimationFrame that lets the browser take care of the animation timing in order to optimize Javascript animations. Rather than using times to perform the animation, which is what jQuery framework uses, you repeatedly a callback to requestAnimationFrame. The browser will call your function with a progress variable for the animation, and you render the current stage of your animation based on the progress variable. requestAnimationFrame for smarting animating talks about this in depth. Google Closure is the only framework I am aware of that uses requestAnimationFrame however, and it's rather heavyweight.
CSS animations. jQuery offers CSS animation, so do many other frameworks. CSS animations give you hardware acceleration, so the animation is much faster. Unfortunately, CSS animations are relatively new and not yet well supported, so you'll probably end up falling back to Javascript animation on older browsers, depending on the library you use.
Optimize your Javascript. Instead of animation each and every box in the grid, encapsulate each row in a div and animate the entire div instead. That should speed the animation up by a bit. I'm sure there are other ways you can optimize based on your current implementation.
Honestly, I don't know of any library that will make this work more efficiently for you, though there are many libraries out there that are faster than jQuery. The issue isn't just the jQuery, its the fact that you have 50 elements that are all moving/draggable, thus requiring a lot of the browser's resources.
If you can post your code there may be a few things that we could suggest to speed it up slightly.
The two biggest things problems that I can think of are if you added those boxes programmatically and added the handler for each as you added the element to the page, and if you don't store your selectors in variables. Aside from that I would have to see the code.
Have a look at:
jQuery isotope
It has options to allow you to use css3 animations if available or use jQuery / JS animations.
Handy for grid like animation and arrangements.
Some brave soul has managed to add drag and drop to isotope too. http://tyler-designs.com/masonry-ui/ (a bit clunky but works)
There are several ways of increasing the performance. One would be to reduce the amount of DOM elements required for each box. Another is to not animate (and render) boxes outside of the current viewport. Give all boxes that are outside of the viewable area "display: none;" and exclude them before starting a new animation. If you want to go even further you can start to recycle boxes instead of showing and hiding them when the user is scrolling through the page.
This way you will always get the same performance no matter how many boxes you have (above the amount that you can fit in the viewport).
This technique is called UI virtualization. There are several projects that use it like: http://github.com/mleibman/SlickGrid/wiki. It's really useful when you need to render a lot of elements (hundreds, thousands, millions). But it takes quite some work to get it right. And I don't know about any generic working components that are easy to plug in. I tried to find an article that explains it. This is the only thing I could come up with for now, it's for Silverlight though: http://www.silverlightshow.net/items/Virtualization-in-Silverlight-4-RC.aspx
Also try this this plugin for jQuery. Use the regular 'animate' method and it will try to use (hardware accelerated) CSS animations where possible: http://playground.benbarnett.net/jquery-animate-enhanced/