Changing webkit transtion speed during transition - javascript

I need to smoothly scroll a large amount of text up the screen. Using webkitTransform does this very well, but I would also like to enable the user to change the speed of the scrolling or pause the scrolling based on how fast they're reading. From what I've found, there isn't a way to change the duration of a webkit transition once it has started. Using setInterval and moving the text works, but it gets jumpy and hard to read as the speed increases.
Can anyone recommend a good way to do this that would allow for the user to adjust speed and still give readable text at higher speeds?

I don't know much about modifying currently running CSS3 transformations, but as an alternative solution, I would scroll a large amount of text with JavaScript by using the browser's native scrolling with scrollTop (.scrollTop() if you are using jQuery).
This allows the user to have a familiar interface even without JavaScript, and can be simply implemented with setTimeout() or setInterval(). If the final result is too jumpy, try modifying scrollTop in smaller intervals, but faster. (i.e., instead of adding +100 every 500ms, try adding +10 every 50ms)

Related

Is there a fluid CSS height property for elements entering the DOM? Jank happens when using Semantic-UI-React Transitions

I am not sure if this is the proper place to ask this question; I considered Software Recommendations however I figured I'd give it a shot here first.
I am creating a PWA and with every iteration I'd really like to focus on making it look/feel like less janky and as smooth as possible. Well, like a native app.
So here is the problem—I am using transitions (animations) provided by Semantic-UI-React, and while it works beautifully when an element which is occupying its on space, I was wondering if there a practice or pattern which handles the behavior of adjacent DOM elements to one that is being animated?
I supplied a GIF below to illustrate what I mean. I suppose I could just move the animated elements out of the container of the form to prevent jank, but I wondered if there was a more elegant pattern or approach to this...
Merci!
Unfortunately, there is no particularly elegant approach to this.
Regarding the question in the title of your post, a common approach is to animate the height of the new elements. If you don't know the height of the elements, unfortunately animating from 0px to auto does not yet work but you can fudge it by animating max-height from 0px to a value slightly larger than the maximum size you expect the element to be.
But don't do that.
It will cause the browser to layout the page on every animation frame and will almost certainly jank on lower-end devices.
Instead, you're better off to animate transform.
The most common approach is to:
Grab the original position of the elements (using getBoundingClientRect() etc.) that are going to be affected just before you add the new elements to the DOM (perhaps using getSnapshotBeforeUpdate unless you're using hooks, in which case you can use useRef to similar effect).
After you've added the new elements (which you're presumably also animating in by using transform with a suitable scale() function), calculate the delta from where the offset elements are now, compared to where they used to be.
Setup a transform animation from the negative of the delta, to zero (i.e. the FLIP approach). E.g. if the element has been shifted 300px down the page, animate transform from translateY(-300px) to none.
Of course you need to do that for all the elements in the flow that are affected so it might be easiest to put them all in one container and just animate that.
Regarding the third point you have a few choices of technology, none of which are great:
CSS transitions. These are simplest but you'll have to trigger a style flush to get the negative delta starting point to stick. e.g.
elem.style.transform = `translateY(-${offset}px)`;
elem.style.transition = `transform .3s`;
getComputedStyle(elem).transform; // Flush style
elem.style.transform = `none`;
CSS animations. Producing #keyframes rules dynamically using the CSSOM is a pain but at least you don't need to trigger a style flush (and you can set an animation with an implicit to-keyframe for convenience).
#keyframes random-id { from: { translateY(-300px); } }
Web animations. This is probably the most well-suited.
elem.animate({ transform: [ `translateY(-${offset}px)`, 'none' ] }, 300);
// In future when browsers ship support for implicit to/from keyframes:
elem.animate({ transform: `translateY(-${offset}px)`, offset: 0 }, 300);
Unfortunately Safari only has Web Animations support in Tech Preview so Safari users will get the un-animated version until the next Safari release. Edge users will also get the un-animated version until the Chromium based Edge ships. There is a polyfill too but it's not actively maintained at this point in time.
If you're using React, Animating the Unanimatable is a helpful article on all this.
The other tricky part is making sure the scroll doesn't jump for which you might need to look into scroll anchoring.

