Implementing basic touch support in JavaScript ✋
Don’t be afraid to just get in there and write your own 🤓
Touch support is becoming more and more likely to be required in your applications. Let’s take a look at why and then how you can combat this with some simple script 👊
The impact of responsive web design
Responsive web design is commonplace in the majority of projects these days. Developing web applications whilst considering an array of device sizes is the norm. In fact, many projects will prioritise mobile first.
Consider this scenario though. You’ve put the graft in and created a web app for your end client. It’s looking sweet across all your test devices. You’ve tapped about a bit and all seems good. You hand it over to the client…
Oh 😞, It’s not working. When I swipe, I expected this to do this, nothing happens… and I can’t rotate this?!
There can almost be a blurred definition of what going “responsive” entails. By definition, responsive design deals with the look and render of your site/app. But, a client or end user may be expecting an almost native experience for devices with touch support.
Native “look and feel” may be a little out of site without reaching for something like React Native. But, with a little JavaScript you can add basic touch support to your web applications. All is not lost 😅
For those in camp TL;DR, here’s a demo!
It’s all about events
It’s of no surprise that we listen for certain events to put together basic touch support. Much like binding an event listener for mouse interaction, you bind an event listener for a touch.
For the most basic touch gestures such as a tap. The browser can deal with these without any changes; a tap is a click handled by the “click” event.
How about more complex gestures such as swiping and pinching? These make the concept of touch more complicated. The result is that we need more events to listen for and bind to.
- Start the touch —
touchstart
- Listen for any movement during the touch to handle gestures —
touchmove
- End the touch —
touchend
- Abandon the touch —
touchcancel
/touchleave
A simple start
Let’s dive into a simple example 🏊
Here, we just change the body
style when different touch
events are fired 🎨
On touch start the body
color will change to red
, if we take our finger away, body
color will change to green
. If we start a touch, move our finger around, and then take it away, we would see red
, then blue
, then green
.
You can see this happening in the demo.
Going a little further — A basic swipe
One of the most requested touch gestures is horizontal swiping. This is usually required for carousel or galleries.
What are the logical steps for this gesture? 🚶
- The user starts by placing their finger on the screen —
touchstart
- The user moves their finger across the screen —
touchmove
- The user lifts their finger from the screen ending the swipe —
touchend
We could actually detect swipe detection in a very basic way by not using touchmove
. Using the information provided in the touchend
event we can determine the gesture.
This leads onto the anatomy of the TouchEvent
.
A TouchEvent
is much like any other event. But, we get extra information about how many touches there are and where. This information is critical to implementing touch gestures.
You can read more about the different properties of a TouchEvent
here 📖
A Touch object gives you various information about a Touch such as its location on screen. See here for more.
For a basic horizontal swipe, we can make use of the touchend
and touchstart
events. We only need the start and end location of our touch to determine the gesture.
Consider the following implementation;
There is a fair bit to take in there but we can break it down.
All we are doing is adding event listeners to the document.body
. As the TouchEvent
s fire, we update some CSS
variables and update some header content.
Starting with touchstart
- We check the amount of touches. We can assume a single finger swipe if
touches.length === 1
. - If we have the right amount of touches, we store the start position with
startX
. This is the value ofclientX
on theTouch
event. - Bind to the
touchmove
andtouchend
events. We also update theCSS
variable--bg
to show atouchstart
.
Moving with touchmove
We aren’t using touchmove
for anything important here. But we can give a little user feedback by updating some CSS
variables for translation
and background-color
. This is certainly important when trying to provide a better experience for your users. For a swipe you might move the element as it’s being touched.
We calculate the correct distance to translate our element by referencing the starting and current location of the touch. We work out whether to apply it in a negative manner or positive based on swipe direction.
Ending with touchend
- There will only be one solo touch within the
changedTouches
array of ourTouchEvent
. We grab the last location of ourtouch
using theclientX
property of this soloTouch
. - We can then use this value and compare it to the starting position of our touch in combination with a swipe limit. Why do we need a swipe limit? Without it, a user tapping the screen could trigger swipe logic. This is because their finger may have moved a mere pixel on the horizontal plane. For this implementation, we define a swipe limit of
50px
. Based on this comparison we can determine whether the user has swiped left or right 🎉 - Carry out the action we want for swiping and then tidy up and remove event listeners from
document.body
.
The rest is down to you! (And your clients 😅)
We’ve taken a look at implementing basic touch support for a swipe gesture. No extra libraries or frameworks required 🎉 We could do a lot more with our solution but this is just an intro. Desired experience for your apps will likely differ from app to app.
On top of that we have only looked at one gesture. There are still gestures such as pinch and rotate to consider. These require the use of multi-touch detection and a little extra thinking. You can see a demo of pinch zooming below.
As always, any questions or suggestions, please feel free to leave a response or tweet me 🐦!