Tactical HTML5

Alex Russell <slightlyoff@google.com>
Sept 27th, 2010

Agenda

  1. Lay of The Land
  2. Thinking Like A Browser
  3. What's New In CSS
  4. The New Tags
  5. Intermission
  6. Mobile First
  7. DOM, Unplugged
  8. Lab!

Grab The Lab!

http://infrequently.org/10/lab.tar.gz

Pull Up These Slides & Follow Along

http://infrequently.org/10/web2expo_nyc/tactical_html5.html

Who Am I?

Formerly: Web Dev, Security Engineer

Recently: Project Lead for Dojo, TC39 Invited Expert

Currently: Engineer on Chrome & Chrome Frame

I'm not a designer,
but I fight IE 6 so you don't have to.

Who Are You?

What's This All About Then?

HTML5 ~= HTML + CSS + JS APIs

XHTML [1,2] lost

Along with XBL, DocBook, XSLT, SVG, and pretty much anything with "XML" in the title or description.

Back To Messy Evolution!

Thesis

The web is slow and cumbersome.

HTML5 is our opportunity to do small things about it.

Mobile forces the issue.

What's So Slow, Anyway?

  • Legacy browsers
  • Poorly constructed pages
  • Geography
  • Plugins
  • Topology
  • DNS
  • Scripts

What Bits Can We Address?

  • Legacy browsers
  • Poorly constructed pages
  • Geography
  • Plugins
  • Topology
  • DNS
  • Scripts

What Bits Can We Address?

  • Legacy browsers
  • Poorly constructed pages
  • Plugins
  • Scripts

Goal: give the user UI faster.

Thinking Like A Browser

Trees All The Way Down

How WebKit Thinks About Your Page:

  1. Tokenized markup
  2. DOM tree
    • RenderObject tree
    • RenderStyle tree
    • RenderLayer tree
    • LineBox tree

Some trees are built and used lazily, others are built pre-emptively.

...unless they can't be

JavaScript Can Force Synchronization

Script tags block parsing
<script src="foo.js"></script>
<div>You won't see this until the script loads and executes</div>
...unless you tell them not to
<script src="foo.js" defer async></script>
<div>
  "defer" puts code execution just before onload <br>
  "async" allows it to be evaluated out of order
</div>

JavaScript Can Force Synchronization (contd.)

Measurement forces pending style tree re-building
<script>
  // Computing sizes accurately requires stopping 
  // the world while we do any pending style calculations, e.g., 
  // from a newly-loaded style sheet.

  // This may take a very long time!
  var throwaway = document.body.clientWidth;

  // But this will probably be instant:
  var throwaway2 = document.body.firstChild.clientWidth;
</script>

How Bad?

  • It's not just scripts
  • Multiple requests for the same thing may lock on the cache
  • DNS is expensive and slow
  • Limited HTTP connections
  • We lack good prioritization

Request order matters

Thinking Like A Browser Engineer

  • Compatibility is king
    • Don't be "the guy who broke the web"
  • Correctness matters, modulo compatibility
  • Flashing content is bad, minimize it
  • Speed isn't how fast you run JavaScript
  • Put scripts last
  • Avoid scattered inline script blocks

What To Do?

As Steve would tell us...

  1. Don't download things you don't need, gzip
  2. Requests hurt more than big paylods
  3. CSS up front
  4. Scripts last
  5. Avoid scattered inline script blocks

Wait, where were we?!

Oh, right. The new shiny!

The Approach

  • Just say "maybe" to IE 6-8
  • Start with mobile
  • Desktop layout as add-on
  • Small "s" semantic markup
  • CSS drives states, transitions
  • Hand-rolled JS

Giant's Shoulders

Where We're Going Off-Road

  • Only hand-rolled JS. No libraries. Deal.
  • Minimal resets
  • Not worrying about "bulletproof"
  • IE 6-8 are legacy

