Sam Croft

A designer/developer on HTML, CSS, JavaScript and PhoneGap

Responsive button feedback in PhoneGap apps: a better alternative to -webkit-tap-highlight-color

  • 10 comments

Filed in: android, apps, Cordova, css, iOS, PhoneGap, zepto

I don’t think I’m alone when I say that the most important thing with a PhoneGap app is that it feels responsive to a users touch. It goes without saying that the easiest argument that web/hybrid app neigh-sayers have is touch response lag. The first thing they’re going to point fingers at and tweet to their native compadres is how many milliseconds it takes for a button to light up when it is touched.

Feedback is important.

Mobile webkit browsers know feedback is important

They really do. Touch any (ok, most) hyperlinks in mobile Safari or Chrome and, unless the developer has overwritten the default event, it will rather delightfully light up the link text/button in a grey background glow. Instant feedback that you have touched something. This is a realtime event that fires the millisecond that you tap a hyperlink. There is no 300ms delay, that you find with click events if you’re using Javascript.

This effect occurs due to a CSS property called -webkit-tap-highlight-color.

The [aesthetic] problems with -webkit-tap-highlight-color

The problem with -webkit-tap-highlight-color is that, other than the colour itself, there is no control over the appearance of it. And while it’s acceptable for text links it’s terrible when put into practice on a beautiful interface where you want to highlight a button being tapped… the very millisecond it is tapped.

The reason it’s terrible is that -webkit-tap-highlight-color effectively puts a rectangular background, with a 3px, or so, corner radius, over the hyperlink. It also gives the highlight a padding of about 3px. Take a look at what it does:

Demonstrating how -webkit-tap-highlight-color brings several aesthetic problems in PhoneGap
Two buttons. The one on the left is inactive. The one on the right has been tapped and is in its active state. This clearly shows how -webkit-tap-highlight-color creates an undesirable effect.

Let’s look at that a little bit closer.

The effects of -webkit-tap-highlight-color viewed on a retina device
The same buttons viewed on a retina device for clarity

That’s something pretty ghastly that you have no control over, other than the background colour itself.

Fortunately you can easily modify the grey background glow with a CSS property called -webkit-tap-highlight-color that you can use to set the colour of the highlight using RGBa. Like so:

a {
	-webkit-tap-highlight-color: rgba(255,0,0,0.5);
}

Now the grey background glow is gone. And replaced with a red background glow. Good times. Except it’s not.

A better alternative to -webkit-tap-highlight-color

Recently I’ve been using a simple alternative to using this property. It yields the same responsive feel while retaining full control over the appearance. It’s not a pure CSS solution, but that’s OK as you will be using JavaScript in your app anyway.

There are several steps to this alternative:

Suppressing the -webkit-tap-highlight-color

Firstly you will need to prevent -webkit-tap-highlight-color from being applied appearing when you tap a hyperlink. That’s just a bit of CSS:

a {
	-webkit-tap-highlight-color: rgba(0,0,0,0);
}

What this does is overwrite the default -webkit-tap-highlight-color, for a elements, with a completely transparent colour. In this case, black with an alpha-transparency of 0—completely transparent.

Creating a custom tap highlight colour

Secondly you will need to create one, or more, custom tap highlight colours to add – when a touch event occurs – to your link/button elements.

I’m going to use a really common design trend in app buttons that I’m seeing at the moment. I call it the active gradient mirror style. It goes something like this; a button will have a vertical gradient background – light grey to a darker grey for example – for its inactive state. It’s tapped, active, state will mirror the gradient—in this example, dark grey to a lighter grey. The iOS and Android Instagram and Twitter apps use this technique to great effect with their buttons.

Something like this:

A screenshot of an alternative to -webkit-tap-highlight-color being demonstrated on a retina device
This side-by-side comparison, viewed on a retina device, shows how the inactive (on the left) and active (on the right) state can give a more aesthetic appearance when compared to the standard -webkit-tap-highlight-color
a {
	background: -webkit-linear-gradient(top, rgba(0,0,0,0.1) 0%,rgba(0,0,0,0.3) 100%);
	background: linear-gradient(to bottom, rgba(0,0,0,0.1) 0%,rgba(0,0,0,0.3) 100%);
}

a.tapped {
	background: -webkit-linear-gradient(top, rgba(0,0,0,0.3) 0%,rgba(0,0,0,0.1) 100%);
	background: linear-gradient(to bottom, rgba(0,0,0,0.3) 0%,rgba(0,0,0,0.1) 100%);
}

Note: I am only using the webkit vendor prefix (to support older mobile webkit browsers versions) and the W3C linear-gradient specification, used in current webkit browser versions, for the purposes of this example.

Rather self-explanatory this. A base, inactive, a element background and a tapped (active) class that can be added to the a element when touch events are fired.

