Page 1
© 2013 Amazon.com, Inc. and its affiliates. All rights reserved. May not be copied, modified, or distributed in whole or in part without the express consent of Amazon.com, Inc.
Russell Beattie, Amazon
November 15, 2013
Coding Tips You Should Know Before Distributing Your HTML5 Web App on Mobile Devices
Friday, November 15, 13
Page 2
Agenda• Welcome• HTML5 Mobile Web App Basics
• Setup• DevTools Demo
• Coding Tips and Best Practices• HTML• CSS• Javascript• Offline
Friday, November 15, 13
Page 3
HTML5 Mobile Web App Basics
Friday, November 15, 13
Page 4
Setup• Text Editor• Modern Desktop Browser
• Chrome, Firefox, Safari, IE 11, etc.
• Modern Mobile Browser or Tester• Amazon Web App Tester, Chrome, etc.
• Android SDK• For remote debugging
Friday, November 15, 13
Page 5
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Basic HTML5 Web App Template<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Friday, November 15, 13
Page 6
Basic HTML5 Web App Template<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Friday, November 15, 13
Page 7
<!DOCTYPE html>
Basic HTML5 Web App Template<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Friday, November 15, 13
Page 8
<!DOCTYPE html><html>
Basic HTML5 Web App Template<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Friday, November 15, 13
Page 9
<!DOCTYPE html><html> <head>
Basic HTML5 Web App Template<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Friday, November 15, 13
Page 10
<!DOCTYPE html><html> <head> <meta charset="UTF-8">
Basic HTML5 Web App Template<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Friday, November 15, 13
Page 11
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title>
Basic HTML5 Web App Template<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Friday, November 15, 13
Page 12
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">
Basic HTML5 Web App Template<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Friday, November 15, 13
Page 13
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>
Basic HTML5 Web App Template<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Friday, November 15, 13
Page 14
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css">
Basic HTML5 Web App Template<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Friday, November 15, 13
Page 15
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body>
Basic HTML5 Web App Template<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Friday, November 15, 13
Page 16
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div>
Basic HTML5 Web App Template<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Friday, November 15, 13
Page 17
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script>
Basic HTML5 Web App Template<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Friday, November 15, 13
Page 18
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Basic HTML5 Web App Template<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style> html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style> <link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body></html>
Friday, November 15, 13
Page 19
DevTools Demo• Connecting (via WebSockets or TCP/IP)• Live modification of page (CSS, HTML)• Interaction with device via inspection button• Debugging (JavaScript, Network, etc.)• Frame-rate / GPU• Profiling
Friday, November 15, 13
Page 20
Coding Tips and Best Practices
Friday, November 15, 13
Page 21
HTML
Friday, November 15, 13
Page 22
<meta name="apple-touch-fullscreen" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="UVM Home">
<link rel="apple-touch-startup-image" href="/startup.png">
<link rel="apple-touch-icon" sizes="128x128" href="niceicon.png"><link rel="apple-touch-icon-precomposed" sizes="144x144" href="img/touch/apple-touch-icon-144x144-precomposed.png"><link rel="apple-touch-icon-precomposed" href="img/touch/apple-touch-icon-57x57-precomposed.png">
<link rel="shortcut icon" href="img/touch/apple-touch-icon.png">
Headers - Apple
Friday, November 15, 13
Page 23
<!-- Google --><meta name="mobile-web-app-capable" content="yes"><link rel="shortcut icon" sizes="196x196" href="nice-highres.png"><link rel="shortcut icon" sizes="128x128" href="niceicon.png">
<!-- Blackberry --><meta name="HandheldFriendly" content="true"><meta name="cursor-event-mode" value="native"><meta http-equiv="x-rim-auto-match" content="none">
<!-- Microsoft --><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta http-equiv="cleartype" content="on"><meta name="msapplication-TileImage" content="pics/logowin8pin.png"/><meta name="msapplication-TileColor" content="#B20099"/><meta name="msapplication-badge" value="frequency=1440;polling-uri=http://www.example.com/Win8TileNotification.php" />
Headers - Google, Blackberry, Microsoft
Friday, November 15, 13
Page 24
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico"/><link rel="shortcut icon" href="favicon.ico" />
<meta name="format-detection" content="telephone=no"><meta name="format-detection" content="address=no"/>
<link rel="dns-prefetch" href="page2.html">
<meta name="description" content=""/><meta name="keywords" content=""/>
Headers - Firefox, W3C, etc.
Friday, November 15, 13
Page 25
<form> Date: <input type="date" value="2013-09-03" name="dateInput"> Datetime: <input type="datetime" name="datetimeInput"> Datetime-local:
<input type="datetime-local" value="2013-09-03T20:00" name="datetime-local"> Email: <input type="email" name="emailInput"> Month: <input type="month" value="2013-09" name="monthInput"> Number: <input type="number" name="numberInput"> Password: <input type="password" name="passwordInput"> Range: <input type="range" name="rangeInput"> Search: <input type="search" name="searchInput"> Tel: <input type="tel" name="telInput"> Time: <input type="time" name="timeInput"> Url: <input type="url" name="urlInput"> </form>
Input Field Types
Friday, November 15, 13
Page 26
<input type="url" name="urlInput" required pattern="https?://.+">
...
input:required:invalid, input:focus:invalid { background-image: url(/images/invalid.png); background-position: right top; background-repeat: no-repeat;}
input:required:valid { background-image: url(/images/valid.png); background-position: right top; background-repeat: no-repeat;}
Required and Validation
Friday, November 15, 13
Page 27
CSS
Friday, November 15, 13
Page 28
html { -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -webkit-user-select: none;}
body{ -webkit-font-smoothing: antialiased; /* Fix for webkit rendering */ -webkit-text-size-adjust: 100%;}
/* don't let "actions" dialog to come up when element is touch/held */.prevent-action { -webkit-touch-callout: none;}
Interaction
Friday, November 15, 13
Page 29
/* no dragging of element at all */.content p.no-drag { -webkit-user-drag: none;}
/* drags entire element, not the text/selection */.sidebar div.element-drag { -webkit-user-drag: element;}
/* change the character used to hide user passwords */input[type="password"] { -webkit-text-security: square;}
textarea[contenteditable] { -webkit-appearance: none;}
Interaction continued
Friday, November 15, 13
Page 30
/* position */
-webkit-transform: translate(0, 0);-webkit-transform: translateZ(0);-webkit-transform: translate3d(0, 0, 0);
/* scale */
-webkit-transform: scale(0);
/* rotation */
-webkit-transform: rotate(0);
/* opacity */
opacity: 0.5;
Hardware acceleration
Friday, November 15, 13
Page 31
@-webkit-keyframes pulse { from { -webkit-transform: scale(.1); } to { -webkit-transform: scale(1); }}
div { -webkit-animation-name: pulse; -webkit-animation-duration: 2s; -webkit-animation-iteration-count: infinite; -webkit-animation-timing-function: ease-in-out; -webkit-animation-direction: alternate;}
// Javascriptcontent.addEventListener("webkitAnimationIteration", countAnims, false);
Animations
Friday, November 15, 13
Page 32
// CSS
.box {left: 40px;-webkit-transition: all 0.3s ease-out;
}div.box.totheleft {
-webkit-transform: translate3d(0, 0, 0);}div.box.totheright {
-webkit-transform: translate3d(80px, 0, 0);}
// Javascript
window.addEventListener("webkitTransitionEnd", function() { // Handle the end of the transition}, false);
Transitions
Friday, November 15, 13
Page 33
@media screen and (orientation:portrait) { /* portrait-specific styles */}
@media screen and (orientation:landscape) { /* landscape-specific styles */}
@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi) { /* Style adjustments for viewports that meet the condition */}
Media Queries
Friday, November 15, 13
Page 34
JavaScript
Friday, November 15, 13
Page 35
var mql = window.matchMedia("(orientation: portrait)");if(mql.matches) { // Portrait orientation} else { // Landscape orientation}
mql.addListener(function(m) { if(m.matches) { // Changed to portrait } else { // Changed to landscape }});
// Resizing window.addEventListener("resize", function() { // window.innerHeight > window.innerWidth ... }, false);
Orientation Detection
Friday, November 15, 13
Page 36
var meta = document.createElement("meta");
meta.setAttribute('name','viewport');
var content = 'initial-scale='; content += 1 / window.devicePixelRatio; content += ',user-scalable=no';
meta.setAttribute('content', content); document.getElementsByTagName('head')[0].appendChild(meta);
Device Resolution
Friday, November 15, 13
Page 37
// no pre-rendering
function render() { drawSpaceShip(context); requestAnimationFrame(render);}
// pre-rendering
var sprite = document.createElement('canvas');sprite.width = 64;sprite.height = 64;var spriteCtx = sprite.getContext('2d');drawSpaceShip(spriteCtx);
function render() { context.drawImage(sprite, 0, 0); requestAnimationFrame(render);}
Canvas pre-rendering
Friday, November 15, 13
Page 38
// Slower
for (var i = 0; i < points.length - 1; i++) { var p1 = points[i]; var p2 = points[i+1]; context.beginPath(); context.moveTo(p1.x, p1.y); context.lineTo(p2.x, p2.y); context.stroke();}
// Faster
context.beginPath();for (var i = 0; i < points.length - 1; i++) { var p1 = points[i]; var p2 = points[i+1]; context.moveTo(p1.x, p1.y); context.lineTo(p2.x, p2.y);}context.stroke();
Canvas batch calls
Friday, November 15, 13
Page 39
// redraw entire canvascontext.fillRect(0, 0, canvas.width, canvas.height);
// redraw only 'dirty' areascontext.fillRect(last.x, last.y, last.width, last.height);
// faster way to redraw canvascontext.clearRect(0, 0, canvas.width, canvas.height)
Canvas Redraw Regions
Friday, November 15, 13
Page 40
function animate(time){
//random drawing context.clearRect(0, 0, canvas.width, canvas.height); context.beginPath(); context.rect(x, y, 50, 50); context.fillStyle = '#8ED6FF'; context.fill();
// Old way: // window.setTimeout(animate, 1000/60);
// New way: window.requestAnimationFrame(animate);
}
RequestAnimationFrame
Friday, November 15, 13
Page 41
var bstyle = document.body.style; // cache
bstyle.padding = "20px"; // reflow, repaintbstyle.border = "10px solid red"; // another reflow and a repaint
bstyle.color = "blue"; // repaint only, no dimensions changedbstyle.backgroundColor = "#fad"; // repaint
bstyle.fontSize = "2em"; // reflow, repaint
// new DOM element - reflow, repaintdocument.body.appendChild(document.createTextNode('hello...'));
Reflows and repaints
Friday, November 15, 13
Page 42
// Slower
var elem = document.getElementById('animated');elem.style.fontSize = (elem.offsetWidth / 10) + 'px';elem.firstChild.style.marginleft = (elem.offsetWidth / 20) + 'px';
// Faster
var elem = document.getElementById('animated'), elemWidth = elem.offsetWidth;elem.style.fontSize = (elemWidth / 10) + 'px';elem.firstChild.style.marginleft = (elemWidth / 20) + 'px';
Minimize dimension or location queries
Friday, November 15, 13
Page 43
function SomeObject() { var self = this; this.lastExecThrottle = 500; // limit to one call every "n" msec this.lastExec = new Date(); this.timer = null; this.resizeHandler = function() { var d = new Date(); if (d-self.lastExec < self.lastExecThrottle) { if (self.timer) { window.clearTimeout(self.timer); } self.timer = window.setTimeout(self.resizeHandler, self.lastExecThrottle); return false; // exit } self.lastExec = d; // update "last exec" time self.callResizeHandlerFunctions(); }}
var someObject = new SomeObject();window.onresize = someObject.resizeHandler;
Debounce Events
Friday, November 15, 13
Page 44
Offline
Friday, November 15, 13
Page 45
AddType text/cache-manifest .manifestAddType text/cache-manifest .appcacheAddType application/x-web-app-manifest+json .webapp
Server MIME Types
Friday, November 15, 13
Page 46
CACHE MANIFEST# Version 1.0# filename: app.manifest or name.appcacheCACHE:index.htmlGame-Break.mp3Game-Death.mp3Game-Shot.mp3Game-Spawn.mp3main.jsmain.cssthree.min.js
...
<html manifest="app.manifest">
App cache manifest
Friday, November 15, 13
Page 47
{ "name": "Flip.io", "description": "Flip.io - 999 Word Puzzles. A simple, yet challenging word puzzle that will entertain novices and lexicographers alike. Presented with 10 word definitions and scrambled tiles of letter combos, can you find all the words?", "launch_path": "/", "icons": { "60": "/flip60.png", "128": "/flip128.png" }, "developer": { "name": "Russell Beattie", "url": "http://flip.io" }, "default_locale": "en", "fullscreen": "true"}
W3C Web App Manifest
Friday, November 15, 13
Page 48
{ "verification_key": "insert your verification key from the App File(s) tab", "launch_path": "index.html", "permissions": [ "iap", "geolocation", "auth" ], "type": "web", "version": "0.1a", "last_update": "2013-04-08 13:30:00-0800", "created_by": "webappdev"}
Amazon Mobile Web App Platform Manifest
Friday, November 15, 13
Page 49
Real World App Demo
Friday, November 15, 13
Page 50
Please give us your feedback on this presentation
As a thank you, we will select prize winners daily for completed surveys!
MBL301 Thank You
@RussB • [email protected]
developer.amazon.com/webapps
Friday, November 15, 13