Moving poetry: Behind the scenes
The “Moving poetry” project (Swedish only) was an exploration of text and technology. This post describes some of the nifty Javascript (and CSS) tricks used to build it.
Web Animations API
The entire project revolves around the “new” Web Animations API, available in modern browsers. As the name suggests, the API makes it possible to animate DOM elements. All properties of an element which can be animated are listed here.
Animations are defined as a
KeyframeEffect
,
which consists of two parts: the
keyframes
describing the transitions of the animation,
and the options controlling the animations behavior.
Below some examples are shown of what effects can be achieved when animating text elements (all but the font size animation can of course be applied to any type of element).
Opacity
To make an element fade in and/or out, the opacity can be animated.
Notice the difference when pressing the cancel or finish button:
cancelling an animation
will remove any applied effects (returning the element to its starting state)
while
finishing an animation
will set the current playback time to the end of the animation, which combined with the animation option fill: 'forwards'
puts the element in its final animated state.
Safari bug: When animating the opacity it seems Safari does some strange things.
In below example (Safari only, reproducible at least in version 14.1.2
, even though it seems like an
old issue)
the top two lines fade out even though only the first line has its opacity animated.
The third line only stays visible since it has opacity: 1
applied by CSS.
Font size
By animating the font size, text can be made to smoothly disappear or appear:
A small problem, illustrated by the red border in above example, is that the element itself is still rendered.
This can be fixed by using
Animation.onfinish
to apply a CSS class hiding the element.
Translation
The movement of elements can also be animated.
Using the cubic-bezier
function to control the timing of the animation
allows some really cool patterns to emerge while still using the same simple keyframes.
CSS-Tricks
has further examples with explanations.
To experiment with finding the perfect curve you can use cubic-bezier.com.
When there is a single keyframe specified, the browser will interpret it as the end state and
try to infer the starting state.
Hence, when chaining animations with more than one keyframe it’s necessary to make sure they are still starting from their current state.
This can be done using
getComputedStyle
to get the current transform of the element.
Otherwise the result will look very jumpy, as can be seen in the below example: the “Relative” text element moves along a smooth square (split into two separate animations),
while the “Basic” text elements jumps between positions.
Rotation
Similarly, the rotation of elements can be animated.
By moving the
transform-origin
,
the element can be rotated around different points.
By combining animations more complex effects can be achieved. In the following example an element containing a child element is rotated, before the child element itself is transformed.
Responsiveness
To make sure animations are responsive, and working nicely on smaller screens as well, there are some tricks that can help:
- Use relative length units for all the things, including animated translations. Especially if you’re using fluid typography the text animations will scale nicely.
- CSS functions and variables can be used when specifying the animation keyframes. It’s totally legal to specify something like
{ transform: ['translateX(calc(var(--font-size) * 5))'] }
- If you really need to customize the animations based on for example screen size, media queries can be used in Javascript via matchMedia.