Experimenting with Custom Functionality Appropriate to a User's Scrolling Behaviour

View DemoView on GitHub

Scrolling is one of the web's most basic methods of navigation, allowing a user to move to a position on a page in multiple ways: dragging the scroll bar, using a mouse-wheel, swiping on a touch enabled device, pressing space, clicking an anchor link, and so on.

The way in which a user scrolls can reveal a lot about their intentions. For example, if a user is scrolling up towards the top of a page very quickly, are they focused on content? Most likely not. We can assume they're looking for something such as navigation links. Knowing this, we can make those links appear sooner to save the user having to scroll to the very top of the page.

In this article, I experiment with improving a user's experience based on their scrolling behaviour and determine whether this is a technique applicable to the real-world.

Existing Methods of Determining User Behaviour

Possibly the most successful use for determining user behaviour on the web today is a method known as Hover Intent.

Hover Intent is described (although not named) in Ben Kamens' Breaking Down Amazon's Mega Dropdown. This technique determines whether a sub menu should remain open and prevents other sub menus from opening based on the user's cursor direction. If it appears the user is moving toward the sub menu belonging to a parent link, then it will remain open regardless of the user hovering over other parent links.

There is also a jQuery plugin available called HoverIntent, which works in a similar way to Amazon's drop-down menus, except HoverIntent works on a timer rather than determining cursor direction. It improves upon jQuery's hover() method by only initiating an hover event when the user's cursor has slowed down on a particular element. This way of determining intent ensures no drop-down menus open when the user quickly hovers over them in the process of trying to reach another element for example.

Uses for Determining Scroll Intent with scrollIntent.js

As we've seen with Hover Intent, the functionality of a web page can change to assist the user based on their behaviour. How can this be applied to the method of scrolling and what uses does it have?

To experiment with this methodology, I created scrollIntent.js, a JavaScript plugin that allows the executing of functionality specific to a user's scrolling behaviour.

The following are some example uses for determining Scroll Intent and how they were implemented using scrollIntent.js.

Infinite Scrolling with a Footer

The use of infinite scrolling is controversial; whilst it has its advantages, it comes with plenty of disadvantages too, as described in Infinite Scrolling: Let's Get to The Bottom of This.

In short, Infinite Scrolling is a technique used to load and append more content as a user reaches the bottom of a page. This creates an endless feed of content, allowing a user to continuously read without ever having to break their focus to navigate to the next page. It has its downsides though; content can lose hierarchy, scroll bars don't represent the amount of data available, infinite content can overwhelm the user, the footer can never be reached, and so on. All problems which can lead to user frustration.

We can't solve all of these issues but we can offer a solution to not being able to reach the footer by determining the user's intent whilst scrolling.

Let's take a couple of use cases on a typical web page:

  • A user is scrolling very slowly using their mouse-wheel, moving toward the bottom of the page
  • A user is pressing their keyboard's down key every so often, moving toward the bottom of the page
  • A user is scrolling very quickly using their mouse-wheel, moving toward the bottom of the page

In the first two use cases, we can assume the user is reading and focused on the page's content; they are moving down the page very slowly. For these behaviours, the Infinite Scrolling functionality is perfect; the user is focused on the content, so let's give them more as they need it.

In the third use case however, the user is scrolling far too quickly to be able to read the content, we can assume that rather than reading content, they are looking for something else on the page. If they reach the bottom of the page, then do they really want more content? In this case, let's forgo the Infinite Scrolling functionality and allow the user to naturally reach the page's footer where they can find navigation links or other information more appropriate to the behaviour they're exhibiting.

Using scrollIntent.js, we can selectively execute the Infinite Scrolling functionality, like so:

    var actions = [

      //ACTION 1
      {
        scrollMethod: ["mousewheel", "scrollbar"],
        direction: "down",
        maxSpeed: 100,
        waypoint: "100%",
        waypointRelativeTo: document.body,
        waypointOffset: -300,
        callback: function() {

          ajax.load();
        }
      },

      //ACTION 2
      {
        scrollMethod: ["down", "space"],
        keyPressesPerEvent: 1,
        waypoint: "100%",
        waypointRelativeTo: document.body,
        waypointOffset: -300,
        callback: function() {

          ajax.load();
        }
      }
    ]
    scrollIntent = new ScrollIntent(window, actions);

The above code will initiate scrollIntent.js on the window (the web page) and specifies our use cases -- described as "actions" in scrollIntent.js. Both actions will execute ajax.load() (the functionality used to load more content and create Infinite Scrolling) but only when all conditions from one of the following actions are met:

  • Action 1:

    • The user is scrolling by using the mouse-wheel or scrollbar
    • The user is scrolling down (toward the bottom of the page)
    • The user is scrolling slower than 100px per 250ms*
    • The user passes a waypoint 300px from the bottom of the page**
  • Action 2:

    • The user is scrolling by pressing the down or space keys
    • The user is pressing the down/space key once per action (rather than holding it down)
    • The user passes a waypoint 300px from the bottom of the page**

*scrollIntent.js will check specified conditions every 250ms during the period the user is scrolling. This value can be changed in the options.

**This condition is made up of waypoint, waypointRelativeTo, and waypointOffset.

When the user scrolls, these conditions will be checked every 250 milliseconds to determine if the user has completed one of the defined actions. If the user does complete an action, then more content is loaded else they just reach the bottom of the page.