Why are slow jQuery animations choppy?

I'm having a hard time googling this issue because most of the things I can find are about animations that are supposed to be fast but are acting slow. My question is regarding an animation that I want to have a long duration but still be smooth.
I've created this jsfiddle to demonstrate the issue: http://jsfiddle.net/93Bqx/
I'm trying to make an element slowly move to another position over time. But the animation is very choppy.
Basically, it boils down to something like this:
$elem.animate({
left: x,
top: y
}, someLargeNumber);
I'm wondering if the problem is that the animation is so slow that each step is less than a pixel and so it is rounding them to either 0 or 1 making it appear to drop frames and then move all at once. But I don't know how I would check or fix this.
Is there a better way to be doing slow animations so they're smooth? I had a similar one created with CSS3 and translate(x,y) that was smooth but unfortunately I need more flexibility than I think I can get with CSS.
I guess it's the inevitable bargain with doing animation programmatically.
Maybe try a framework specialized in animation like:
http://www.greensock.com/gsap-js/
but adapting the animation to CSS would be best.
It's not much smoother even using a CSS transition.
I added the Transit jQuery plugin to test a CSS transition instead, and it looks almost the same.
Your code with minor fixes: http://jsfiddle.net/thirtydot/93Bqx/5/
Same code but with Transit added: http://jsfiddle.net/thirtydot/93Bqx/6/.
I think this is a limitation of the fact that (most?) browsers don't do subpixel rendering. As you mentioned, the x and y of the element is rounded after every step of the animation, and it's this rounding that causes the unsightly "jiggling" effect.
The CSS transition version does look noticeably better for less pathological test cases. Read this for more information: http://www.paulirish.com/2012/why-moving-elements-with-translate-is-better-than-posabs-topleft/
I think it has something to do with how often you move an element. For example, if you move the object once every second, it will seem choppy. Try decreasing the amount of time between each move as well as decreasing the distance between each move. See http://jsfiddle.net/2K9xP/ for an example.
So we have...
var duration = Math.round(10 * distance);
instead of...
var duration = Math.round(1000 * distance);

Repaint slowdown with CSS via Javascript in webkit browsers

