e.g. animation-delay: -1500ms will begin the animation immediately but jump to 1.5s into the animation. Controlling this value with JS lets you effectively scrub through CSS animations via JS, making every animation compatible with game-engine style compute-update-render tick loops.
https://developer.mozilla.org/en-US/docs/Web/CSS/animation-d...
https://web.dev/shows/http-203/Qf5wdXOxW3E
Sadly no Safari support yet.
(attaching an active JS event listener to scroll is considered bad because it means your scroll movement gets tied up in the JS event loop. On a fast device it’ll probably be fine but on a slower one things can start getting choppy pretty easily)
We built a high performance animation library on this concept: https://github.com/Monadical-SAS/redux-time
I've been using Theatre.js the last few years and really loving it. It's a library divided into two parts; one is a studio UI with a timeline for editing keyframes and bezier curves, and the other is a runtime for taking those keyframes and interpolating values in relation to a timeline. Try it for anything that requires coordinated animations.
CSS now has enough Math functions supported,
particularly mod(), round(), and trigonometric
functions
CSS can not start a timer like JavaScript does,
but nowadays it's possible to define a custom
variable with the CSS Houdini API to track time
in milliseconds.
Why do we need all this when we have JavaScript?Shouldn't the drawing layer be concerned with drawing primitives? Why put more and more of the higher layers into it?
Updating the DOM (as in innerHTML) is always expensive because it triggers layout. This is true whether you're doing it from JS or a CSS trick like on this page.
Finally this approach is using CSS custom properties. These are slow - slower than JS for most things.
If you stop all animations on this page and profile it via Chrome you can see this in effect. The root node is animating a CSS variable. 117 elements have their style recalculated. Every frame - yet no animations are running. There's also a tiny paint triggered too, obviously there's been no changes so it is tiny in this instance, but a paint is always triggered when a CSS variable updates.
This is why animating x and y separately via CSS and a style like `translate(var(--x) var(--y))` would be worse than animating them via JS ala Framer Motion/GSAP.
CSS is not a drawing layer. The drawing is driven by the DOM, either setup by HTML or updated through JS. CSS only piggyback on it by giving parameters to the painting engine about what to do with dom, essentially overriding the defaults parameters. You can add dom blocks, modify positioning behavior with complex algorithms, even margins are not really trivial.
I don't think this is a great solution, but people started this to be able to modify colors during dom rendering without having to update their HTML code, probably because updating HTML code was not fun at all, but I really think the wrong problem was addressed. Those were the «webmaster» times, so there's also that.
Jokes aside, CSS is declarative and while there is overlap between problems solvable by JS and CSS, I think that’s only natural.
I’m actually really excited for all the new features added to CSS lately, less interpreted code is better.
In practice, mostly so google can still invade the privacy of users after they disable javascript.
No user ever asked for this.
This seems to be an example of browser optimization leaking private information. There's an obvious way to fix that: deoptimize. Instead of lazily downloading resources as they are needed, request all the linked resources when the page loads, and do it only once. Now they can't tell whether the requests were due to user interaction or just normal browser behavior.
I wonder if uBlock Origin can deal with this. I know it's got a lot of options for blocking weird information leaks like this, webfonts being an example. Firefox also has fingerprinting resistance, I wonder if it resists this.
One thing to watch out for is differences in how browsers handle setting the fallback initial-value. Chrome will use initial-value if CSS variable is undefined OR set to an invalid value. Firefox will only use initial-value if the variable is undefined. For most projects, this won't be an issue, but for a recent project, I ended up needing to use javascript to set default values in Firefox to iron out the inconsistency between browser implementations.
Get property value defined in :root{}:
getComputedStyle(document.documentElement).getPropertyValue("--some-custom-css-var");
Set property value:
document.documentElement.style.setProperty("--some-custom-css-var", "some value");
This can work as a polyfill for browsers that do not yet have CSS @property support enabled.
Could not figure out a way to do it (sans JS or insane complexity) without something like what's on this page. Holy stylesheets! This page has really creative demos!!! Haha :)
I'm thinking of a customizable CSS version of: https://quietkit.com/box-breathing/
https://codepen.io/spartanatreyu/pen/YzbPjwg?editors=1100
But if you want each step's duration to be parameterizable then you'll need to reach for js, I'd recommend the Animation API.
If you're not needing to control ticks and just want smooth CSS animations in all browsers, the FLIP method is useful:
https://medium.com/outsystems-experts/flip-your-60-fps-anima...
Demo on https://RTCode.io
(To import pens, simply replace the hostname with xcodepen.io in your URLs.)
RTCode is in private alpha. (Currently building Code Versions: diff, rollback, A/B testing; and Code Search: full-text search across all your active deployments).
Our playground and network have proven stable in production in several large enterprises for the last year.
I can answer any questions via email (support@elefunc.com) or chat (https://meet.elefunc.com).
Edit: Just read the disclaimer, whoops!