3 Hours Is A Lot of Time, But...

HTML

  • <canvas>
  • <audio>
  • <video> & formats (WebM, etc.)
  • <input type="range">
  • <input autofocus>
  • <input placeholder="...">
  • New semantics: header, section, etc.
  • Microdata
  • ARIA roles and states
  • Inline SVG

CSS 3

  • Selectors
  • Gradients & Reflections
  • Rounded corners
  • Box & Text shadows
  • Transitions & Animations
  • GPU acceleration
  • @font-face & WOFF
  • Pointer events
  • Box layout
  • Text clipping
  • Multiple backgrounds
  • background-[size|origin|clip]

JS & DOM

  • Touch events
  • querySelectorAll
  • ES5
  • history.pushState
  • Web Workers
  • Local Storage
  • Databases
  • Drag & Drop
  • Web Sockets
  • AppCache
  • Notifications
  • Geolocation
  • WebGL

Ask questions,
  we'll cover what you care about.

Wait, what? No IE 6-8?
Not even 8?

Nope.

Well, nope-ish.

Our Baseline

In: IE 9+, Safari, Mobile Safari, Firefox, Chrome, Opera, Opera Mini, Blackberry Torch+, Android, IE 6-8 with Chrome Frame

Out (Fallback): IE < 8 without Chrome Frame, IE Mobile, Blackberry pre-Torch, Nokia phones

Spend Less: Write once*

Go Faster: Fewer requests, fewer plugins, smaller downloads

Get Paid: PhoneGap, Chrome Web Store, Palm Store, etc.

Adding Chrome Frame Support

HTTP header:
X-UA-Compatible: chrome=1
Or meta tag:
<meta http-equiv="X-UA-Compatible" content="chrome=1">

That's it

HTML

New Features We'll Use

  • New doctype
  • Shorter charset
  • New structural elements
  • New input types
  • <canvas>
  • <audio>*
  • <video>*
  • contentEditable

New semantic tags

<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>

   <article>
     <header>
       <h1>Title</h1>
     </header>
     <section>
       Content...
     </section>
   </article>
  </section>

  <aside>
   Top links...
  </aside>

  <footer>
   Copyright © 2009.
  </footer>
</body>

            

New input types

Implemented

Dedicated UI:
              
<input type="range" min="0" max="50" value="0" /> 
<input results="10" type="search" /> 
<input type="text" placeholder="Search inside" /> 

Input Validation:

<style> :invalid { background-color: red; } </style>
<input type="color" /> 
<input type="number" /> 
<input type="email" /> 
<input type="tel" /> 
etc...

Not yet

<meter> <progress> <output> etc...

Canvas

<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>
            

contentEditable: Like Input, Sort Of

Rich-Text Editing

<div contentEditable="true"
  onkeyup="console.log(this.innerHTML);">
  Everything, including <em>formatting<em>, is editable.
<div>

Not part of forms by default:

<form>
  <textarea id="ceStorage">
  </textarea">
  <div contentEditable="true"
    onkeyup="document.getElementById("ceStorage").value = this.innerHTML;">
    ...
  <div>
</form>

Cross-browser sadness

CSS

New Features We'll Use

  • Gradients and corners
  • Media queries
  • Animations, Transforms, and Transitions
  • Pointer Events

Gradients

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))
                                                        

Rounded corners

  border-radius: 0px; 
Example

Shadows

text-shadow: 
  rgba(64, 64, 64, 0.5) 
  0px 
  0px 
  0px; 
box-shadow: 
  rgba(0, 0, 128, 0.25) 
  0px 
  0px 
  0px; 
            
Shadows example

Background enhancements

Background sizing

#logo {
  background: url(logo.gif) center center no-repeat;
  background-size: 
    ;
}

Resize me! »

Multiple backgrounds

div {
  background: url(zippy-plus.png) 10px center no-repeat, 
              url(gray_lines_bg.png) 10px center repeat-x;
}
            

