Creating Fast Buttons for Mobile Web Applications
Ryan Fioravanti
January 2011
Background
Here at Google, we’re constantly pushing the boundaries of what’s possible in a mobile web application. Technologies like HTML5 allow us to blur the distinction between web apps and native apps on mobile devices. As part of that effort we’ve developed a technique for creating buttons that are far more responsive than plain HTML buttons. Previously for a button, or any clickable element, we might have just set up a click handler. For example:
<buttononclick='signUp()'>Sign Up!</button>
The problem with this approach is that mobile browsers will wait approximately 300ms from the time that you tap the button to fire the click event. The reason for this is that the browser is waiting to see if you are actually performing a double tap. For most buttons we are developing we know that there is no double click behavior that we want to handle, so waiting this long to start acting on the click is time wasted for users. We first developed this technique for the Google Voice mobile web app since we wanted users to be able to dial phone numbers rapidly.
Handling Touch Events
The technique involves a bit of JavaScript that allows the button to respond to touchend
events rather than click
events. Touchend
events are fired with no delay so this is significantly faster than click
events, however there are a few problems to consider:
- If the user tapped somewhere else on the screen and then invokes a
touchend
on the button then we should not fire a click. - If the user touches down on the button and then drags the screen a bit and then invokes a
touchend
on the button then we should not fire a click. - We want to highlight the button when the user touches down to give it a pressed state.
We can solve the first two problems by monitoring touchstart
and touchmove
events as well. We should only consider a touchend
on the button if there was previously atouchstart
on the button. Also if there exists a touchmove
anywhere that goes past a certain threshold from the touchstart
then we should not handle the touchend
as a click.
We can solve the third problem by adding an onclick
handler to the button as well. Doing so will allow the browser to properly treat it as a button, and our touchend
handler will ensure that the button is still fast. Also, the presence of an onclick
handler serves as a good fallback for browsers that don’t support touch events.
Busting Ghost Clicks
Adding the onclick
handler back to the button introduces one last ugly problem. When you tap the button, a click event will still be fired 300ms later. Now we run the risk of the click handler executing twice. This can be easily resolved by calling preventDefault
on the touchstart
event. Calling preventDefault
on touchstart
events will stop clicks and scrolling from occurring as a result of the current tap. We wanted users to be able to scroll even if they started their scroll on a button, so we didn’t consider this an acceptable solution. What we came up with to deal with these ghost clicks was called a click buster. What we do is simply add a click event listener to the body, listening on the capture phase. When our listener is invoked, we try to determine if the click was as a result of a tap that we already handled, and if so we call preventDefault
and stopPropagation
on it.
Fast Button Code
Here we will offer some code that implements the ideas we have just discussed.
Construct the FastButton with a reference to the element and click handler.
google.ui.FastButton=function(element, handler){ this.element = element; this.handler = handler; element.addEventListener('touchstart',this,false); element.addEventListener('click',this,false); }; google.ui.FastButton.prototype.handleEvent =function(event){ switch(event.type){ case'touchstart':this.onTouchStart(event);break; case'touchmove':this.onTouchMove(event);break; case'touchend':this.onClick(event);break; case'click':this.onClick(event);break; } };
Save a reference to the touchstart
coordinate and start listening to touchmove
and touchend
events. Calling stopPropagation
guarantees that other behaviors don’t get a chance to handle the same click event.
google.ui.FastButton.prototype.onTouchStart =function(event){ event.stopPropagation(); this.element.addEventListener('touchend',this,false); document.body.addEventListener('touchmove',this,false); this.startX =event.touches[0].clientX; this.startY =event.touches[0].clientY; };
When a touchmove
event is invoked, check if the user has dragged past the threshold of 10px.
google.ui.FastButton.prototype.onTouchMove =function(event){ if(Math.abs(event.touches[0].clientX -this.startX)>10|| Math.abs(event.touches[0].clientY -this.startY)>10){ this.reset(); } };
Invoke the actual click handler and prevent ghost clicks if this was a touchend
event.
google.ui.FastButton.prototype.onClick =function(event){ event.stopPropagation(); this.reset(); this.handler(event); if(event.type =='touchend'){ google.clickbuster.preventGhostClick(this.startX,this.startY); } }; google.ui.FastButton.prototype.reset =function(){ this.element.removeEventListener('touchend',this,false); document.body.removeEventListener('touchmove',this,false); };
Call preventGhostClick
to bust all click events that happen within 25px of the provided x, y coordinates in the next 2.5s.
google.clickbuster.preventGhostClick =function(x, y){ google.clickbuster.coordinates.push(x, y); window.setTimeout(google.clickbuster.pop,2500); }; google.clickbuster.pop =function(){ google.clickbuster.coordinates.splice(0,2); };
If we catch a click event inside the given radius and time threshold then we call stopPropagation
and preventDefault
. Calling preventDefault
will stop links from being activated.
google.clickbuster.onClick =function(event){ for(var i =0; i < google.clickbuster.coordinates.length; i +=2){ var x = google.clickbuster.coordinates[i]; var y = google.clickbuster.coordinates[i +1]; if(Math.abs(event.clientX - x)<25&&Math.abs(event.clientY - y)<25){ event.stopPropagation(); event.preventDefault(); } } }; document.addEventListener('click', google.clickbuster.onClick,true); google.clickbuster.coordinates =[];
Conclusion
At this point you should be able to easily create fast buttons. With a bit of fancy styling you can make them look and feel like native buttons according to the platform you are developing for. There are already a few mobile JavaScript libraries available that solve this same problem, but we haven’t yet seen any that provide the fallback for click events or a solution to the ghost clicks problem. We hope that browser developers will solve this problem in future releases by firing click events immediately when zooming is disabled on the website (using the viewport meta tag). In fact, this is already the case with the Gingerbread Android Browser.
相关推荐
Buttons 是基于 Sass 和 Compass 框架构建的各式各样的 Web 上的按钮集合。 标签:Buttons CSS框架
标题"Navigation Buttons for button"表明这是一个关于为Delphi按钮组件增添导航功能的资源。描述中的"a good navigation buttons for delphi best to try!"暗示这可能是一个高质量的导航按钮组件库,适用于Delphi...
"Agama Web Buttons"是一款专为程序员设计的高效工具,旨在帮助他们轻松创建各种自定义按钮,提升网页设计的质量和效率。这款软件提供了丰富的DIY功能,让程序员无需深入学习图形设计,也能制作出专业水准的网页元素...
Bootstrap and web applications 16 Browser compatibility 17 Summary 18 Chapter 2: Creating a Solid Scaffolding 19 Understanding the grid system 19 Building our scaffolding 20 Setting things up 21 ...
Buttons 2.0 是一款专为移动Web和桌面应用设计的高度可定制的CSS按钮库,旨在为开发者提供一套生产就绪、易于使用的按钮样式解决方案。这个库由Alex Wolfe开发,其版本5cdec1b包含了最新的特性与优化。在JavaScript...
fastButton可以解决两个问题:1.click在移动端使用时有300ms的延时,使用fastButton可以降低到10ms;2.tap在安卓端使用时会出现触发两次问题,使用fastButton可以解决这个问题。使用说明在压缩包中。
**PhoneGap 3.x Mobile Application Development Hotshot.2014.pdf** is a comprehensive guide designed to help developers create engaging and practical mobile applications for iOS and Android devices ...
An OIF application is designed for creating more traditional web applications with a fixed structure. This involves setting up the basic layout and adding UI building blocks. ###### 2.2.2 Creating a ...
- **Master Pages and Themes:** Design patterns for creating reusable layouts and styles, enhancing consistency and maintainability across web applications. - **Server Controls:** Built-in controls ...
《jQuery Mobile:构建移动Web应用的关键技术》 jQuery Mobile(jqMobile)是jQuery库的一个扩展,专门用于构建响应式和触控友好的移动Web应用程序。它提供了一套完整的UI组件和交互模式,使得开发者能够快速地创建...
本教程将详细讲解如何利用CSS3创建10种不同颜色的线性渐变按钮,以实现美观且动态的Web Buttons。线性渐变在网页设计中被广泛应用,可以提升网页的视觉效果,让按钮看起来更加吸引人。 首先,我们来理解一下CSS3...
在Web开发领域,jQuery Mobile是一个强大的框架,专为移动设备设计,提供了一套完整的用户界面(UI)组件和交互效果,以实现跨平台、响应式的移动Web应用。"jquery.mobile demo.zip"这个压缩包包含的是jQuery Mobile...
Buttons提供一套给用户添加自定义按钮的特性,让按钮看起来和表格是一个整体。 Buttons提供了一些基本的按钮,比如打印,导出之类的按钮,也提供了API让用户自己扩展按钮,触发自定义的操作。 当在DataTable中显示...
这不,一个名叫Actual Title Buttons的小工具就是专门用来对标题栏中的图标进行更改的,没想到吧。通过使用这一工具,你可以为普通窗口标题栏增加“最小化至系统托盘”和“总在最上面”两个特殊的按钮。
for Android buttons Overview Demo Application : Download APK Features Border (stroke, radius, color) Background (normal, focus) Icon (Drawable, font icon) FontAwesome Custom font Icon ...