Animated Page Transitions in Rails 4 Apps
If you're using Turbolinks in your Rails app, which is default in Rails 4, you can add a neat little page transition animation. No jQuery required!
If you want a quick demo, just try using the navigation menu at http://www.xtagon.com/
There are probably many ways to do this, but here's how I did it.
The HTML
You might want to decide which portion(s) of the page to animate. In my case I animated everything but the header and nav bar. For this example, give one of your elements and ID of primary-content
and everything inside it will be treated as the main content to transition.
The CSS
We're going to use the wonderful animate.css for our transitions. Play around on their website until you find a transition you like, then create a custom animate.css file. Drop that bad boy into app/assets/stylesheets
.
The JavaScript
Animate.css works by adding the animated
class to an element, along with the class for the specific animation you wish to perform. What we want to do is hook into Turbolink's page:fetch
and page:change
events to start the animations when the page changes.
Save this bit of JavaScript to app/assets/javascripts/turbolinks_transitions.js
and make sure it's required in application.js
.
document.addEventListener('page:change', function() {
document.getElementById('primary-content').className += 'animated fadeIn';
});
document.addEventListener('page:fetch', function() {
document.getElementById('primary-content').className += 'animated fadeOut';
});
And here it is in CoffeScript, if that floats your boat:
document.addEventListener 'page:change', ->
document.getElementById('primary-content').className += 'animated fadeIn'
document.addEventListener 'page:fetch', ->
document.getElementById('primary-content').className += 'animated fadeOut'
That's it!
Restart your Rails server, load the page, and off you go!
Written by Justin Workman
Related protips
11 Responses
Nice tip, Btw, I checked out your SoundCloud; cool music my fellow musician/coder!
Thanks! You've got some pretty sweet sounds yourself.
Thanks!! I've been working on new stuff, can't wait to upload the finished versions :)
Btw, I hope to visit Oregon one day. It seems like the best place to live :)
Hey Great post! Thanks. I am wondering if you can think of a way to bind the transitions differently, based on the page that is being changed.
For example, If I am on a homepage and go to projects index it will slideInRightBig & going back home will slideInLeftBig.
However if I select a project show from the index, the index will slideOutDownBig & going back to index will slideInUpBig - any thoughts?
@serknight, it would be trivial to change the JavaScript code to animate elements based on a data-transition-in and data-transition-out attribute set on the element(s) you wish to transition. This would solve the problem of wanting to animate more than one element, and animating different elements different ways on different pages.
However, it sounds like what you actually want is to set the transitions based on the context of your navigation. That's a bit more tricky. You can transition out based on which link you've clicked, by tagging certain a
elements with a data-attribute to describe which transition you want for that link. But how would the next page know which transition in to use? You could use a cookie, a GET param, or pass the Referrrer header. It sounds possible, but I don't think it would be very clean.
Another idea is to use meta link elements as context when applying the transitions. For example, an article might have multiple pages. You might want <link rel="next">
to animate one way and <link rel="prev">
to animate another way. Still, you would need a way to know which transition in to use on the next page when it loads.
Thanks for the response. Yeah I continued with it, using turbolinks and got further down the rabbit hole.
I found out that turbolinks does not save the window.referrer so I could not bind the next transition based on the referrer. I tried setting a global js variable, but the way the turbolinks/coffeescript was set up was overwriting the variable every transition. Back to the drawing board. I think I will add meta-tags to specific links and use those to bind which transition I will bind.
Thanks for the response. & once again, thanks for the OP.
@serknight, when you solve it, be sure to make your own pro-tip :)
Thanks for this! It saved me a good chunk of time not rebuilding pages into one page and doing goofy JS stuff. It would wonderful to see this in a gem that compiles only the animations used and have data- support.
If your animation wrapper has an existing class (say "container") and you're using native JS, don't forget to add a space before "animate" when adding that class.
In addition to the issue @serknight mentioned, I'm getting some choppy fadeInRight animations due to the page loading, then the animation starting. Any suggestions on how to get a smooth animation?
@archonic The issue is that 'page:change' might be fired before the transition out animation has a chance to finish. I'm sure there's a way to get it right, but I'm not quite sure how.
@xtagon It sounds like the transition in animation event listener should be listening for the end of the transition out animation (in addition to the content being available after the request). I don't think CSS3 can do that, but I know greensock can.