A starting point for animating page transitions in Turbo Drive apps.
- Copy
turn.jsandturn.cssto your project and include them however you build your JavaScript & CSS - Add
data-turn-enteranddata-turn-exitto the elements you wish to animate - Call
Turn.start()in your application JavaScript file - Navigate between pages … ✨
Turn adds turn-exit and turn-enter classes to the HTML element at the appropriate times. Apply your own animations by scoping your animation rules with this selector. For example:
html.turn-exit [data-turn-exit] {
animation-name: MY_ANIMATE_OUT;
animation-duration: .3s;
animation-fill-mode: forwards;
}
html.turn-enter [data-turn-enter] {
animation-name: MY_ANIMATE_IN;
animation-duration: .6s;
animation-fill-mode: forwards;
}
@keyframes MY_ANIMATE_OUT {
…
}
@keyframes MY_ANIMATE_IN {
…
}This is how turn.css is organized, so you may want to get rid of that file altogether. animation-fill-mode: forwards is recommended to prevent your transitions from jumping back.
The values set in the data-turn-exit and data-turn-enter attributes will be applied as class names to that element. This lets you customize animations for each element. Styles should still be scoped by html.turn-exit and html.turn-enter.
Define animations in tailwind.config.js, and add a plugin that scopes the styles, e.g.:
const plugin = require('tailwindcss/plugin')
module.exports = {
theme: {
extend: {
animation: {
exit: 'fade-out-up 0.3s cubic-bezier(0.65, 0.05, 0.35, 1) forwards',
enter: 'fade-in-up 0.6s cubic-bezier(0.65, 0.05, 0.35, 1) forwards'
},
keyframes: {
'fade-out-up': {/* … */},
'fade-in-up': {/* … */}
}
}
},
plugins: [
plugin(function ({ addVariant }) {
addVariant('turn-exit', 'html.turn-exit &')
addVariant('turn-enter', 'html.turn-enter &')
})
]
}Then in your HTML:
<main data-turn-exit="turn-exit:animate-exit" data-turn-enter="turn-exit:animate-enter">
<!-- … -->
</main>Avoid animating the whole body. Animations should target elements that change on navigation. So avoid animating persistent headers and instead animate the main element or just the panels/cards within it.
Nesting animating elements draws attention and brings screens to life. Add data-turn-exit/data-turn-enter attributes to elements such as headings and key images within an animating container. The compound animation effects means they'll exit faster, and enter slower than other elements. For example:
<main data-turn-exit data-turn-enter>
<h1 data-turn-exit data-turn-enter>Hello, world!</h1>
</main>Exit animations on slow requests can leave users with a blank screen. Improve the experience with a loading spinner that appears a short time after the exit animation. For example, if your exit animation take 600ms, add a spinner that starts appearing 700ms after that by using transition-delay. This spinner can live permanently in the body and only transition when the turn-exit class is applied:
.spinner {
position: fixed;
top: 15%;
left: 50%;
transform: translateX(-50%);
opacity: 0;
transition: opacity 100ms;
transition-delay: 700ms
}
html.turn-exit .spinner {
opacity: 1;
}Check your device preferences to see if you have requested reduced motion. Turn will only animate transitions when the prefers-reduced-motion media query does not match reduce.
Turn adds exit and enter classes at the appropriate times like so:
- on
turbo:visitadd the exit classes - pause
turbo:before-render(wait for exit animations to complete before resuming) - on
turbo:render, remove exit classes and add the enter classes - on
turbo:load, wait for the enter animations to complete before removing the enter classes
Default fade in/out animations adapted from Jon Yablonski's Humane By Design.
Copyright © 2021+ Dom Christie and released under the MIT license.