Trends for 2016: Subtle Hover States

Around this time of year, there's always a lot of discussion around what will be the next big thing in web development. Will it be a new design style, lightweight JavaScript library or something with "2.0" at the end of it? I came across a collection of candidates on the Econsultancy blog and they make for interesting reading.

From an ecommerce point of view, however, there are a lot of considerations before deciding to embrace one of these potential trends, such as:

  • Suitability — you run a site whose goal is to convert visitors into customers, so you need to do things that induce conversions. Some changes, while attractive, will simply not help and may in fact hinder you. Think about user experience, particularly across all devices.
  • Weight — more code means more page weight, which means longer loading, processing and rendering times. From a performance point of view we always recommend keeping your site as light as possible.
  • Maintenance — once you make this change, are you going to be able to keep it up to date and fresh? You put it together once, if it breaks can you put it back together? If you've just found an amazing new JS library, are you just introducing a whole new level of (unnecessary) complexity?

So are there any worth using?

The Brief

Going through Econsultancy's list, it's clear that there are a few candidates for consideration that could meet this criteria. One in particular, 'more creative hover states', caught my attention. We already recommend a bold color and design for primary calls to action, but what we were to add a subtle change for the hover state — in particular one that triggers when a shopper hovers close to the button?

I thought about this and decided to see if I could come up with something to replicate this behavior. I came across a Stack Overflow question asking for help writing code that does just this, and one respondent offered some simple code, which I'm going to adapt and include below.

In short, I'm going to write some JavaScript and CSS, put it in a module and then include it in the module that affects add to cart buttons on product detail pages. What it'll do is modify the styling of these buttons whenever a user hovers their cursor near the button. As mobile users don't have cursors, naturally this'll only affect desktop users.

Note that the following code is only an illustration of how one could implement this functionality. Experienced developers will undoubtedly find other, possibly more elegant, ways to implement it or something similar.

Do the Prep Work

So, first and foremost, we need to do the standard steps for creating a new module such as:

  1. Creating a parent folder and sub-folders for JavaScript and Sass
  2. Adding an ns.package.json file
  3. Updating distro.json so that it's registered as a module and included in the CSS for shopping.css.

As this is basic stuff, I won't go into details of what you need to do (you can read previous tutorials or the documentation). For the sake of this tutorial, I'm going to call my module jQuery-hoverButton.

Add the JavaScript

The JavaScript I'm going to provide you is a modification of the respondent in the Stack Overflow question. Here's the code for jQuery-hoverButton.js:

define(
  'jQuery-hoverButton'
, [
    'jQuery'
  , 'Utils'
  ]
, function(
    jQuery
  , Utils
  )
{
  'use strict';

  jQuery.fn.hoverButton = function ()
  {
    if (canHover()) {
      jQuery('body').mousemove(function(event)
      {
        if(isNear(jQuery('[data-type="hover-near"]'), 120, event)) {
            jQuery('[data-type="hover-near"]').addClass('hover-button-highlight');
            jQuery('[data-type="hover-far"]').addClass('hover-button-lowlight');
        } else {
            jQuery('[data-type="hover-near"]').removeClass('hover-button-highlight');
            jQuery('[data-type="hover-far"]').removeClass('hover-button-lowlight');
        }
      });
    }

    return this;
  };

  function canHover ()
  {
    var viewport_width = Utils.getViewportWidth()
    ,   mobile_width_max = 768;

    return viewport_width > mobile_width_max;
  };

  function isNear (element, distance, event)
  {
    if (element.offset() && distance && event) {
      var left = element.offset().left - distance
      ,   top = element.offset().top - distance
      ,   right = left + element.width() + ( 2 * distance )
      ,   bottom = top + element.height() + ( 2 * distance )
      ,   x = event.pageX
      ,   y = event.pageY;

      return (x > left && x < right && y > top && y < bottom);
    }
  };

});

There are three main functions here:

  1. jQuery.fn.hoverButton — this binds the functionality to jQuery so that we can use it as if it were a jQuery method. It checks the screen width to see if it should be called (small screen devices are excluded) and then adds a listener for when the mouse moves. If it's near our designated element, it does some style changes via classes.
  2. canHover — if you're familiar with the article I wrote on sticky buttons then there's a similar function in that one that exists purely to prevent the main functionality from firing if the user is on a mobile (small-screened) device. We want the same functionality here because mobiles don't have cursors, and we have separate styling for mobile devices that means this stuff isn't appropriate anyway.
  3. isNear — this function does all of the calculations relating to whether or not the cursor is near the specified element or not.

