My Allstar Jamstack. Animations
This article is Part 2 in a 3-Part series.
- Part 1 - My Allstar Jamstack. Jekyll with Webpack, ES6, Stimulus, Turbolinks and Tailwind SCSS
- Part 2 - This Article
- Part 3 - My Allstar Jamstack. Custom Responsive TailwindCSS Utilities
We’re going to introduce animations into the Allstar Jamstack, beginning with the holy grail of web animations: Animated page transitions. Source code available in the foot notes.
Turbolinks Animate
yarn add turbolinks-animate
First, the markup
Modify the default layout with an animatable content wrapper like so:-
--- a/_layouts/default.html
+++ b/_layouts/default.html
@@ -8,6 +8,8 @@
<link rel="stylesheet" href="{{ "/dist/main.css" | relative_url }}">
</head>
<body>
- {{ content}}
+ <main class='turbolinks-animate'>
+ {{ content}}
+ </main>
</body>
</html>
This is so that we don’t trigger animations or transitions on the body tag, since this is not advised.
Next, modify the index page:-
--- a/index.markdown
+++ b/index.markdown
@@ -4,7 +4,13 @@
layout: home
---
-<div data-controller="hello">
- <input data-target="hello.name" type="text">
- <button data-action="click->hello#greet">Greet</button>
+
+<div id='home'>
+ <h1>Home</h1>
+ <a href='/transition'>Transition</a>
+
+ <div data-controller="hello">
+ <input data-target="hello.name" type="text">
+ <button data-action="click->hello#greet">Greet</button>
+ </div>
</div>
Now add a new page that we will transition to:-
---
layout: home
---
<div id='transition'>
<h1>Transitioned</h1>
<a href='/'>Home</a>
</div>
Next, the CSS with Animate.css
Modify the CSS entrypoint file with the following:-
--- a/src/main.css
+++ b/src/main.css
@@ -1,4 +1,5 @@
@import 'tailwindcss';
+@import '~turbolinks-animate/~animate.css/animate.css';
@import './sass/main.scss';
body {
Some things to note here. First, the tildes (~
) preceding paths, is effectively a shorthand for ./node_modules
, it lets webpack know that the source for this is a node module in node_modules
. Secondly, note that you can nest these shorthand ~’s when using @import
so you can get to nested node module dependencies!
Finally, the JS
Turbolinks provides two events that we need to leverage in order to make animated page transitions work, turbolinks:load
and turbolinks:before-visit
. The following change will handle the full transition by leveraging both Turbolinks and Turbolinks Animate:-
--- a/src/index.js
+++ b/src/index.js
@@ -11,4 +11,30 @@ application.load(definitionsFromContext(context))
import Turbolinks from "turbolinks"
Turbolinks.start();
+import "turbolinks-animate";
+
import './main.css';
+
+const fadeInTime = '0.4s'
+const fadeOutTime= '0.3s'
+
+document.addEventListener( 'turbolinks:load', function() {
+ TurbolinksAnimate.init({ duration: fadeInTime, animation: 'fadein', element: document.querySelector('main.turbolinks-animate') });
+});
+
+document.addEventListener( 'turbolinks:before-visit', function(e) {
+ let animatedMain = document.querySelector('main.turbolinks-animate')
+
+ if(!animatedMain.classList.contains('transition-out')) {
+ animatedMain.classList.add('transition-out')
+ TurbolinksAnimate.init({ duration: fadeOutTime, animation: 'fadeout', element: document.querySelector('main.turbolinks-animate') });
+
+ setTimeout(function() {
+ Turbolinks.visit(e.data.url);
+ }, 400);
+
+ e.preventDefault();
+ }
+
+});
Since all the Animate.css CSS rules are being applied dynamically by Turbolinks Animate, PurgeCSS will not be able to pick up on them to optimise the bundle and will remove the whole lot when we bundle this in production mode. So we need to add the JS bundle to our PurgeCSS config, like so:-
--- a/purgecss.config.js
+++ b/purgecss.config.js
@@ -1,6 +1,6 @@
module.exports = {
// These are the files that Purgecss will search through
- content: ["./_site/**/*.html"],
+ content: ["./_site/**/*.html", "./_site/**/*.js"],
// These are the stylesheets that will be subjected to the purge
css: ["./_site/dist/main.css"],
And that’s it! You can build in development or production mode safely!
The source code for this tutorial is available here.