"Scroll-Jacking" in Full Screen.

The controversy and how we built it.

Wes Hatch
February 19, 2014

Since we launched the new Hugeinc.com, we’ve been gratified by the almost entirely positive reaction of the design and digital communities. One new element, though, has generated some controversy: the full-screen “work” navigator on the homepage, which overrides user scrolling and provides its own interaction paradigm. Critics cried “Scroll-Jacking!” Here’s why we did it (and how).


In designing the new hugeinc.com, we wanted to keep the focus on our work, but didn’t want to resort to using a standard homepage carousel to do so. Instead, we designed the homepage to shine our own H-shaped spotlight on a continually updated gallery of work we’re most proud of. The gallery of “H’s” includes several slides, each occupying the entire height and width of the screen. We abandoned traditional scrolling because allowing the bottom half of one slide to appear with the top half of another would have undermined the intended experience. There was a lot of internal back and forth about this decision, but ultimately we stuck to it. This is colloquially known as “scroll-jacking,” so yes, guilty as charged.

On the one hand, we compromised the native UX of the browser. On the other, we built an interaction paradigm that we felt was missing and so had to develop ourselves. We like to try new things out and then improve them. Will “scroll-jacking” be a permanent part of our site? Probably not, because we’re always adapting.


There were two major constraints we had to consider when constructing the HTML. First, the slides’ “wipe” effect needed to gradually reveal content that was fixed underneath—as it turns out, there are only a few ways to do this, limiting our implementation options. Second, the same code—JavaScript, CSS, and HTML—had to be used for both desktop and mobile.

As always, with initial design and functionality needs in hand, we got to work building prototypes. A lot of them. These were necessary to test our ideas and better understand how to make them work. We played with different kinds of HTML structures, different transitions, transforms, positioning, etc. After many iterations, we settled on our current approach.

The Basics.

The skeleton HTML structure looks like this:

We paired this with the following CSS:

Essentially, we positioned each slide so that it fills 100% of the viewport’s width and height, and then set the z-index to order the slides so that #project-0 displays on top, while #project-1 and #project-2 are underneath. We used the “active” class to set a slide’s height to 100%; without this class, the slide’s height is 0 and thus hidden.

Note that if we removed the “active” class from the first—topmost—slide, it would reveal the slide beneath. The CSS3 transition ensures that this happens smoothly by animating the height between 100% and 0%.

The JavaScript.

Next, the JavaScript. There are a few things going on here. Let’s dive in and then discuss:

At the bottom of this fragment, we first set up a listener to the scroll event, which binds to elementScroll. This function detects the direction of scrolling and whether or not it has exceeded a certain threshold; if so, it will advance to the next slide accordingly. It does this by updating currentSlideIndex and then calling showSlide.

showSlide dutifully displays the correct slide by adding or removing the “active” class to each slide as appropriate. Toggling this class on a slide causes the CSS to kick in, which results in a nice transition.

The Secret Sauce.

The last element is the fixed “H” within each slide. The necessity of it being fixed actually influenced a lot of the implementation decisions. We of course achieved it with background-position:fixed, which ensures the background image remains fixed relative to the viewport.

We wanted to optimize our slide transitions with translateY and the like, but using translate would mean that the background image would move along with the slide, thus ruining the “reveal” effect over the “H.”

Why? Because translate avoids any expensive reflows by leveraging the power of the GPU to move the entire slide--background and all--with its own RenderLayer

So instead, we modified the height of each slide, collapsing it up and ensuring that the background remains fixed.


The advantage of this approach is that it can easily work on mobile devices as well, where the user may control the “wipe” effect with a touch gesture. So on a mobile device, we lost the “scroll-jacking” and instead used touch events to navigate through the slides:

We started by binding our functions to the various touch events. touchstart will log where the initial touch occurred, touchmove will update where the touch has travelled and update the delta, and touchend determines whether that distance is sufficient to display the next slide. Here, touchmove uses the delta to dynamically adjust the height of the slide, allowing the user to “drag it” by proportionally adjusting the slide’s height. We can use the same nextSlide and prevSlide as above to affect the transition.

We spent a large chunk of development time on this one component and were pleased with the results. It’s a simple but beautiful introduction to our work.

Read this.