Presented by Tran Trong Thanh / @trongthanh
* not include proxy browsers
One Must Know
Make use of built-in inputs and interactive elements.
Your custom JS components can't beat the native one.
<input type="date">
<input type="time">
<input type="month">
<input type="range">
<select>
<option value="">Jump To Section:</option>
<optgroup label="Introduction">
<option value="about">About</option>
</optgroup>
...
</select>
Link: all built-in iOS Safari inputs
* Range input is customized with CSS for better interaction.
/* Disable text selection for all */
* {
-webkit-user-select: none;
}
/* Enable back text selection on text inputs */
input, textarea {
-webkit-user-select: text;
}
And use :active
instead
/* disable tap highlight color */
* {
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
/* use pseudo class :active instead */
.tappable:active {
transform: translateY(2px); /* browser prefix needed */
}
HWA rendering through CSS3's 3D transform
/* Enable HWA on a particular element */
.hwa {
-webkit-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
Note: only use HWA rendering when needed.
Overuse may cause GPU memory shortage and result in crash/hang.
Source: Why Moving Elements With Translate() Is Better Than Pos:abs Top/left
if ('geolocation' in navigator) {
/* geolocation is available */
navigator.geolocation.getCurrentPosition(function(position) {
alert('Your position: ' + position.coords.latitude + ' - ' + position.coords.longitude);
}); //second param is fail handler
} else {
alert('Your browser doesn\'t support Geolocation API');
}
Is A Must
em, rem
vh, vw, vmin, vmax
<head>
...
<!-- Allow the app to runs in fullscreen mode -->
<meta name="apple-mobile-web-app-capable" content="yes"/>
<!-- Control the status bar appearance in fullscreen mode (new in iOS7) -->
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<!-- Control viewport sizes, scaling... behaviors -->
<meta name="viewport" content="width=device-width,height=728,
initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
<!-- Disable/enable telephone number detection -->
<meta name="format-detection" content="telephone=no">
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
...
</head>
Link: iOS Safari supported meta tags
Link: Mobile Boilerplate
@media
(-webkit-min-device-pixel-ratio: 2),
(min-resolution: 192dpi) {
/* Retina-specific stuff here */
}
*Link: Responsive image solution
You Must Embrace
Mouse Events
(desktops)
Touch Events
(mobile webkit and the like)
Pointer Events
(IE Mobile*)
* In IE10 Mobile, it is
MSPointerDown, MSPointerUp...
$('#foo').on('click', function() {
//stuff
});
$('#foo').on('mouseup touchend MSPointerUp pointerup', function(event) {
//stuff
});
var POINTER_END = 'mouseup';
if ('ontouchend' in window) { POINTER_END = 'touchend'; }
else if ('onmspointerup' in window) { POINTER_END = 'MSPointerUp'; }
else if ('onpointerup' in window) { POINTER_END = 'pointerup'; }
document.getElementById('foo').addEventListener(POINTER_END, function() {
//stuff
});
document.addEventListener('DOMContentLoaded', function() {
//enable FastClick
FastClick.attach(document.body);
document.getElementById('fastclick-btn').addEventListener('click', function(e) {
clickNote.textContent += 'Click! ';
});
});
Link: FastClick library
Update: New workarounds for 300ms delay on major mobile browsers
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
.scroll-box {
width: 200px;
height: 200px;
overflow-y: scroll; /* has to be scroll, not auto */
}
.touch {
-webkit-overflow-scrolling: touch;
}
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
var output = document.getElementById('scroll-output');
var scrollBox = document.getElementById('scroll-box');
scrollBox.addEventListener('scroll', function() {
output.value = scrollBox.scrollTop;
});
Work around: use iScroll library
:hover
state is triggered after first tap and mantained until user tap again on another target..submenu {
position: absolute;
overflow: hidden;
height: 0; opacity: 0;
transition: height 0.5s, opacity 0.5s; /* browser prefix needed */
}
.menu:hover .submenu {
height: 400%; /* there are 4 items */
opacity: 1;
}
Push
To The Next Level
requestAnimationFrame
instead of setInterval
** A good animation library like GSAP will help using the best approach
Demo
Demo
iOS Safari with OSX Safari developer tool demo
Android Chrome with desktop Chrome devtool demo
This presentation was first presented in June 2014 by Thanh Tran for Nau Studio team.
Revised first time on January 2016
The slides is powered by RevealJS presentation framework with a modified Beige theme.
Source code of the slides is available on github.
© 2016 Nau Studio. All rights reserved.