When Gatsby announced the first ever Silly Site Competition in November 2020, I was excited to create a suitably fun and silly project. My submission, “The Jabberwocky Poem,” was chosen as a top 5 runner-up. Here’s the story behind how it was made.
I knew first off that I wanted to create something simple and visually appealing. I was inspired by the idea of Star Wars-style scrolling text, and planned to drive that movement using the user’s scroll position. But what would be the right content?
From time to time it helps to have a well-read linguist at arm’s reach. My girlfriend Ana-Maria suggested Lewis Carroll’s famous Jabberwocky nonsense poem due to its complete and utter silliness. Perfect!
With the vision in mind and the content sourced, it was time for the fun stuff…
Creating the Animation
Prerequisite 1: 3D Transforms
Rather than scaling the text as the user scrolls, I wanted to translate the Z position inside a 3D container. It’s a subtle difference, but this gives the effect of the text actually moving towards you from a distance. To get this to work you add the following CSS properties to a container:
Prerequisite 2: GreenSock Animation Platform
The site relies on the GreenSock Animation Platform (GSAP), and in particular two of their amazing plugins: ScrollTrigger and SplitText. The aim of this article is not to provide a comprehensive guide to GSAP, but rather to show you how I implemented the library to achieve the end result.
Note: When using GSAP with Gatsby, you must test for the browser window before registering plugins. I included this code at the top of my index.tsx file.
The Title Transition with SplitText
The SplitText plugin wraps lines, words, and characters in nested div tags. When the page loads, SplitText works its magic and stores the div-wrapped characters in an object. The characters in that object (headingSplit) are then animated. Let me break that down for you:
The Main Poem Timeline with ScrollTrigger
If at first you don’t succeed…
Part of any creative process is trial and error and this journey was no different. There were definitely some errors on the way to success! After establishing that the split text transition with random character appearance looked good, and the Z-translation was neat… I just needed to figure out how to optimize it.
In my first attempt I animated all of the poem’s sentences at the same time. The first sentence started right at the “front” and the final sentence was a mile away in the distance. I did this by looping through each sentence and incrementing its Z position by 100vh, until the 28th sentence was 2800vh back on the Z axis.
Yes, it was a mega silly timeline (and not silly in a good way). And it proved to be too slow for the browser to compute, even on a top spec MacbookPro — imagine what this would do to a normal computer. Worse, this approach made it very difficult to read the poem as there were no clear paragraph breaks, only a parade of sentences.
A More Performant Solution
The problem was that I was asking the browser to do too much, and asking it within a 3D space.
The ideal solution would be to only animate two blocks at a time. One paragraph that’s leaving (fading out towards you) and one that’s entering (fading in from the distance).
Like great artists, I went digging in the GSAP examples for inspiration. That’s when I came across some code that I could adapt.
Rather than creating one monolithic animation timeline with every paragraph and character transition nested inside it, I would create individual timelines and initiate them at the appropriate scroll position using ScrollTrigger.
I had a poem constant like so:
Mapped into suitable HTML elements…
The text-container-motion is set to “position: absolute”, which causes the paragraphs to stack on top of each other.
When the page mounts (assuming animation is enabled) I call this function:
When the scroll position reaches a certain trigger point, ‘setActiveParagraph’ will be called to animate the 2 paragraphs.
Accessibility: Implementing “prefers reduced motion”
The competition stipulated that accessibility and performance were key factors in the judging process. And rightly so.
My website was heavily animated and this could cause a problem for acessibility devices, not to mention for those prone to motion sickness.
Therefore I created a static version of the poem and switched between the two by toggling a ‘disableMotion’ state variable.
When the page loads, I check for the media query ‘prefers-reduced-motion’, and if it’s true I set ‘disableMotion’ to true, otherwise it remains false.
I also added a disable / enable motion button which allows the user to manually set the state.
When the ‘disableMotion’ state changes (and when the page mounts), I call the relevant setup function.
Once the difficult stuff was out the way, I experimented with a variety of different colour palettes and ultimately settled on this one:
To further increase performance, I used Gatsby Image for the background image and the photo of Lewis Carroll.
You can visit the code repository here if you’d like to take a closer look.
If you have any questions or would like to collaborate with me on something silly or sensible, you can reach me at matthew@loopspeed.co.uk
Here’s my tired-looking mug with a much needed cup of coffee in my super swanky Silly Site Challenge prizewinners mug. LOL. Cheers!
Stay silly!
Matt