I've been working on a slideshow script that uses CSS3 transitions, or jQuery's animate when they are unavailable. I've created a custom function to do the slide animations, which does so appropriately. Everything seemed to be working fine, but I've hit a major snag during testing.
For one reason or another, there is an large delay applying the jQuery CSS before and after the transition on large slideshows. For example, the slideshow in the link below is around 9900 pixels wide (container width, most of which is hidden). The container is maneuvered to display the appropriate slide, using CSS3 transition and transform properties. The delay occurs applying the CSS between lines 75 - 82 in the paste below. In particular, applying the 'transition' CSS causes the problem. Add the 'transition' CSS to the stylesheet (rather than applying it with JS), and delay disappears. This isn't really a solution however, because we only want to use CSS3 transitions on specific properties, that can vary (using 'all' in the stylesheet would transition some CSS that we don't want to animate, but change regularly).
Animation function:
http://pastebin.com/9wumQvrP
Slideshow Demo:
http://www.matthewruddy.com/demo/?p=2431
The real problem is with iOS, in which the slideshow (and even the browser sometimes) becomes completely un-usable. I can't pinpoint any errors, and have really exhausted my knowledge of debugging JS. I'm sure it is related to this section of the function after playing around a bit, and disabling CSS3 support within the plugin altogether removes the problem completely.
I'm completely stuck, and really appreciate any help anyone can give.
--- Edit ---
I've tried applying the CSS with native Javascript rather than jQuery's .css function. Same results, no better performance. Also worth noting that this isn't happening at all in Firefox, and seems to only be a problem with Webkit browsers.
Anyone with a solution, would happy to make a donation towards a few beers! I really cannot figure this out!
--- Second Edit ---
Ok, so been debugging and I can see that the slowdown is caused by the browser repaint cycle that is taking a very long time. Is there a better way to handle this that the way it is already doing? Positioning the element absolutely is a known way to reduce repaints, but that isn't really working because the slideshow is responsive. Absolutely positioning the slide images or the slides themselves causes it to collapse.
--- Third Edit ---
A day later, and I've made some progress. Adding 'transition: all 0s ease' to the elements stylesheet CSS has gotten rid of the repaint caused by adding the inline CSS transition property via the custom animation function mentioned in the original post. This causes a significant performance gain, especially when removing the inline CSS transition property when the transition itself has finished.
Good stuff! However, now there is still a slowdown when the inline CSS translate is being removed (that was used to create the hardware accelerated transition effect itself) after the transition, and the left positioning is being applied. When the two happen together, there is a slowdown.
Breaking them up into two separate tasks (the translate removed, then the left position added in a setTimeout with no time specified), again gets rid of the repaints = performance gain, and looks likes problem solved. But sometimes, the CSS transition property isn't get negated fast enough, and the translate removal gets animated. No good, and don't know where to look next to work around it.
I think the problem is you're loading HUGE images :)
They are too big for the container you have them in, so you scale them down, which is even more resource intensive.
Try resizing them.
First of all congrats for your debugging!
I have been working on the exact same stuff lately and found out that ios devices don't support a large number of images positionned in the same page. It causes crashes and the only solution I found was removing elements instead of just hiding them. The downside is that removing and appending elements causes lags so you have to do it cleverly, when your transitions are done. I thought the best way to go was keep 3 or 5 images in the DOM and replacing the rest with thumbnails of the images, resized to fit the original. When transitions are done, I'd just put the large images back into place...
Hope this helps you a bit on the ios problem at least...
After spending some time analysing your code TimeLine with Chrome Dev Tools, I believe there's some optimization you could do.
As far as I can tell, every single one of your 16 images gets fully repainted every time an animation is requested. This seems quite obvious to me, as there are 16 images in your example, and the Chrome Dev Tools reports 16 long "Paint" executions every time in hit "Next".
In my humble opinion, you should figure out a solution that considers only translating two images: the one you want to hide and the one you want to show. So, consider please, not moving the rest of the images and, instead, leaving them all side-by-side to the shown image.
One more thing, using scaled down images is probably making the paint cycles quite longer. Avoid them whenever you can.
Well, think I've managed to figure it out! Just so you know, original post links don't reflect the changes as I've done them on my localhost environment.
Absolutely positioning the slides container has fixed the problem that was occurring with repaint speeds after the transition had taken place (whilst applying CSS properties). Obviously taking them out of the DOM has done the trick, allowing painting to take place much more efficiently.
I originally didn't try this too much because I knew this would add a lot of work to the resizing functionality. I had originally intended to not resize at all in JS, and rely on percentages to do the dirty work. Absolutely positioning the container would cause the slideshow viewport to collapse, rendering the native resizing useless.
However, I was already having problems with sub-pixel rendering in other browsers anyway, so I guess it was time to bite the bullet and rely on fixed pixel values. I then used JS to handle the resizing, using the window resize event. All seems good, however the slideshow was still collapsed due to the positioning. Assigning height values wasn't working correctly, so was at a bit of a loss.
Thankfully, I came across a neat little trick of setting the 'padding-top' of the slideshow viewport to a percentage value, dynamically calculated (desired slideshow height, set in the settings panel for this script, divided by desired width). As padding-top percentages are relative to the width of the element, this did a great job of providing responsive height and correcting the viewport again (no longer looking collapsed).
Here is some info on using padding-top for responsive elements that maintain aspect ratio. Great little trick: http://f6design.com/projects/responsive-aspect-ratio/
All is good now, and things are working well in iOS and webkit browsers. Everything is extremely quick and working as it should. Four days later, and it is finally figured out. Not happy about having to resort to JS for resizing, but I guess it was always going to happen due to percentage inconsistencies between browsers. Lots of decimals = no good!
Thanks to all who tried to point me in the right direction. Definitely got me thinking, and learned a lot of debugging skills that I can use again to make sure transitions are performing well. Thanks again!
not sure if this helps or not but I noticed you use 3d translation - I would think a simple 2d translation would be enough especially since your third parameter is 0 and might accelerate the issue, also go with fewer images as Armel L. suggested, don't have an iphone to test though... alternatively, this is a solution I used before css3 but should still work move the element containing the images using javascript by modifying left (?and top - the demo only moves left and right though? without the transition effects) and this way you can fine-tune the refresh rate which I think might account for the slowdown... you can go as low as 18 fps without anyone noticing, might even be good enough with just 16fps
I had this when I was first designing a magazine carousel-style page device.
If you have a series of images within a long "tray", even if they are not within the viewport, they will still take up ram, and you can effectively have five or so before leaks and nastiness begin to happen.
What I found works is "hiding" them ... But make sure they take up the physical space necessary.
What I also found worked was that one could make the 'previous' current and 'next' image are visible and move the tray, 'unhiding' them as they reach those three positions.
In my own system, I skipped the 'tray' holding e images and only had them at -100% width, 100% width and the current one a 0.
I never had much luck with the typical long-tray carousel with large scale background images... Especially with css3 acceleration.

