Page Transitions for Everyone

As Sarah mentioned in her previous post about page transition using Vue.js, there is plenty of motivation for designers and developers to be building page transitions. Let's consider mobile applications. While mobile applications are evolving, more and more attention is given to the animation experience, while the web pretty much stays the same. Why is that?

Maybe it’s because native app developers spend more time working on those animations. Maybe it’s because users say that’s what they want. Maybe it’s because they know more about the environment in which the app is going to run. All of that helps to improve the experience over time. Overall, it seems like mobile app developers somehow seem to know or care more about user experience.

If we take a look at how mobile apps are designed today, there is very often some sort of animated transition between states. Even ready-to-use native components have some kind of simple animation between states. Developers and designers realized that this little animation helps a user grasp what is happening in the app. It makes the navigation through the app easier and tells the user where they are going within the app.

For example, when you’re navigating to a subcategory, it usually slides in from the right side of the screen, and we all somehow know what that means.

Animation matters. It can be used to improve the user experience.

When you’re developing a website, it’s easy to spend hours making sure the user sees the whole story by way of top-notch transitions, like the movement between gallery pictures or fancy hover effects...but once a user clicks a link, all of that experience falls apart and you’re starting from the beginning. That’s because the page reloads and we don’t have an easy/obvious/native way to handle animations/transitions in that situation.

On the web, most of the effort used to improve the experience is in structure, visual design, or even the performance of the site. There are some elements you can swipe around here and there, but that’s about it. A boring remnant of the time when the web was simply used to navigate through a bunch of text pages later upgraded with some sliding text.

Yes, we actually used to do this.

There are some very fancy websites that are filled with animation or incredible WebGL hieroglyphs in the background. Unfortunately, they are often hard to navigate and your laptop battery is drained in about 15 minutes. But they are certainly nice to look at. Those sites are full animation, but most of it is used to impress you, and not to help you navigate around, or make the experience faster, or make things more accessible for you to browse the site.

The Source of the Problem

All of this raises a big question. We have all the technology to do this page transitions stuff on the web. Why don’t we do it? Is it because we don’t want to? Is it because we don’t think that’s part of our job? Is it so hard that we’d have to charge double for projects and clients aren’t buying it?

Let’s take a look at another possible reason. Often, a company chooses technologies that are common for all of their projects. You, as a front-ender, don't have much control over what’s implemented on the server, so maybe you can't count on some server-side rendering of your JSX.

Maybe you have to choose something stable and generally usable for any sort of solution (which usually means the less codebase, the more flexible), so you’re kind of forced to avoid some framework in your development stack. Unfortunately, it makes sense. You don’t want to implement a contact form in 10 different frameworks just because you’ve decided that some framework is a good base for this particular project. And don't get me started on security, which has been in the process of being improved throughout the years. You cannot just throw it away because you want your user to have a bit more fun browsing your site.

There is another possible reason. Maybe you want to build on WordPress because you want to take advantage of all those open source goodies people prepared for you over the years. Would you exchange all of that "free" functionality for a better experience? Probably not...

The Goal

Aside from drastic and unrealistic changes like getting rid of all images and videos, our website load time from the server just is what it is. We have a server rendered page, and apart from a faster server or better caching, there isn’t much to do to improve that.

So the way to improve the load time is to cheat a bit! Cheat by making the user think it takes less time because they are distracted by what’s happening on the screen. Cheat by loading the content ahead of time and animating the transition.

Let’s introduce some effects that could be used to do the transition. Even simple fade in/fade out can give you a whole different feel, especially with some element indicating loading. Let’s look at some examples.

Note: All of following examples are websites build on PHP and pretty much work without JavaScript as any other site would.

A simple fade out/fade in seamlessly improves experience user has before the click of the link and doesn't act that disturbing as a normal browser reload would. The loading indication on a menu icon ensures a user doesn’t panic in case the page takes little longer to load.

Some interesting animation can be achieved by animating different elements in different ways, which can also be combined with fading.

The main navigation element introduced in a form of bubbles plays with the user while the content of the next page is loading. The impact is that user is not bored and knows that something is happening. As the animation starts on the click of the link, the user doesn't even realize he’s been waiting for something.

Solution

We have sorted out what we actually want to do, and why do we want to do it… let’s see how can we achieve this.

