A Better Ghost Button Hover Effect

I was visiting Clearleft’s website the other day and noticed a ‘ghost button’ on the home page that was a little bit, well, off.

Moving my cursor across the screen the button ‘jumped’ when hovering. Only slightly (really) but enough for me to take a dive into Firefox’s developer tools.

Using border

image of before

In the animated gif above we can see how, when the cursor moves over the button gets a little wider and taller and in doing so makes it look a little ‘off’.

The code used for this effect on the button is something akin to this:

.button-cta {
    border: 1px solid #fff;
}
.button-cta:hover {
  border: 2px solid #fff;
}

This makes the button appear to be 2px wider and 2px taller on hover and means that it ‘moves’ on the page when hovered as it pushed the button down by a pixel and across by a pixel.

I wondered if there was a more pragmatic, progressive fix for this.

Making it better box-shadow

Instead of using an actual border property for the effect I tried using box-shadow. It seems to work pretty well in this case and doesn’t make the button ‘jump’ at all when hovered.

after

In the animated gif above we can see that, now using box-shadow, we get a similar effect but without the button jumping when the cursor hovers over it.

The CSS I added to the button (removing the CSS for the border) was something like this:

.btn-cta {
    box-shadow: 0 0 0 1px #fff;
}
.btn-cta:hover {
    box-shadow: 0 0 0 2px #fff;
}

In CodePen

Animated images are all well and good and the code examples above don’t really show you too much. So I’ve created a quick CodePen with working examples of a button using border and one using box-shadow.

See the Pen a better ghose button by Stuart Robson (@sturobson) on CodePen.

On Support

It’s 2016, browser support for box-shadow is pretty good (if you go with global statistics). According to caniuse.com it’s available on 91.33% of browsers being used daily. That other ~8 percent though. IE8 and Opera mini (5–8), let’s not forget those. We need to look at doing something similar.

IE8 Fallback

For IE8 we can use a conditional comment to target that browser by having a HTML class available. We could perhaps keep the border or we could remove the border and add text-decoration on hover, something like:

.lt-ie8 .btn-cta {
  border: 1px solid #fff;
}
.lt-ie8 .btn-cta {
    text-decoration: underline;
}

Opera mini

Instead of creating a fallback, let’s look at making something progressively enhanced. Let’s first off add some JavaScript that will test if the browser supports box-shadow:

if (document.createElement("detect").style.boxShadow === "") {
  document.getElementsByTagName("html")[0].className += " boxshadow";
}

Now we can write some CSS that will work giving Old IE, Opera Mini and the original border effect and if the browser does have box-shadow and JavaScript doesn’t fail to load we get the nicer effect using box-shadow:

.btn-cta {
    border: 1px solid currentColor;
    box-shadow: 0 0 0 1px currentColor;
}
.btn-cta:hover {
  border: 2px solid currentColor;
  box-shadow: 0 0 0 2px currentColor;
}
.boxshadow .btn-cta {
  border: 0;
}
.boxshadow .btn-cta:hover {
  border: 0;
}

Over Engineering

Is this solution too much? I guess when you look at supporting as many browsers as you possibly can, then maybe it looks that way. Perhaps you could forgo the support for Opera Mini (5–8) as the button will still have the whitespace around it to make it look not like a paragraph of text. You could change how you create the 'button'. Perhaps only add a style reset for anything with box-shadow and leave OldIE and older Opera mini browsers with a default button style. Whatever's fit for yours and your users needs. Personally I’d be happy to add a couple more lines of CSS for this so that it can work for as many browsers as possible.