You should be able to see how this all fits together. We're going to put the hover-near data attribute onto the button used for adding an item to the cart, then hover-far on the button next to it; strictly, this is a coincidental thing as we only really need to do something to the specified element, but because the style change will affect a thing next to it, we also need to make a style change to that element too. When the mouse is moved away from the element, the classes are removed (thus restoring their styling to normal).

Add the Sass

The styling is pretty basic. After all, the mission here is to add 'subtle' changes that the user will appreciate while also achieving our goal of increasing conversions. While your definition of subtle may vary from mine, let's just put the following in _jquery-hoverbutton.scss for now:

div[data-type="hover-near"],
div[data-type="hover-far"] {
    transition: width 1s;
}

.hover-button-highlight {
    width: 60%;
}
.hover-button-lowlight {
    width: 40%;
}

Pretty simple stuff: the main button we want to highlight (the add to cart button) grows to 60% width and the secondary button (the add to wishlist button) shrinks to 40% width. Then there's a transition animation to make the whole thing smooth.

Modify the Template

I want to change the buttons used on the product detail page, and these are generated in the item_details.tpl template, which are about half way down (do a search for "add-to-cart-button"). Now, because the width of the buttons is determined by the size of their containers (and not the buttons themselves) you need to add the hover-near and hover-far attributes to the containers of the the add to cart and add to wishlist buttons. For example:

<div class="item-details-actions-container">
  <div data-type="hover-near" class="item-details-add-to-cart">
    <button data-type="add-to-cart" data-action="sticky" class="item-details-add-to-cart-button" {{#unless isReadyForCart}}disabled{{/unless}}>
      {{translate 'Add to Cart'}}
    </button>
  </div>
  <div data-type="hover-far" class="item-details-add-to-wishlist" data-type="product-lists-control" {{#unless isReadyForWishList}} data-disabledbutton="true"{{/unless}}>
  </div>
</div>

Edit the View

Finally, you add the JavaScript as a dependency to your view; in this example, it is ItemDetails.View.js. Add jQuery-hoverButton as a dependency (it doesn't need to be passed as a parameter in the function) then find the initPlugins function. Add in this.$el.find('[data-type="hover-near"]').hoverButton(); to the function.

Note that for other views, you'll need to make sure that jQuery is a dependency and that something like an initPlugins function exists, and that this function is called within a showContent function. You can find out some more information on this in the sticky button tutorial.

Test the Work

Start your local server and visit a product detail page on your local site. You should see that when you hover your cursor close to the add to cart button, it slowly expands (and the add to wishlist button shrinks).

Considerations

Apart from the general ones mentioned at the top of this article, one particular consideration is performance. As the jQuery documentation for mousemove points out:

Keep in mind that the mousemove event is triggered whenever the mouse pointer moves, even for a pixel. This means that hundreds of events can be generated over a very small amount of time. If the handler has to do any significant processing, or if multiple handlers for the event exist, this can be a serious performance drain on the browser. It is important, therefore, to optimize mousemove handlers as much as possible, and to unbind them as soon as they are no longer needed.

In other words, because we've made any cursor movement trigger some JavaScript, this is will negatively affect performance. I imagine that one could probably replicate this functionality using entirely CSS. However, just because this adds weight does not mean you should avoid it — rather you should just keep it in mind and run tests on slower devices, to gauge the real life impact of this functionality. I'm sure there are many developers, designers and UX specialists who would argue that this sort of change is simply too frivolous to justify.

Extending the Idea

Obviously, these sorts of things don't need to only be applied when in a hover state. There's even a follow-up article on Econsultancy discussing other uses of hover effects, should you seek additional inspiration.

Alternatively, I've seen some sites apply the same principle when a user clicks on a search box: it expands and some subtle highlighting is added. Whether or not this is effective an improving conversions, to me I find it inviting.

If you have multiple effects that you wish to include then you could always write your code to support multiple types, and then pass through a parameter to the JavaScript from the template or view.

Summary

This article illustrates how you can implement a subtle style change to your site using a custom jQuery-powered plugin. These sort of subtle effects are growing increasingly common throughout the web, including some ecommerce sites. As with all design changes, you need to consider a number of factors before implementing them (such as whether there will be a performance cost, and whether that cost will increase conversions). Some changes can be effected through CSS alone, others require some help from JavaScript.

With the power of local servers, you're able to see how these changes will look and demo them. As noted in the roadmap, we are looking at adding Google Tag Manager support in the near future, which will mean easier integration with A/B testing services like Optimizely. Once these features are in place, I'll look into producing an article that'll show how you can test out a change like this and see if it really does help increase conversions.

Further Reading