Infinite Scrolling with a Footer demo

Intuitive Navigation

Let's assume the user has spent 5 or 10 minutes reading a page with a lot of content. They're a long way from the top of the page where the navigation resides and they want to go to another page. There are multiple ways to reach the top of a page quickly but we can't rely on the user always knowing the fastest method. The user starts spinning their mouse-wheel and it takes them a good 5 spins and several seconds to reach the top. Can we improve that experience for them?

With the following code, we can hide a fixed position navigation menu after a 300px waypoint and then show that menu when the user scrolls anywhere after that 300px waypoint at a speed greater than 150px per 250ms:

var actions = [

  // ACTION 1
  {
    waypoint: 300,
    direction: "down",
    callback: function() {

      menu.hide();
    }
  },

  // ACTION 2
  {
    waypoint: 300,
    direction: "up",
    callback: function() {

      menu.show();
    }
  },

  // ACTION 3
  {
    minWaypoint: 300,
    minSpeed: 150,
    callbacksPerAction: 1,
    callback: function() {

      menu.show();
    }
  }
];
var scrollIntent = new ScrollIntent(window, actions, options);

Again, scrollIntent has been initiated on window (the web page), then the following actions are described:

  • Action 1

    • Hide the menu when the user scrolls down over a 300px waypoint
  • Action 2

    • Show the menu when the user scrolls up over a 300px waypoint
  • Action 3

    • When the user scrolls faster than 150px per 250ms, show the menu (only once per action and anywhere after the 300px waypoint)

With these actions applied to scrollIntent.js, when it appears the user is no longer focused on content and trying to reach somewhere on the page, the navigation header will appear to assist them, and save the user having to scroll all the way to the top of the page.

Intuitive Navigation demo

Other Uses for Determining User Intent

The following are some other ways in which determining user intent could be used.

Data Collection

The Scroll Intent examples I've described above make large presumptions about how a user behaves. To be able to provide the most accurate functionality specific to a user's intent, a large amount of research and testing would be required.

Prior to implementing any custom functionality, determining user intent could be used to collect and send that data to your server, enabling you to make more accurate assumptions about how users behave.

Type Intent

Over the last several years, the web has seen the introduction of search suggestions. This is where the contents of a user's search query is sent to a server as the user types, and then returns suggestions based on what they've typed so far.

Although useful, it seems somewhat wasteful to always try to make suggestions when the user is typing quickly.

When a user is typing quickly into a search field and exhibiting a behaviour that suggests they know exactly what they are searching for, do they really need suggestion functionality? By making suggestions only when the user appears to be typing slow, the server needn't be queried as much.

Capturing Method of Interaction and Running With It

Often a user has multiple ways of interacting with a page. Take for example, scrolling. The user may use a mousewheel or touch device, press up/down/space/page up/page down on their keyword or use their cursor to interact with the scrollbar -- all ways of making a page scroll. By determining which of these methods they use, a page could change to better accommodate the user's behaviour or provide tips on how else they could achieve the same goal.

Capturing User Mistakes/Misuse

Sometimes a user may complete an action that the website page/application doesn't intend for them to do. For example, on a page with drag 'n' drop functionality, the user may drop an element into an area that isn't a drop zone, by monitoring their behaviour, you could alert them to the fact the drop zone is elsewhere by making it subtly flash or rumble.

Conclusion

By providing custom functionality appropriate to a user's behaviour, we can present the user with a more tailored experience to them, but can it work in a real-world application?

In the Infinite Scrolling with a Footer demo, the infinite scrolling functionality only executes when the user is scrolling below a certain speed at a particular point on the page. Sometimes the user will see additional content load, other times not. This may prove to be confusing and frustrating for a user because the functionality to them does not appear consistent and with no indication of what is happening.

If the Infinite Scrolling with a Footer demo were to succeed in the real-world, the way in which more content is loaded would need a lot of user testing to ensure the experience is seamless. With so many ways in which a page can scroll and so many user behaviour patterns though, to achieve a seamless experience for all users would most likely be impossible.

It can be argued that the Intuitive Navigation demo also presents a lack of consistency -- showing and hiding the navigation header when the user scrolls quickly/slowly. Without any indication of why the header is showing/hiding the user may see it as a random and inconsistent event. Unlike the Infinite Scrolling demo however, it isn't integral to their interaction with the page. The fact that the header appears when the user exhibits the behaviour of no longer focusing on content assists them to navigate elsewhere quicker. A greater benefit to the user that outweighs the minor inconsistency in my opinion.

Providing user-aware functionality is used to enhance a page, without affecting existing functionality, then I believe determining user intent can improve the usability of a page.

Currently, the web is built to account for many user behaviours but rarely extends to tailor itself to a specific user's behaviour beyond its initial delivery. It seems that as web developers and designers, this isn't a mindset we have. To make the web a more sophisticated place then, perhaps we should begin thinking about user-aware functionality and have its application in the back of our minds when building the future of the web.

scrollIntent.js and its documentation can be found on GitHub.

Useful? Buy me a coffeeUseful? Buy me a coffee

Ian Lunn is a Front-end Developer with 12 years commercial experience, author of CSS3 Foundations, and graduate of Internet Technology. He creates successful websites that are fast, easy to use, and built with best practices.