While there is not much to do on the back-end for this, there is a whole bunch of things you can do on the browser side. A good example is Turbolinks, developed by the Basecamp folks, which takes your website and makes it more app-feeling by enabling content loading with JavaScript. It simply avoids that ugly browser page-to-page reloading jump. Turbolinks deals with browser history, loading, and all that other stuff that would normally happen under the hood of the browser. The key thing here is taking control over loading and replacing content because as long as the browser doesn’t reload, everything that happens on a screen is in our control.

Let’s think of some concepts we can use to improve our experience. The load time is our biggest enemy, so how can we improve it in the browser?

Preload

In most cases, the request for loading the next page doesn't have to start only once a user clicks the link. There is another event happening that can indicate users intention to visit the page, and that’s a hover over the link. There are always few hundreds of milliseconds between hover and click on the link, why not use that time to our advantage? Heck, if the majority of your users end up on the next page that is known to you and you have the statistics to prove it, why not even preload it any time after the initial render, while the user is trying to get around the current page?

The following diagram illustrates how many things can happen in parallel and save us some of that precious time, instead of being done one by one. A very common mistake seen in custom solutions for page transition that people make for themselves is the start of the request, which is usually triggered after the page is unloaded/hidden.

Possible process of transition

Caching

While this can be a problem for some dynamic sites, static sites are perfect candidates for caching. Why would you load a page twice, when you’re in control of loading and replacing the content? You can save the contents and use it in case the user visits the same page or returns to it with the browser back button.

Or, you can use the cache to preload pages on hover and empty the cache regularly (maybe after each page visit?) to always have the latest version of the page on dynamic sites while still enabling that preload feature.

Interestingly, Progressive Web Apps also "invest" in this area, although the approach is a bit different.

Animation

All these concepts are great, but we still need to bring animations to the party.

The control of the page load and replacement can be taken over by us, thus we can play with the contents of the page at any given time. For example, it’s simple enough to add a class to the page while it's loading. This gives us the ability to define another state for the page, or in other words, hide/unload it. When the animation is done and the page is loaded, we are free to replace the content and remove the state class to let the page animate back in again.

Another option is to animate your page "out" with JavaScript, replace the content, and animate it back "in."

There are many possibilities of how to approach this, but in any way, the key feature here is not letting the browser reload.

Ready to Go

Those are three main concepts that will make a lot of difference. The point is, with a little extra effort, it's not that hard to do this yourself, and I encourage you to do so.

It's going to be a bumpy road with loads of possible headaches, as it's not always easy not to break the browser’s native functionality.

However, if you’re more of a load and go type of person, I have put together a little package called swup that sorts out all of those things that Turbolinks does, plus all three of the concepts we’ve covered here. Here's a little demo.

What are the perks of swup?

It works exclusively on the front-end, so no server setup is required. Although you can easily implement a transfer of only required data based on X-Requested-With in the request header (little modification of swup is required based on your particular solution).

Uses browser history API to ensure correct functionality of your site, as it would work without swup (back/forward buttons and correct route in the URL bar).

It does not have to be part of initial load batch and can be loaded and enabled after the initial render.

Takes care of the timing, meaning it automatically detects the end of your transitions defined in CSS and, in the meantime, takes care of loading the next page. The whole process is based on promises, so not a single millisecond is wasted.

If enabled in options, swup can preload a page when a link is hovered or once it’s encountered in loaded content (with the data-swup-preload attribute).

If enabled in options, swup also caches the contents of the pages and doesn’t load the same page twice.

Swup emits a whole bunch of events that you can use in your code to enable your JavaScript, analytics, etc.

You can define as many elements to be replaced as you want, as long as they are common for all pages. This enables the possibility to animate common elements on the page, while still replacing its parts. The bubble menu in our earlier example above uses this feature, where the check signs on the bubbles are taken from the loaded page, but rest of the bubble stays on the page, so it can be animated.

Gives you the possibility to use different animation for transitions between different pages.

For those of you that like your animation done with JavaScript, there is also a version for that called swupjs. While it may be harder to implement animations in JavaScript, it definitely gives you more control.

Conclusion

The animation and seamless experience doesn't have to be strictly limited to native applications or newest technologies. With little effort, time, and a bit of code, even your WordPress site can feel native-like. And while we already love the web the way it is, I think we can always try to make it a little better.

Why didn’t you made use of the ability to change the URL too in your swup demo? Without unique URLs you web app is not SEO friendly and pages can’t be shared.

I was playing around with the History API 4 years ago and I’ve used https://github.com/devote/HTML5-History-API in my demo, but I didn’t made use of some caching or preload system, because I was just experimenting a bit with pushState. Although the main menu pages of the demo are SEO friendly and sharable.

