Scroll hijacking, sometimes just called 'scroll jacking', has caused quite a stir in the usability and web development world.

Some call it a "usability nightmare." Others think it's a great way to create a unique, immersive experiences. Some avoid it like the plague. Others swear by it.

As is often the case, both in design and in life in general, the truth is somewhere in between the extremes. If you use scroll hijacking incorrectly, you might frustrate and annoy your users. Today we'll start from the ground up - we'll talk about what scroll hijacking is, how to implement it, and some key things to keep in mind.

What is scroll hijacking?

Scroll hijacking is when you take control of the normal scrolling behaviour of a website, and make it do something unexpected.

This could mean (to name just a few examples):

  • Making the site scroll at a different speed to usual
  • Activating an animation as you scroll
  • Horizontal scrolling
  • Moving to another page in a full-page site

Why the controversy?

To understand why this is controversial, we need to grasp some basics of usability.

For a website to be considered "easy to use" or "intuitive" (this also applies to any tech, gadget, appliance... anything that people use), it has to take advantage of conventions. In other words, it has to work how we expect it to work.

Take those internal swing doors you'll find in any office building. You know, the ones that close themselves. If those doors only open one way, it's best to put a handle on the 'pull' side, and just a panel one the 'push' side. The purpose of a handle is so you can grab and pull the door - if the door cannot be pulled from that side, then there is no point in a handle being there. You'll end up with situations like this:

The same principle applies to web usability - elements should behave in the way people expect them to. Things that look like links should be clickable. Embedded video should start and stop on click. And scrolling should enable the user to control how they move through the site in a predictable way.

Now, that doesn't mean you should never use scroll hijacking. In fact, some of the worlds biggest brands, including the design-centric Apple, are rather fond of it. You just need to ensure that it adds to the user experience, rather than taking away from it. Let's go over a couple of use-cases for scroll hijacking, and discuss some of the issues around it.

Using scroll hijacking to create a scrolling website animation

Have you ever landed on a website, started scrolling, and instead of moving down the content, you see an animation playing out?

Apple's AirPods page is a great example. As you scroll, the light swoops around the sleek, curvy AirPods. You scroll further, and the screen darkens... a little more, and some sales copy fades in. Even though technically you are still scrolling down the page, it doesn't feel like that. It feels like you're controlling the animation that's playing out in front of you.

This is something you should think carefully about before employing. Scrolling, by convention, is a power that users have over a website. If you take that power away, it feels like a loss of control. Also, many users are scanners - they don't want to get immersed in your narrative, they just want to get the key product features and move on.

But if you do decide to go ahead with this method of scroll hijacking, how would you do it? Well, at its core, the basic method is quite simple:

  1. Figure out where the user has scrolled to
  2. Use JS to update the CSS of an element based on that positioning

Here's a simple example:

See the Pen on CodePen.

And here's how to do it...

1) Create the elements you want to animate by scrolling

In this example, I just have two elements - the bar that scrolls from left to right, and the text that fades in afterwards:

<div class="container">
<div id="scroll-animation">
<div id="scroll-bar"></div>
</div>
<div id="message-animation">
<div id="message-text">
Scroll Different.
</div>
</div>
</div>

So for each animation you'd have a separate container. I've got two animations, so my containers are: scroll-animation and message-animation. We'll use these elements to figure out how far down the user has scrolled, and the height of them determines how long that animation will take - if you want a longer animation, you'd just make the containers larger. The elements inside are the things we'll actually animate.

And the CSS for these is:

#scroll-animation {
height: 1000px;
position: relative;
}

#scroll-bar {
position: fixed;
top: 0;
left: 0;
width: 0;
height: 100%;
background: #B0A3D4;
z-index: 1;
}

#message-animation {
width: 100%;
height: 500px;
z-index: 2;
display: flex;
justify-content: center;
align-items: center;
}

#message-text {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 3em;
z-index: 2;
opacity: 0;
}

Nothing too crazy here - the main thing of note, is that I've set the elements we're animating to position: fixed, which keeps them on-screen as the user scrolls down.

2) Detect how far the user has scrolled

First let's store our elements in JS variables:

let scrollAnimation = document.getElementById("scroll-animation");
let scrollBar = document.getElementById("scroll-bar");
let messageAnimation = document.getElementById("message-animation");
let messageText = document.getElementById("message-text");

Then let's work out where they user has scrolled to. The function below will return how far down a particular element the user has scrolled, as a percentage:

function getPercentageScrolled(element) {
let distanceScrolled = window.scrollY - element.offsetTop;
let percentageScrolled = Math.round(distanceScrolled / (element.offsetHeight / 100));
return Math.min(100, Math.max(0, percentageScrolled));
}

