For 2011: The Latest in HTML5
cancelRequestAnimationFrame renamed to cancelAnimationFrame.
Prefixed in Canary/WebKit/FF nightly<meta name="referrer" content="never">a[download] attribute. Demo
canvas.toDataURL('image/webp')xhr.responseType = 'arraybuffer'; can no longer be set with sync. requestsBlob/File in IndexedDB
xhr.responseType = 'arraybuffer'reader.readAsArrayBuffer(file)ws.binaryType = 'arraybuffer'ctx.getImageData().data == Uint8ClampedArraywebkitPostMessage()video.webkitSourceAppend(new Uint8Array(...))
Style elements mid-document, confined to immediate parent:
<article>
<p>This p will have inherited color.</p>
<section>
<style scoped>
p { color: red; }
</style>
<p>This p will be red.</p>
</section>
</article>
calc()
width: -webkit-calc(200px - 100); width: -webkit-calc(2 * 50%); width: -webkit-calc(200px / 2); color: hsl(-webkit-calc(120), -webkit-calc(75%), 0.5); background-position: -webkit-calc(50% + 5px) center;
min()
width: -webkit-min(150px, 100px, 200px); width: -webkit-min(90px + 50px, 100px); width: -webkit-min(100px, 100%); /* where 100% is 200px; */
max()
width: -webkit-max(150px, 100px, 200px); width: -webkit-max(200px - 50px, 100px); width: -webkit-max(100px, 100%); /* where 100% is 200px; */
cross-fade()
background-image: -webkit-cross-fade(url(first.png),
url(second.png), 50%);
@-webkit-keyframes fading {
0% { background-image: -webkit-cross-fade(
url(first.png), url(second.png), 0%); }
100% { background-image: -webkit-cross-fade(
url(first.png), url(second.png), 100%); }
}
Flow content into specified regions:
<style>
#content {
-webkit-flow-into: bodytext;
}
.region {
width: 200px;
height: 200px;
-webkit-flow-from: bodytext;
-webkit-region-overflow: break;
}
@region #region1 { /* webk.it/71487 */
p { color: navy; }
}
</style>
<div id="region1" class="region"></div>
<div id="region2" class="region"></div>
<div id="content">
<p>Lorem ipsum dolor ... or a nunc.</p>
<div><img src="...">Lorem ipsum dolor ... or a nunc.</div>
</div>
Access to the Document's named flows:
var namedFlow = document.getFlowByName('body_text');
namedFlow.overflow // true if flow doesn't fit in all its regions.
// Ordered NodeList of elements that constitute the named flow.
var els = namedFlow.contentNodes;
// NodeList of regions that contain (part of) the target node.
var regions = namedFlow.getRegionsByContentNode(targetNode);
Determine if content fits in a region:
Element.regionOverflow // 'overflow', 'fit', 'empty', 'undefined' // Array of Ranges for the content that is positioned in the region. var ranges = Element.getRegionFlowRanges();
document.webkitGetFlowByName()) available in WebKit but implementation isn't complete.
<style>
.exclusion {
-webkit-wrap-flow: both;
-webkit-wrap-margin: 10px;
-webkit-padding-margin: 10px;
-webkit-shape-outside: circle(50%, 50%, 50%);
position: absolute;
}
</style>
<div>
<div class="region">Donec metus messa, mollis...</div>
Lorem ipsum dolor sit amet...
</div>
Demo: Adobe Prototype Build
display: -webkit-box.Vertically center content:
section {
display: -webkit-flex;
-webkit-align-items: center;
-webkit-justify-content: center;
-webkit-flex-flow: row no-wrap; /* both default values */
}
section > div:first-child {
-webkit-flex: 2 0 100px; /* first div will be 2x wider */
}
See Fronteers article for more info.
Apply filter effects to any DOM element:
video, img {
-webkit-filter: grayscale(0.5) blur(10px);
}
--enable-accelerated flag for hardware accelerated content.
// unknown, ethernet, wifi, 2g, 3g, 4g, none navigator.connection.type
navigator.connection and navigator.onLine implemented in Android 2.2+MutationEvents because they were:
<ol contenteditable>
<li>Press enter</li>
</ol>
<script>
var ol = document.querySelector('ol');
var observer = new WebKitMutationObserver(function(mutations, observer) {
console.log(mutations, observer);
});
observer.observe(ol, {
subtree: true, // observe the subtree rooted at ol
childList: true, // include childNode insertion/removals
characterData: true, // include textContent changes
attribute: true // include changes to attributes within the subtree
});
// observer.disconnect() // Cease observations
</script>
ArrayBuffer to new context (worker or window).postMessage() because of semantic changes:
worker.webkitPostMessage(arrayBuff, [arrayBuff]); // 2nd arg: list of transferables. window.webkitPostMessage(arrayBuff, targetOrigin, [arrayBuff]);
worker.webkitPostMessage({
view1: uInt8Array,
buffer2: anotherBuffer,
username: 'johndoe'
}, [uInt8Array.buffer, anotherBuffer]);
See HTML5Rocks Update for more info.
.byteLength goes to zero.
var ab = new ArrayBuffer(1);
worker.webkitPostMessage(ab, [ab]);
if (ab.byteLength) {
alert('Transferables are not supported in your browser!');
} else {
// Transferables are supported.
}
Stream a File, Blob, or ArrayBuffer:
window.URL = window.webkitURL || window.URL;
window.WebSocket = window.WebSocket || window.MozWebSocket;
var ws = new WebSocket('ws://example.com/sock', ['dumby-protocol']);
ws.binaryType = 'blob'; // or 'arraybuffer'
ws.onopen = function(e) {
console.log('Connection OPEN');
};
ws.onmessage = function(e) {
// e.data.__proto__ === Blob.prototype
document.querySelector('img').src = URL.createObjectURL(e.data);
};
See HTML5Rocks Updates for more info on changes.
mousemove, mousedown, ... ) continue to fire, but only on the target.mouseover, mouseout) are not fired.MouseEvent contains new e.movementX / e.movementY, which
are the deltas in movement.
// Note: webkit and moz vendor prefixes are not shown.
document.body.addEventListener('click', function(e) {
if (!document.isFullScreen) { // Chrome requires fullscreen to succeed.
document.body.requestFullScreen();
} else if (navigator.pointer.isLocked) {
navigator.pointer.unlock();
} else {
document.cancelFullScreen();
}
}, false);
document.addEventListener('fullscreenchange', function(e) {
if (document.isFullScreen) {
navigator.pointer.lock(document.body, function() {
console.log(e.movementX, e.movementY);
}, function(e) {
console.log('Mouse lock unsuccessful', e);
});
}
}, false);
document.body.addEventListener('pointerlocklost', function(e) { ... }, false);
navigator.gamepads = navigator.webkitGamepads || navigator.MozGamepads;
var requestAnimationFrame = window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame;
var cancelAnimationFrame = window.webkitCancelAnimationFrame ||
window.MozCancelAnimationFrame;
var controllers = {}; // Stash connected controllers.
var reqId = null;
function onConnected(e) {
controllers[e.gamepad.index] = e.gamepad;
runAnimation();
}
function onDisconnected(e) {
delete controllers[e.gamepad.index];
cancelAnimationFrame(reqId);
}
window.addEventListener('webkitgamepadconnected', onConnected, false);
window.addEventListener('webkitgamepaddisconnected', onDisconnected, false);
window.addEventListener('MozGamepadDisconnected', onDisconnected, false);
window.addEventListener('MozGamepadConnected', onConnected, false);
function runAnimation() {
reqId = requestAnimationFrame(runAnimation);
for (var i in controllers) {
var pad = navigator.gamepads[i];
//pad.id // string for brand/style of connected device.
//pad.index // index of the gamepad in navigator.gamepads.
//pad.timestamp // last time data for the gamepad was updated.
//pad.axes // array of all axes values [-1..1, -1..1].
//pad.buttons // array of all button values [0..1, 0..1, 0..1].
}
}
Demo
( FF/Chrome )