Skip to main content

Responsive scrollytelling best practices

April 2017

I recently wrote an article about how to implement scrollytelling with six different libraries. In this post, we will discuss all things mobile; from planning, to choices, to lessons learned. Let’s get the elephant in the room out of the way first.

When do you start on mobile?

First. Or second. It doesn’t matter as long as you plan it out, ideally from the get-go. Keep in mind that by “mobile” here, I mostly mean browser size, although it can sometimes mean other things, like touch events, geolocation, or crappy internet.

The main advantage of starting with mobile first is that it forces you to pare down your experience to the nuts and bolts, leaving only the necessities. This refines and focuses the content, which can be a helpful exercise in and of itself. Starting with mobile can also improve development time and efficiency. If the experience is functionally the same on desktop, you do not need much additional code. By framing the story and development around mobile, you can view desktop as the enhanced version, that you can soup up like a car from Fast and Furious.

But life is short. Sometimes it is more exciting to dream big and think desktop first. By restricting yourself to a mobile thought process, you might lose out on some cool concepts in the brainstorm phase. And while there are certainly fantastic interactives on mobile (sometimes even better than on desktop), I’ll never turn down more pixels to work with. There is no shame in this approach, as long as you have a plan for how your interactive scales down.

To scroll or stack?

Once you commmit to scrollytelling, you have two mobile choices: keep it scrolly, or stack it. Keeping it scrolly preserves the most similar experience for all users. You might have to eliminate some flair or reduce complexity, but it will generally behave the same way. The most important reason to preserve the scroll is if the transitions are truly meaningful, and not just something to make it pop. Seeing change over time or spatial movement are some good justifications for this. Here are some examples of keeping it scrolly.

But sometimes doing a series of stacked charts is the way to go. This method might be a better mobile solution if...

Here are some examples of stacking on mobile.

You actually have two other choices, but I do not recommend them. The first is a stepper. Steppers perform the same function as scrollytelling, but require the user to click through. The whole trend towards scrollytelling is to get away from forcing the user to click to reveal content. It allows them to simply scroll, which is the way they are used to consuming a story. Whether scrollytelling increases interest and comprehension is up for debate, but it doesn’t hide content.

Your other choice is the swipe/tap approach. While this works quite well and performs the same function as scrollytelling, it overrides default scrolling behavior and browser functionality, which I do not recommend.

Best practices

Now that we’ve covered some high-level stuff, I want to share a few disparate thoughts, technical and otherwise, that I’ve accumulated after producing a handful of scrolly stories.

I love using the css unit vh (viewport height). If you haven’t used it, 100vh would mean full viewport height, which automatically adjusts with resize. It is awesome, and something that you used need JavaScript to do. That being said, don’t use vh for scrollytelling. Mobile browsers toggle the top and bottom navbars’ position and sizes whether you are scrolling up or down.

This causes the viewport height to change, and will mess with your scroll triggers and make things a little janky. Instead, you should use px values that you calculate from window.innerHeight on load/resize in JavaScript.

		function resize() {
			const height = window.innerHeight
				.style('height', `${height}px`)

I mentioned it earlier, but there are many ways to differentiate between mobile and desktop. I have personally only needed two approaches to handle these situations. The first is browser size. A lot of responsive scrollytelling is done in the CSS with media queries, but since you will also be doing things on the JavaScript end, you will want to keep them in sync. My favorite method is to use the matchMedia function on load/resize.

		function resize() {
			const breakpoint = '(min-width: 800px)'
			const enhanced = window.matchMedia(breakpoint).matches
			// use "enhanced" to make JS decisions

If you are looking for mobile features, you can use something like Modernizr, or do some device-sniffing which works good enough. I’ll usually add a class to the html tag so the CSS can get in on the action.

		function init() {
			// from the device-sniffing link above
			const mobile = isMobile.any()
			if (mobile)'html').classed('is-mobile', true)

Separate all your chart setup and chart drawing functionality. This is good practice to begin with, but is necessary with a responsive graphic. This way on resize, you can simple update your charts rather than build them from scratch. I’m writing a whole post dedicated the basic structure and flow I use that will go into more detail on this.

Remember to consider how all your mouse interactions will function on mobile. Try to either limit the interactions or make them part of UI elements so it is clear where they will be required. Otherwise, inadvertent interactions may happen while the user is simply trying to scroll. A good example of this is hover events. I prefer to remove them and replace with some fixed text or annotation.

Pacing is important. While not specifically a responsive topic, it has different effects on different screens. Something might seem fine on desktop, but then may be fatiguing or tiresome on mobile. I err on the side of short and sweet. A few steps to grab the user and make your point and then you’re out. The reason for this is explained brilliantly in Tony Chu’s OpenVis talk.

Go forth and scroll

Hopefully you are now equipped to make (or justify) the best scrollytelling decisions. I’m sure there is a lot more that I am leaving out or I have left unanswered. Hit me up on Twitter at @russellviz.