Nice article and examples, but this seems like an exceptionally complicated and prone-to-bugs solution for what is ultimately a nice to have. I'm all for subtle UI sugar, I pay it a lot of attention in my own work, but subtlety (and usability) really is key IMO.
I was clicking through on Firefox android and noticed a small number of minor things, incl. bounding box issues, animations that went off screen, and glitches when an example was toggled while in motion. Not sure if these are intentional (or expected). No doubt easily fixed. But they paint a picture for edge cases. I'm sure there's some amazing use cases for these techniques, but there's also a good case for simple CSS (and restraint!)
This is a home-grown solution but the version in Framer is extensively tested (though still not perfect ofc).
The version in Framer has stuff like infinitely deep scale correction and shared element transitions so because of the filesize overhead (~10kb) I would only use this for complex stuff that is otherwise prohibitively tough (shared element transitions, layout etc).
However I do want to make the point that this approach should be more robust and simpler to maintain for even simple examples.
If you imagine an iOS-style pill toggle. The "simplest" way to animate this would be to have `translateX(0)` when off and something like `translateX(100px)` when on.
However, if there were no animations, this isn't how you'd write it. You'd probably do something like switch `flex-start` to `flex-end` on the parent.
This is easier to change the design and also maintain between breakpoints. But it can't be animated. Except with these technique, where you'd simply write
Hey thanks for the detailed response. I'm actually all for progressive enhancement, and appreciate the philosophy you're getting at here. I still think, generally speaking, you're either designing for animation or not. With CSS, if something works with a transition it also works without. Once you start meddling with animation states in JS you've taken point on all that otherwise abstracted away state-based logic. What happens when an animation get interrupted, memory use, timing functions, etc. Sure, if you weren't animating a pill-box you might use flex. But if a transform works, why not use that for both animated and inanimate versions? It's certainly not any less correct or legible.
Excellent article. Explains the FLIP concept in CSS animation performance. Doesn't really have much to do with Framer, besides it being the inspiration for the article
One thing I noticed that often isn't caught due to platform differences is when "Hide types" is pressed, a scrollbar will appear on most browsers on Windows 10. This draws the eye so harshly that most - if not all - of the magic of the animation is ruined.
I wish that Windows 10 had an option to "hide scrollbars until necessary" like macOS does, but sadly this continues to be a bit of an edge case for FE work.
Given Edge’s recent work on overlay scrollbars (#edge-overlay-scrollbars-win-style flag) that are still displayed at all times for any element with overflow: scroll, only slimmer, I’m not holding my breath.
So you can hide the scrollbars in CSS if you want to, but doing so is also an accessibility pipe-bomb waiting to happen: things in motion in visually impaired systems plus no scroll bars when navigating a space is hellacious.
Framer takes a slightly different approach in their docs which appears to be a mixture of pinning objects down and shoving margins around as well.
I use Framer on some projects and I love its declarative approach to creating nice animations. It allows someone like me who doesn't know much about the topic to create really nice experiences.
But one thing that has been confusing me is its performance. The same simple animation might be smooth 60fps 9 times out of 10, but chug significantly the 10th time, on the same device etc. Any advice on how to profile this?
I would start with the Performance tab in Chrome. Or if you're on a mobile device double checking you're not in low-powered mode, where animations are throttled to 30fps.
I've recently had a similar problem making a game with javascript. I stated making it render with plain dom elements and transforms because it was simpler, however I noticed that sometimes it stuttered.
After looking at performance tab it turned out that dom modifications trigger uBlock to run it's internal checker(presumably to check in case you are adding some ads onto the page). It's not a problem in a normal circumstances, but when you are updating dom 10+ times a second it sometimes chugs. Rewrote rendering to use canvas and the problem went away.
Love the website style and interactiveness, in particular those sections that can be expanded for that extra bit of explanation that makes all the difference!
One thing it didn't explain (or I might've missed): How do you animate the neighbors this way when a component changes? Aka if my size increases it shows how to animate that, but without doing anything else the neighbor component would just jump to its new position, or?
The rounded corners and the border thickness are getting distorted when animating size changes. I would imagine a repeating background image would distort similarly. Basically any effect that doesn’t commute with affine transforms is going to look distorted while the animation is running.
Additionally to the sibling comment, we do expose a secret API that can be used to fix distortion on other properties.
To take border from your example, in the Framer app we add correction that fixes border. But border is tricky because it only renders rounded values and triggers layout - exactly what we're trying to avoid. I always recommend a two element approach, one with an inset. More performant and visually nicer.
We also use this API to do more advanced stuff like this <LayoutCamera /> component for React Three Fiber/Framer Motion 3D. https://www.framer.com/docs/layoutcamera/
This camera renders the scene pre-distorted so when the layout transform is applied, everything looks correct.
>This camera renders the scene pre-distorted so when the layout transform is applied, everything looks correct.
Close, but still not perfect. Lines look blurry during the size animation, because the WebGL surface is rendered at the new resolution and then stretched to the current size. So if you animate from a 600x600 viewport to a 60x60 viewport it’s gonna look very bad when the animation starts. You should always render at max(old, new) resolution during the animation.
And again, this only works as long as the WebGL content commutes with affine transforms. If the WebGL content would contain 1 pixel screen-space hairlines, those would look bad when the framebuffer is stretched.
As a UX designer, I'm curious as to how Framers animations (and interactive prototyping in general) compare to Axures. I've always loved using Axure for my animations, and it does a great job with giving non-code people a way to lay out conditions, set variables, etc.
I implemented this once, for an animation system prior to the existence of CSS animations. It was an obvious solution, hardly worth making a big deal about.
It is a very well-written and beautifully explained article though.
I was clicking through on Firefox android and noticed a small number of minor things, incl. bounding box issues, animations that went off screen, and glitches when an example was toggled while in motion. Not sure if these are intentional (or expected). No doubt easily fixed. But they paint a picture for edge cases. I'm sure there's some amazing use cases for these techniques, but there's also a good case for simple CSS (and restraint!)