(Jquery/Javascript) Event Handle - Lose Focus

here's my question, i'm developing a personal website that has a huge animation in the background, with clouds moving around in an infinite loop.
Everything is done with jquery extended with jquery timers and sprites.
|
First it fills out the cloud starting position matrix (random)
|
it set's the actual position of each cloud.
|
start moving the clouds with .animate() function and start a timer to fire again that animation until the clouds reach the left border.
|
repeat forever :)
Anyway this method consume a "little" memory and CPU, i'm trying to optimize the code,
and i was wondering if there's a method to call a function when the browser switch to a different page, to stop the animation.
Thanks.
Plus, if anyone would help in optimizing code, i will appreciate so much! :)
I'll post the link to the website if anyone could help with that.
Thanks Again
First, make sure you animate a single DOM-element, not a bunch of individual clouds. Put your clouds into a container and move the latter.
Second, take a look at CSS3 transitions. They are much smoother (GPU-accelerated), than JavaScript-based animation. Also, super-easy to learn and use. Just describe a CSS class and add it to your clouds upon initial position setting.
As for the determining if the browser tab is in the background, requestAnimationFrame, used by jQuery as animation ticker which is a 60 FPS ticker, can do that for you automatically.
It appears, jQuery is no longer using requestAnimationFrame (they used to at some point, but then removed it). So, here's an animate function employing requestAnimationFrame (with a setTimeout shim for IE) you can steal ideas from (or just grab the function itself).
You could listen to the window's blur and focus events:
$(window).on('blur', function() {
// window went into background, stop animations here
// ...
});
$(window).on('focus', function() {
// window became active, start animations here
// ...
});

How do I make this Javascript/jQuery animation better?

Webpage is - http://schnell.dreamhosters.com/spriteanimate.html
Just go to the page and 'View Source' and you'll see all the code.
Right now it's pretty simple. Right arrow key makes X go right, left arrow key makes him go left. He does a running animation in the proper direction and the actual image element moves in the same direction.
The major issue I have with this right now is optimization. If you play around with it a little you'll notice that the running animation isn't always smooth and for the first few seconds it feels very laggy, like it's still loading something. The animation for going left is particularly guilty of this. Another problem is with the .animate() from jQuery. It does a sort of stop-and-go motion and you can tell. The movement of the image element is jerky and not very smooth.
The .animate() from jQuery can be tweaked with easing and such, but I'm not entirely sure if that's the answer and that still leaves me with the occasional running lag or something. So does anyone have any suggestions?
Use image preloading for the sprite images, or better still, use one image as a sprite, and instead of swapping the image file, shift the position of the image file. You need to set the image as a background image and shift the background position to achieve this.
Also, use linear easing, otherwise it will default to swing, which enters and exits slowly.
Have you considered using CSS3 transitions rather than standard jQuery animations. In doing so you'll have dramatically better performance but lose some cross browser compatibility. Here's an example which only works in Chrome but shows the power
http://girliemac.com/sandbox/matrix.html
and more about CSS3 animations
http://css3.bradshawenterprises.com/

Categories