This works because window.scrollY tells you how many pixels down the page the user has scrolled, and element.offsetTop returns the distance between the top of the element (including padding and borders, but not including margin) and the top of its parent. Subtracting offsetTop from scrollY therefore tells us how far down the element the user has scrolled, in pixels.

Once we have this, we can get the percentage scrolled by dividing it by the element's height / 100, which is what the second line does.

The return line ensures that we're returning a value between 0 and 100.

3) Update the animation based on the scroll distance

Then it's just a matter of using JS to animate your elements according to how far the user has scrolled. So we just listen out for a scroll event, and run a function if we detect one:

document.onscroll = function() { 
scrollBar.style.width = getPercentageScrolled(scrollAnimation) + '%';
messageText.style.opacity = (getPercentageScrolled(messageAnimation) / 100);
}

When we pass getPercentageScrolled() a particular element, it tells us how far we've scrolled past that element, as a percentage. We can use that to change the CSS property of another element.

In my example above, the scrolling bar is simple - we just set its width to the value returned by getPercentageScrolled(). When the user has scrolled 100% of the way through the element, the scroll bar's width will also be 100%. Easy.

To make the text fade in, we do a similar thing with opacity, except here we have to divide the percentage scrolled by 100, since the opacity property takes a value from 0 to 1, not 0 to 100.

You can update any CSS property you want in this way. Advanced scroll animations like Apple's AirPods are far more impressive than this little demo, but they work on the same principle - detect how far the user has scrolled, and update CSS accordingly.

Horizontal scrolling with CSS

Even though we read books and magazines horizontally, horizontal scrolling never caught on in the digital world. But you can implement it with pure CSS if you want:

See the Pen on CodePen.

Just set up a wrapper element, and an inner element to contain your content:

<div class="horizontal-wrapper">
<div class="horizontal-content">
</div>
</div>

And then use the following CSS:

.horizontal-wrapper {
transform: rotate(-90deg) translateX(-100vh);
transform-origin: top left;
overflow-y: scroll;
overflow-x: hidden;
scrollbar-width: none;
}

.horizontal-content {
height: 100%;
transform: rotate(90deg) translateY(-100vh);
transform-origin: top left;
}

This creates the essence of a horizontally scrolling site. You can then fill the inner element with whatever content you want.

So this type of scroll hijacking is pretty easy to set up - but should you do it? There are probably some situations where you might want to. Horizontal scrolling is probably more acceptable if your brand is expected to be unique, creative, and perhaps a little bit weird (like an art studio, for instance). Or maybe you're applying for jobs in the games industry so you want to set up an online CV in the style of a side-scrolling video game. That would be appropriate too.

But except for these quite rare use-cases, I'd probably advise against this. Horizontal scrolling is most effectively used within elements, as part of a larger, vertically scrolling design (like Netflix, for instance).

However, in these cases, I'd advise against setting up your side scrolling elements as shown above, because then your user's scrollwheel will be doing different things depending on what element they are hovering over.

It might get frustrating if you're trying to scroll down a site, and suddenly a child element starts scrolling horizontally. You might even get stuck, unable to scroll any further without using the scrollbar itself - like this:

See the Pen on CodePen.

The above example is best used for the whole site, or when elements don't take up a lot of space vertically in the viewport.

To scroll hijack, or not to scroll hijack?

So now that you've learned a few scroll hijacking methods, should you use it?

Think carefully and be sure it's what you need. If you do it right, you can make something fun and unique, that sets you apart from your competition and showcases your brand. But if you get it wrong, you may create a very frustrating experience for your visitors. Some key questions to ask yourself are:

  • Are you looking for style over substance? In other words, are you just looking for ways to look flashy, in the hope that your visitors will be impressed? If so, I'd recommend you focus on getting your message right first. But if looking flashy is your #1 aim, then go for it!
  • Will you be taking too much control away from the user? Will it be hard for them to get back to the top of the page, for instance? If you're completely hijacking the scroll behaviour, make sure you have other means of navigation available.
  • Could you use scroll hijacking on some in-page elements, rather than the whole page? This might let you get the impact you want, without taking away the scroll behaviour that users know and love.
  • Will it slow down your site?

As I said previously, there are some situations where scroll hijacking can work really well, and one example is full page websites. These are broken down into several full-page segments, and by scrolling down with the mouse or swiping on the track pad, you are taken down to the next page.

The great thing about the full page design is that it gets around many of the things people hate about scroll hijacking. The user remains in control - they can scroll from page to page as quickly and easily as they like. The content is still scannable - you can scroll through and find the information you're looking for without having to sit through a load of animations. And it integrates perfectly with horizontal scrolling elements like sliders.

And if this sounds like what you're looking for, you'll want to try out fullPage.js. It's the leading JS library for full page sites, and it's used by big name brands like Google, Sony, EA and eBay. fullPage is easy to set up, won't slow your site down, and is highly customisable with a range of transitions and effects you can use. Check it out!