Transitions

#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'; 

Transforms

Hover over me:

-webkit-transform: rotateY(45deg);
-webkit-transform: scaleX(25deg);
-moz-transform: scaleX(25deg);
-o-transform: scaleX(25deg);
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);
}

A Word on Compositing, Transforms, and Graphics Hardware

.composited {
  -webkit-transform: translateZ(0);
}
chrome.exe --enable-accelerated-compositing --enable-webgl

Canvas Elements As Backgrounds!

Can you hear that?

It's the sounds network requests dying

#logo {
  background: -webkit-canvas(drawn-logo);
  -webkit-transition: background-position-x .3s;
  border: 0;
  ...
}

Animations

@-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 ;)

Pulse!

JS & DOM

New Features We'll Use

  • querySelectorAll
  • ES 5 defineProperty
  • Drag & Drop
  • Pointer Events
  • Sane event syntax

Built-in Selector Magic

Finding elements by class (DOM API)

var el = document.getElementById('section1');
el.focus();

var els = document.getElementsByTagName('div');
els[0].focus();

var els = document.getElementsByClassName('section');
els[0].focus();

Using the New Selectors API

var els = document.querySelectorAll("ul li:nth-child(odd)");
var els = document.querySelectorAll("table.test > tr > td");

Sucks about them miss-designing it, though.

Filtering vs. descending,
the ID hack

Extending DOM Types

Sure Would Be Nice If We Could Extend That Thar DOM...

HTMLElement.prototype.shout =
    function() {
      alert(this.innerHTML);
    };
var f = document.getElementsById('f');
f.shout();

Not so fast there, pardner

for (property in f) {
  if (property == "shout") {
    alert("we've busted the iteration surface area!");
  }
}

defineProperty To The Rescue

Object.defineProperty(HTMLElement.prototype, "shout", {
  value: function() {
    alert(this.innerHTML);
  },
  writable: true,
  enumerable: false,
  configurable: true
});
var f = document.getElementsById('f');
f.shout();

This is how h5.js works

h5.extend(HTMLElement.prototype, { "name": value, ... });

Web Storage

// use localStorage for persistent storage
// use sessionStorage for per tab storage
textarea.addEventListener('keyup', function (e) {
  window.localStorage['value'] = e.target.value;
  window.localStorage['timestamp'] = (new Date()).getTime();
}, false);
textarea.value = window.localStorage['value'];

Save text value on the client side (crash-safe)

Drag and drop

<div draggable />
document.addEventListener('dragstart', function(event) {
   event.dataTransfer.setData('text', 'Customized text');
   event.dataTransfer.effectAllowed = 'copy';
}, false);
  1. Select text and drag (original text will be dropped)
  2. Select text and drag (dragged text data will be altered from original)
Source Data
Drop Area

Application Cache

<html manifest="cache.manifest">
window.applicationCache.addEventListener('checking', updateCacheStatus, false);
CACHE MANIFEST

# version 1

CACHE:
/html5/src/refresh.png
/html5/src/logic.js
/html5/src/style.css
/html5/src/background.png

Intermission

Take 20

Mobile First

Stuff We Can't Use

  • WebSockets
  • Fonts on iOS (SVG fonts!?!)
  • A single video file
  • Pointer Events everywhere
  • Many of the best new input types

Media queries to pull style sheets

A quick tour of h5.js

The async loader

No scripts can depend on others!

Lab!

http://infrequently.org/10/lab.tar.gz

What You'll Need

  • Google AppEngine Python SDK
  • Chrome, Safari, or Firefox with Firebug
  • A search engine
  • A text editor

Challenges

  1. Style the item list
  2. Collapse/expand the list
  3. Animate list collapse
    • Bonus! animate in response to orientation change
  4. Make items in the list draggable
  5. Add touch scrolling using iScroll
  6. Integrate Web Fonts

Any More Questions?

Thank You