This presentation is an HTML5 website
Press → key to advance.
Having issues seeing the presentation? Read the disclaimer
Slides controls, press:
*Including other next generation technologies of the Web Development stack
Expect the unexpected
// use localStorage for persistent storage // use sessionStorage for per tab storage saveButton.addEventListener('click', function () { window.localStorage.setItem('value', area.value); window.localStorage.setItem('timestamp', (new Date()).getTime()); }, false); textarea.value = window.localStorage.getItem('value');
Save text value on the client side (crash-safe)
var db = window.openDatabase("DBName", "1.0", "description", 5*1024*1024); //5MB db.transaction(function(tx) { tx.executeSql("SELECT * FROM test", [], successCallback, errorCallback); });
See the generated database: Developer > Developer Tools > Storage
var idbRequest = window.indexedDB.open('Database Name'); idbRequest.onsuccess = function(event) { var db = event.srcElement.result; var transaction = db.transaction([], IDBTransaction.READ_ONLY); var curRequest = transaction.objectStore('ObjectStore Name').openCursor(); curRequest.onsuccess = ...; };
<html manifest="cache.appcache">
window.applicationCache.addEventListener('updateready', function(e) { if (window.applicationCache.status == window.applicationCache.UPDATEREADY) { window.applicationCache.swapCache(); if (confirm('A new version of this site is available. Load it?')) { window.location.reload(); } } }, false);cache.appcache:
CACHE MANIFEST # version 1.0.0 CACHE: /html5/src/logic.js /html5/src/style.css /html5/src/background.png NETWORK: *
Turn off your internet connection and refresh this page!
Stay connected
var worker = new Worker('task.js'); worker.onmessage = function(event) { alert(event.data); }; worker.postMessage('data');task.js:
self.onmessage = function(event) { // Do some work. self.postMessage("recv'd: " + event.data); };
Loading Route...
Try dragging the map while the complex route is being calculated (you will only be able to do that with Workers!)
var socket = new WebSocket('ws://html5rocks.websocket.org/echo'); socket.onopen = function(event) { socket.send('Hello, WebSocket'); }; socket.onmessage = function(event) { alert(event.data); } socket.onclose = function(event) { alert('closed'); }
Full-duplex, bi-directional communication over the Web: Both the server and client can send data at any time, or even at the same time. Only the data itself is sent, without the overhead of HTTP headers, dramatically reducing bandwidth.
if (window.webkitNotifications.checkPermission() == 0) { // you can pass any url as a parameter window.webkitNotifications.createNotification(tweet.picture, tweet.title, tweet.text).show(); } else { window.webkitNotifications.requestPermission(); }
Note: Use this button if you also want to reset the permissions
Enter your twitter user name to show your last tweet as a notification
Deeper integration with the Operating System
document.addEventListener('dragstart', function(event) { event.dataTransfer.setData('text', 'Customized text'); event.dataTransfer.effectAllowed = 'copy'; }, false);
document.querySelector('#dropzone').addEventListener('drop', function(e) { var reader = new FileReader(); reader.onload = function(evt) { document.querySelector('img').src = evt.target.result; }; reader.readAsDataURL(evt.dataTransfer.files[0]); }, false);
<a href="src/star.mp3" draggable="true" class="dragout" data-downloadurl="MIMETYPE:FILENAME:ABSOLUTE_URI_TO_FILE">download</a>
var files = document.querySelectorAll('.dragout'); for (var i = 0, file; file = files[i]; ++i) { file.addEventListener('dragstart', function(e) { e.dataTransfer.setData('DownloadURL', this.dataset.downloadurl); }, false); }
( this feature is only available in Google Chrome )
window.requestFileSystem(window.TEMPORARY, 1024 * 1024, function(fs) { // fs.root is a DirectoryEntry object. fs.root.getFile('log.txt', {create: true}, function(fileEntry) { fileEntry.createWriter(function(writer) { // writer is a FileWriter object. writer.onwrite = function(e) { ... }; writer.onerror = function(e) { ... }; var bb = new BlobBuilder(); bb.append('Hello World!'); writer.write(bb.getBlob('text/plain')); }, opt_errorHandler); } }, opt_errorHandler);
( The FileSystem API is currently only implemented in Google Chrome 9+ )
if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(function(position) { var latLng = new google.maps.LatLng( position.coords.latitude, position.coords.longitude); var marker = new google.maps.Marker({position: latLng, map: map}); map.setCenter(latLng); }, errorHandler); }
window.addEventListener('deviceorientation', function(event) { var a = event.alpha; var b = event.beta; var g = event.gamma; }, false);
This sample requires FF3.6+ or Google Chrome on a device with a built in accelerometer or iOS 4.2.
<input type="text" x-webkit-speech />
Speech input is not enabled in your browser.
Try running Google Chrome with the --enable-speech-input
flag.
More meaningful elements
<body> <header> <hgroup> <h1>Page title</h1> <h2>Page subtitle</h2> </hgroup> </header> <nav> <ul> Navigation... </ul> </nav> <section> <article> <header> <h1>Title</h1> </header> <section> Content... </section> </article> <article> <header> <h1>Title</h1> </header> <section> Content... </section> </article> </section> <aside> Top links... </aside> <figure> <img src="..."/> <figcaption>Chart 1.1</figcaption> </figure> <footer> Copyright ©
<time datetime="2010-11-08">2010</time>. </footer> </body>
<input list="cars"/> <datalist id="cars"> <option value="BMW"/> <option value="Ford"/> <option value="Volvo"/> </datalist> <menu> <command type="command">Save as...</command> </menu> <details> <summary>HTML 5</summary> This slide deck teaches you everything you need to know about HTML 5. </details>
<meter min="0" max="100" low="40" high="90" optimum="100" value="91">A+</meter> Your score is:A+
<progress>working...</progress> Download is:
<progress value="75" max="100">3/4 complete</progress> Goal is:
<link rel="alternate" type="application/rss+xml" href="http://myblog.com/feed"/> <link rel="icon" href="/favicon.ico"/> <link rel="pingback" href="http://myblog.com/xmlrpc.php"/> <link rel="prefetch" href="http://myblog.com/main.php"/> ... <a rel="archives" href="http://myblog.com/archives">old posts</a> <a rel="external" href="http://notmysite.com">tutorial</a> <a rel="license" href="http://www.apache.org/licenses/LICENSE-2.0">license</a> <a rel="nofollow" href="http://notmysite.com/sample">wannabe</a> <a rel="tag" href="http://myblog.com/category/games">games posts</a> ...
<div itemscope itemtype="http://example.org/band"> <p>My name is <span itemprop="name">Neil</span>.</p> <p>My band is called <span itemprop="band">Four Parts Water</span>.</p> <p>I am <span itemprop="nationality">British</span>.</p> </div>
<ul id="tree1" role="tree" tabindex="0" aria-labelledby="label_1"> <li role="treeitem" tabindex="-1" aria-expanded="true">Fruits</li> <li role="group"> <ul> <li role="treeitem" tabindex="-1">Oranges</li> <li role="treeitem" tabindex="-1">Pineapples</li> ... </ul> </li> </ul>
<style> [required] { border-color: #88a; -webkit-box-shadow: 0 0 3px rgba(0, 0, 255, .5); } :invalid { border-color: #e88; -webkit-box-shadow: 0 0 5px rgba(255, 0, 0, .8); } </style>
<input type="text" required /> <input type="email" value="some@email.com" /> <input type="date" min="2010-08-14" max="2011-08-14" value="2010-08-14"/> <input type="range" min="0" max="50" value="10" /> <input type="search" results="10" placeholder="Search..." /> <input type="tel" placeholder="(555) 555-5555" pattern="^\(?\d{3}\)?[-\s]\d{3}[-\s]\d{4}.*?$" /> <input type="color" placeholder="e.g. #bbbbbb" /> <input type="number" step="1" min="-5" max="10" value="0" />
type="text"
type="number"
type="email"
type="tel"
2D & 3D
<audio id="audio" src="sound.mp3" controls></audio> document.getElementById("audio").muted = false;
<video id="video" src="movie.webm" autoplay controls></video> document.getElementById("video").play();
<canvas id="canvas" width="838" height="220"></canvas> <script> var canvasContext = document.getElementById("canvas").getContext("2d"); canvasContext.fillRect(250, 25, 150, 100); canvasContext.beginPath(); canvasContext.arc(450, 110, 100, Math.PI * 1/2, Math.PI * 3/2); canvasContext.lineWidth = 15; canvasContext.lineCap = 'round'; canvasContext.strokeStyle = 'rgba(255, 127, 0, 0.5)'; canvasContext.stroke(); </script>
<canvas id="canvas" width="838" height="220"></canvas> <script> var gl = document.getElementById("canvas").getContext("experimental-webgl"); gl.viewport(0, 0, canvas.width, canvas.height); ... </script>
<html> <svg> <circle id="myCircle" class="important" cx="50%" cy="50%" r="100" fill="url(#myGradient)" onmousedown="alert('hello');"/> </svg> </html>
Presentation & Styling
.row:nth-child(even) { background: #dde; } .row:nth-child(odd) { background: white; }
div { display: inline-block; }
input[type="text"] { background: #eee; }
:not(.box) { color: #00c; } :not(span) { display: block; }
h2:first-child { ... } div.text > div { ... } h2 + header { ... }
@font-face { font-family: 'LeagueGothic'; src: url(LeagueGothic.otf); } @font-face { font-family: 'Droid Sans'; src: url(Droid_Sans.ttf); } header { font-family: 'LeagueGothic'; }
div { text-overflow: ellipsis; }
Play with the slider on this and further pages!
-webkit-column-count: 2;
-webkit-column-rule: 1px solid #bbb;
-webkit-column-gap: 2em;
In March 1936, an unusual confluence of forces occurred in Santa Clara County.
A long cold winter delayed the blossoming of the millions of cherry, apricot, peach, and prune plum trees covering hundreds of square miles of the Valley floor. Then, unlike many years, the rains that followed were light and too early to knock the blossoms from their branches.
Instead, by the billions, they all burst open at once. Seemingly overnight, the ocean of green that was the Valley turned into a low, soft, dizzyingly perfumed cloud of pink and white. Uncounted bees and yellow jackets, newly born, raced out of their hives and holes, overwhelmed by this impossible banquet.
Then came the wind.
It roared off the Pacific Ocean, through the nearly uninhabited passes of the Santa Cruz Mountains and then, flattening out, poured down into the great alluvial plains of the Valley. A tidal bore of warm air, it tore along the columns of trees, ripped the blossoms apart and carried them off in a fluttering flood of petals like foam rolling up a beach.
This perfumed blizzard hit Stevens Creek Boulevard, a two-lane road with a streetcar line down its center, that was the main road in the West Valley. It froze traffic, as drivers found themselves lost in a soft, muted whiteout. Only the streetcar, its path predetermined, passed on...
div {
-webkit-text-fill-color: black;
-webkit-text-stroke-color: red;
-webkit-text-stroke-width: 0.00px;
}
color: rgba(255, 0, 0, 0.75); background: rgba(0, 0, 255, 0.75);
color: hsla( 128 74% 33% 1.00
face: border-radius: 0px; left eye: border-radius: 0px; right eye: border-radius: 0px; base white: border-radius: 0px; mouth: border-radius: 0px; nose: border-radius: 0px; left black eye: border-radius: 0px; right black eye: border-radius: 0px;
background: -webkit-gradient(linear, left top, left bottom, from(#00abeb), to(white), color-stop(0.5, white), color-stop(0.5, #66cc00))
background: -webkit-gradient(radial, 430 50, 0, 430 50, 200, from(red), to(#000))
text-shadow: rgba(64, 64, 64, 0.5) 0px 0px 0px;
box-shadow: rgba(0, 0, 128, 0.25) 0px 0px 0px;
text-shadow: rgba(0, 0, 0, 0.5) 0 0px 0px; background: -webkit-gradient(linear, left top, left bottom, from(rgba(200, 200, 240, 0)), to(rgba(255, 255, 255, 0))); border-radius: 0px; -webkit-box-reflect: below 10px -webkit-gradient(linear, left top, left bottom, from(transparent), to(rgba(255, 255, 255, 0)));
#logo { background: url(logo.gif) center center no-repeat; background-size: ; }
Resize me! »
div { background: url(src/zippy-plus.png) 10px center no-repeat, url(src/gray_lines_bg.png) 0 center repeat-x; }
.box { display: -webkit-box; -webkit-box-orient: ; } .box .one, .box .two { -webkit-box-flex: 1; } .box .three { -webkit-box-flex: 3; }
.box { display: -webkit-box; -webkit-box-pack: ; -webkit-box-align: ; }
#box.left { margin-left: 0; } #box.right { margin-left: 1000px; } document.getElementById('box').className = 'left'; document.getElementById('box').className = 'right';
#box { -webkit-transition: margin-left 1s ease-in-out; } document.getElementById('box').className = 'left'; document.getElementById('box').className = 'right';
Hover over me:
-webkit-transform: rotateY(45deg); -webkit-transform: scaleX(25deg); -webkit-transform: translate3d(0, 0, 90deg); -webkit-transform: perspective(500px)
#threed-example { -webkit-transform: rotateZ(5deg); -webkit-transition: -webkit-transform 2s ease-in-out; } #threed-example:hover { -webkit-transform: rotateZ(-5deg); }
Now press 3!
@-webkit-keyframes pulse { from { opacity: 0.0; font-size: 100%; } to { opacity: 1.0; font-size: 200%; } } 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; }
*Please make a better use of it. We don't want a new blink tag ;)
Improvements to the core platform
var el = document.getElementById('section1'); el.focus(); var els = document.getElementsByTagName('div'); els[0].focus(); var els = document.getElementsByClassName('section'); els[0].focus();
var els = document.querySelectorAll("ul li:nth-child(odd)"); var tds = document.querySelectorAll("table.test > tr > td"); var el = document.querySelector("table.test > tr > td"); // el == tds[0]
<div id="out" data-id="good" data-name="joe" data-screen-name="user1"></div>
// Add new data attributes via JS. var el = document.querySelector('#out'); el.setAttribute('data-foo', 'bar'); var html = []; for (var key in el.dataset) { html.push(key, ': ', el.dataset[key], '<br>'); } el.innerHTML = html.join('');
Output:
id: good name: joe screenName: user1 foo: bar
<div id="main" class="shadow rounded"></div>
var el = document.querySelector('#main').classList; el.add('highlight'); el.remove('shadow'); el.toggle('highlight'); console.log(el.contains('highlight')); // false console.log(el.contains('shadow')); // false console.log(el.classList.toString() == el.className); // true
Output:
<div id="main" class="rounded"></div>
link.addEventListener('click', function(event) { // manually add a value to the history stack // without making the browser load any new page history.pushState('Contact Page Form', 'Contact Page', '/contact'); }); // capture navigation in case we want to change, // for instance, some content when it changes window.addEventListener('popstate', function(event) { document.querySelector('h1').innerText = event.state; // 'Contact Page Form' });
Client side:
<meta http-equiv="X-UA-Compatible" content="chrome=1">
Server side:
X-UA-Compatible: chrome=1
Try to load this presentation in IE!
HTML5 = Next Generation Features for Modern Web Development