Animating Enhance Movies
by Cole Peters
When it comes to animations on the web, less is often more. So when we were building our latest demo app, Enhance Movies, I knew I wanted to take a minimal approach to animations — just enough to lend the app a sense of sophistication, but not so much as to cause distraction and steal the show from the actual content of a page. (Not to mention that throwing too many animations on a page can be taxing for older/slower CPUs.)
In this article, we’ll walk through how these animations are designed and built in Enhance Movies, with the hopes of giving those new to CSS animations a little inspiration.
Category and genre listing animations
All of the animations in Enhance Movies are implemented with just four simple
@keyframes definitions and a small selection of
transition styles, along with a custom easing curve defined with the
For those unaware, a
@keyframes rule in its most basic form defines the initial and final states of animation using the
to keywords (more detailed steps can be composed using percentages). Once a
@keyframes rule is defined, its name can be referenced in the
animation property to animate an element between the states defined in that rule. (Note that, because a
@keyframes rule only defines what the states of an animation are, it’s up to the
animation property to define how an element moves between those states. More on this below.)
Our keyframes stylesheet defines the three
@keyframes rules used on each category and genre index page. You’ll notice that we have keyframes defined for a fade in animation, a ‘raise’ animation (in which an element starts vertically offset and ends in its normal position), and a ‘slide’ animation (the same as our ‘raise’ animation, but on the horizontal axis).
In Enhance Movies, each listing page — whether for a category such as ‘Popular’ or ‘Top Rated’, or for a given genre — starts by featuring a single movie from that listing. We render that section with our
movie-feature element; you can check out these specific lines of code to see how we apply our animations in this section as discussed below.
First, the entire section is styled to use the
fadein keyframes, and the animation is applied such that it will take 1 second to move from the start to the end of the animation. Additionally, we apply our previously mentioned custom easing curve to this animation. This instructs the browser to move from the start to end state of the animation in a nonlinear fashion, which gives the animation a more natural feel. (Check out the excellent easings.net for reference to a bunch of mathematically derived easing functions.)
raise animation is applied to the section contents (but not the section itself). This will cause the text and buttons within the feature section to animate upwards when the page loads, while leaving the background image in place, lending a sense of depth to the layout as it animates in.
Below each listing page’s featured movie, the full listing of movies also animates into view. For listing pages that use horizontally scrolling collections, this is handled in the
movies-index-collection component; for listing pages that use a grid of movies, this is handled in the
As you’ll note when looking at the linked styles above, these components compose two different animations together: the
slide animations for the horizontal collections, and the
raise animations for the grid. By setting the
fadein animation to 2 seconds in length, and the
slide animations to 1 second, we create a more nuanced flow for these animations. Further, each component delays both of these animations for a quarter second; this is done to stagger the entrance animation of the feature section and the movie listing, thus creating a sequenced flow on each page load.
Movie page animations
For an individual movie’s page, we reuse the
raise keyframes, but we also make use of a new
filterin. These keyframes indicate that an animation should start with no
filter styles, and should end with our
movieBackdropFilter custom property applied. That custom property, depending on the current color scheme, will in turn be defined as one of two possible values, both of which work to make text set on top of the backdrop more legible.
We then apply these keyframes to the backdrop element’s
animation property, setting a delay of 0.5 seconds. This is to allow the movie summary as a whole to fade in first (with the unfiltered backdrop) — then, after the summary fades in, the backdrop will animate to its filtered version (which generally means it animates from a sharp image to a blurred one).
This gives some life to the page by allowing the movie’s backdrop image to be seen in full detail before the additional content animates into view on top of it.
What about view transitions?
You may be wondering why I opted for animations that run each time a page loads, rather than working with the View Transitions API, as many other movie demo apps have tended to do. The primary reason I chose not to implement view transitions is simply due to the fact that this API is not yet available in all modern browsers. As the purpose of this app is to serve as a learning tool, I wanted to make the experience as consistent as possible for as many people as possible.
Secondly, while I think view transitions offer an intriguing opportunity to create a more organic sense of navigation between different web pages, I didn’t find them wholly necessary — especially after implementing the page load animations which, in my opinion, offer a more pleasing sense of depth than what I’ve seen in many view transition demos to date.
That said, I look forward to continuing to explore the View Transitions API as it becomes more generally available!
Coming up next
In a future article, I’ll dive into some of the more intriguing aspects of component styles used in Enhance Movies — including the color scheme switcher and some learning I had to do myself on the topic of CSS masks.
In the meantime, I hope this has been a helpful guide to how animations are handled in Enhance Movies! If you have any questions on these or CSS animations in general, be sure to join the Enhance Discord server.
See you next time!