Handling the touch events with a bit of Javascript to complete the effect

Now that the CSS is complete the effect just requires a few lines of Javascript to handle the touch events. There are a number of things to bear in mind here.

  • when a finger is touching a button
  • when a finger stops touching a button
  • when a finger taps a button

That’s quite a few things to be constantly looking out for. And while jQuery might be your go-to JavaScript library, it doesn’t support touch events out of the box. But there is an alternative JavaScript library, that you’ve likely heard of of – if not already used – that is optimised for touch events. It’s called Zepto.js and it makes checking the for above events a breeze. It’s also considerably lighter in file size than jQuery’s ever-bloating core library.

Using zepto.js to manage the button touch states

Firstly let’s add an ‘active’ class to a button when it is touched and remove it when it is no longer being pressed:

$('a').on('touchstart', function(e){
	$(this).addClass('tapped');
});

$('a').on('touchend', function(e){
	$(this).removeClass('tapped');
});

So here we’re leveraging two touch events; touchstart and touchend. Both of these events occur instantaneously. This pretty much completes the effect. To go a step further and handle a tap event is simple with zepto.js is simple too:

$('a').on('tap', function(e){
	e.preventDefault();
	
	//do your thing
	
	return false;
});

Here is a short video of the effect in action.

It’s worth noting that Zepto.js handles tap events in a specific way. A tap event is triggered when a button is touched and the finger is released within 750ms. If the finger remains touching the button for longer than 750ms the tap event will not fire. The touchstart event (where we have added a tapped class above) will remain, however, until the finger is released.

And there you have it. Simple, streamlined and super-responsive buttons in your PhoneGap app.

About the author

I'm Sam Croft - a thirtysomething designer/developer and co-founder of Running in the Halls Ltd—a web and app development studio in Huddersfield, UK. I was educated in graphic design and now specialise in front-end web and app development; my main passion being usability and accessibility. I strongly believe web apps (vs native) are the future and love developing for mobile using the wonderful PhoneGap.

I am a massive sports fan - Formula One in particular. I live in the Pennines with my beautiful wife, Alex. Occasionally I own a large scruffy beard.

I tweet about all of my interests - you should follow me. I also have a .

  • http://twitter.com/cleggypdc Paul Clegg

    Nice Article. I’ve found that using a separate class for a button tap / press sometimes isn’t as responsive as I’d like it to be. For instance when I have used a sprite image as the button background. I have opted to use the a:active class in place of any javascript whatsoever.

  • http://samcroft.co.uk/ Sam Croft

    Hi Paul. That sounds really interesting, thanks for sharing. I’m going to give that a go when I get some time.

  • John

    When you are developing what is your process for testing. Gestures don’t work on a desktop, so I am wondering during your dev process how do you do your testing with a code like this that only works on a mobile device. I have been using a library the works on desktops as well as mobile so I can easily do simple testing on my desktop. However, all I really need is for mobile in the end.

  • http://blowintopieces.com/ imissmyjuno

    Since you’re really only using the touch events, why not just use vanilla Javascript in the first place, e.g. document.addEventListener(‘touchstart’, …) ?

  • http://samcroft.co.uk/ Sam Croft

    I considered this but vanilla JS, to my knowledge, doesn’t have an actual tap event. Zepto does a good job of handling tap, longTap and other useful touch events.

  • http://blowintopieces.com/ imissmyjuno

    It sure does (W3 spec: http://www.w3.org/TR/2011/WD-touch-events-20110505/#the-touchstart———event), although support for multi-touch events is spotty on Android:

    http://www.quirksmode.org/mobile/tableTouch.html

    Zepto appears to offer some niceties in the form of double-tap support and proper cancelling in case of scrolling:

    https://github.com/madrobby/zepto/blob/master/src/touch.js

  • http://samcroft.co.uk/ Sam Croft

    I am aware of JavaScript’s touch events. The zepto tap event is more than just binding touchstart, however.

    https://github.com/madrobby/zepto/blob/master/src/touch.js

  • jeliasson

    I personally use Ripple Emulator (Chrome plugin) for emulating things like different vendors and models (screen res), accelerometer, geolocation and events. While this does not support testing of multi-touch gestures, I find this tool very handy for quick testing. I’ll hope you appreciate it.

  • Holda

    a:hover { background: -webkit-linear-gradient(top, rgba(0,0,0,0.3)0%,rgba(0,0,0,0.1) 100%); background: linear-gradient(to bottom, rgba(0,0,0,0.3)0%,rgba(0,0,0,0.1) 100%);
    }

  • Velda

    Response can be also acoustic and vibrating, so I post here my plugin https://github.com/VVelda/device-feedback which give you option to handle it to have app which porvide native feel to user. :-)