As swup only runs in a browser, it can’t affect whether your page is SEO friendly in any way.

However, I get your point on page sharing. Swup always keeps current URL in the URL bar. Demo is intended to demonstrate the ability to transition between pages and the URL actually gets changed in the iframe containing the page with swup enabled (left side of the page). I tried to demonstrate the URL changing in the bar at the top of the page.

He’s referring to my demo :)
Most pages don’t have scrollbars, but have scroll-to-anchor animations when clicking on a button and that console error is due to some nasty user agent sniffing I did back then to get something to work in old IE.

Wow this is amazing! I agree. It is so mich nicer to have a nice animated webpage. It feels more native. It is one of the main reasons im creating websites with vue/nuxt. But as you say, you can not always use them. I was messing with my head to find a prober solution. Will try out your suggestions! Animate the web!!

Am I the only one who cannot wrap his head around the node modules and how to use them in a simple old HTML file? The installation instructions are a little bit scarce.

npm install swup

Okay, done that; now what? I got a node_modules folder with all the files, but how would I go on about including them in a sample HTML page? I have googled for a solution but couldn’t easily come up with one so maybe an answer to this comment will help others :)

Hi, thanks for your feedback! As far as I know, there is no way to load NPM packages in a browser without any additional steps. NPM is a package manager and it loads your defined dependencies, with the dependencies of dependencies, and so on… There is a lot of logic going on in the background for all of this package importing to be possible. For swup to be loadable as a file in a browser, it must be bundled with tools like webpack or Browserify, so it contains all the code including the dependencies.

That being said, I’ve been using webpack for all my code for a long time now. It didn’t occur to me that someone might want to load it as a standalone file. I will try to add those files to a repo later today.

One thing I’d like to add is a consideration for users who have expressed a desire for a reduced animation experience. Full screen page transitions are a common trigger for Vestibular conditions such as vertigo. Creating an alternate, low-to-no animation experience using the reduced motion media query can accommodate them without having to completely scrap the app-like effects.

I’ve seen several libraries where Barba.js is definitely the most advanced, so I’m going to focused on that one.

In fact, if you compare it to swupjs, it’s almost identical in the way it works. I think swupjs is a little handier, where the logic behind choosing the transition is done for you and you don’t have to write promises to wait for the transition to finish, but a simple call of the next function is enough. On the other hand, I’ve never used Barba.js myself, but it seems nicely cleaned up.

For swup, the difference is a little more significant. You can create quite complex transitions with little to no work using CSS. The whole point of why I started this was to be actually able to do the page transitions in a first place in a limited time, as it usually is in commercial projects.

This is awesome. I am wondering what cosiderations might be given to screen readers when changing page states. Would there be some kind of focus() given to the new page view’s heading tag? I guess its totally up to each developer if there is an “after render” function available to use.

Swup places the content of the next page into your DOM. It seems like that is not enough for the browser to load the script in the script tag.

Of course, it could go through all the scripts in the loaded content and place them in your page manually. I’m not sure what that would do in case you visit the same page twice for example (place the same script in your DOM twice). If the browser loads the script again, then you have the same code twice on your page, and if it doesn’t, then your page won’t have the same code attached to it as it would with the normal load.

All of this seems like a very hacky solution and I would rather avoid it. There are two things you could do: Put all the code together and run it when you need to or use some kind of code splitting that would load the scripts automatically for each page.

I see. My test was pretty simple actually. I’ve just post a console log on each of the loaded pages, and checked to see if they would run when switching pages. It only does so for the first page load. Turbolinks seems to handle this, hence my question on whether this had been a deliberate decision on swup to not do that.

I’ve never needed such functionality myself and I’m kind of against it… but if you don’t share my opinion, feel free to open up an issue. It just seems to me like a generally bad approach for a website with no page reloads.

Posting Code!

You may write comments in Markdown. This makes code easy to post, as you can write inline code like `<div>this</div>` or multiline blocks of code in triple backtick fences (```) with double new lines before and after.

Code of Conduct

Absolutely anyone is welcome to submit a comment here. But not all comments will be posted. Think of it like writing a letter to the editor. All submitted comments will be read, but not all published. Published comments will be on-topic, helpful, and further the discussion or debate.

Want to tell us something privately?

Feel free to use our contact form. That's a great place to let us know about typos or anything off-topic.