How do you use images?

We want to find out more about how web developers use images.

It would really help if you could answer a few simple questions using our online survey. That should only take a few minutes.

We’ll collect responses for two weeks, then publish a summary of the results.

If you don’t have time for the survey, just reply to this post.


Posted in Uncategorized | Tagged , , , , , | Leave a comment

Search Shakespeare

Fast search for the complete plays, poems and sonnets of Shakespeare (including locations and stage directions) using texts from the PlayShakespeare project.

This app works offline!

Texts are downloaded automatically as you use them.

You can also manually download texts by clicking one of the Download all checkboxes.

Texts are removed when a checkbox is unchecked.

Link to texts and search results

As well as search, you can use the app to open texts or citations:

You can also link to search results:

Search options

There are several options for filtering search results:

  • Text name
  • Type of text (play, poem or sonnet)
  • Speaker
  • Speaker gender

Click on a word in a text to search for that word.

Feedback and feature requests

Feedback welcome!


App code on GitHub

This app is open source.

The code and data used by the app is available on GitHub:

Play and poem texts

© 2005-2016 Permission is granted to copy, distribute and/or modify this information under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation. Terms at

Please note that this is not an official Google product.

Posted in Full text search, Literature, Poetry, Shakespeare | Tagged | Leave a comment

A manifesto for teaching web development

Over the last two decades I’ve taught several Web Dev 101 courses.

To be honest, I don’t think any of those courses were much good.

In my experience students start out excited and ready to learn, but soon glaze over because the content and teaching are boring or baffling or both.

By way of apology to those I have baffled and bored over the last 20 years, I’ve put together 10 principles for explaining HTML, CSS and JavaScript to absolute beginners.

I think we can do a better job of teaching basic web skills.

  1. For live classes, consider flipped classroom techniques. Get students to learn at home (with specific goals and requirements) then complete activities with supervision in the classroom. Be upfront about the level of commitment expected. Provide a clear path: how to get help, where to find out more, what to do next.

  2. Wherever possible, show don’t tell. Emphasise learning by doing. Online or live, avoid presenting or talking for more than a few minutes.

  3. Describe an objective, then show how to achieve it: avoid putting the technology before the requirement. For example, demonstrate the need to set the maximum size of an image, then show how to do that with CSS (not the other way around). Focus on ‘getting things done’ rather than language features.

  4. Avoid unnecessary information. For example, do not go into the gory details of CSS specificity algorithms or JavaScript function hoisting. (I’ve seen both of these in 101 courses.) Stick to the basics — that’s plenty.

  5. Make examples as simple as possible. Get rid of all redundant content and code.

  6. Avoid jargon, fussy nomenclature and unhelpful analogies. Concepts such as ‘the cascade’ and  ‘the box model’ are easy to grasp in practice. Formal naming just makes them sound difficult. Most students will intuitively understand that overrides div (just ask them which one ‘wins’). Likewise for padding, borders and margins: good examples and simple diagrams can work better than formal descriptions and naming. Once students are comfortable with a conceptual model, you can mention the official name for it.

  7. Many people new to coding don’t use or understand hierarchical file systems. When you start, make sure everyone is comfortable with files and folders. Many problems for beginning web developers are caused by something ‘in the wrong place’.

  8. Beginners make different kinds of mistakes than experienced developers. Be aware of this when you’re debugging. Show beginners what to watch out for: missing angle brackets (<div class=”foo”), missing equals signs (<div class”foo”>), missing closing tags, copy-pasted curly quotes instead of straight quotes.

  9. Present a single best-practice approach and if necessary, go back later to show alternatives. There’s more than one way to do it is a healthy attitude to impart, but options can be confusing. In particular, beginning students do not need to consider browser compatibility handling.

  10. Teaching and examples should follow best practice and industry norms: use semantic elements, ===, single quotes in JavaScript, double quotes in HTML — and so on. You don’t need to go into the whys and wherefores, just be consistent and get students to follow best practice by default from the start.

    …and two extras:

  11. Don’t bother with the backstory, the history of the web, the things you used to do, and why things are the way they are now. Don’t explain HTML5 versus HTML4 or why JavaScript was invented. Web history doesn’t help students get started with coding. Rather than recounting the story of AJAX, just show the need to interact with servers and explain how to do that with fetch().

  12. Tailor your content and teaching to your audience. Try to work out how to reach a wide variety of people and capture their interest via problems they want or need to solve.
Posted in HTML, Uncategorized, Web development | 4 Comments

JavaScript linting: moving from JSHint and JSCS to ESLint

I recently read a couple of articles that convinced me to try ESLint:

We went ahead and implemented ESLint for the WebRTC samples repo, and we’re really pleased with the results. JSHint and JSCS are both brilliant tools, but ESLint provides more functionality than both of them combined. It’s quick, too: checking the 23 WebRTC samples main.js files in a couple of seconds, for 30 customised rules (along with the defaults).

If you want to do the same yourself, here’s a quick how-to for making the move from JSHint and JSCS to ESLint.

1. Create an eslint branch for your repo.

2. Run npm install grunt-eslint --save-dev to install ESLint and add it to your package.json file. Remove JSHint and JSCS from package.json.

3. Create an ESLint .eslintrc config file (or adapt ours). Add rules, globals and other settings based on your existing JSHint and JSCS config. Note that rules marked ‘recommended’ in the ESLint documentation are run by default.

@slicknet pointed out that there’s a tool for this:

4. Remove .jshintrc and .jscsrc files.

5. Replace JSHint and JSCS build tasks with ESLint — for example, in Gruntfile.js or gulpfile.js. Likewise for Git hooks and test scripts.

6. Install ESLint for your text editor and turn off JSHint and JSCS linting.

7. Remove or replace references to JSHint and JSCS in your JavaScript files, such as inline rule settings. The following ESLint declarations can be used instead:

... // eslint-disable-line new-cap

/*eslint-disable */

/*eslint-enable */

Global declarations are the same:

/* global Fubar */

8. Run ESLint for your files and fix them as necessary. (This is much easier if you already have ESLint installed for your editor.) You can also run ESLint from the command line with the --fix parameter to automatically fix some errors, such as spaces in arrays or function definitions.

9. Test all the files that you changed.

10. Make a pull request for the eslint branch, get an LGTM and merge it.

That’s it!

.eslintrc config file for WebRTC samples repo

.eslintrc config file for WebRTC samples repo

Posted in Code linting, git, GitHub, JavaScript | Tagged , , , , , , , , , | Leave a comment

Search Google developer videos

Please note: I am currently rebuilding this app: the URLs below will not work.

I built a prototype API and application for searching Google developer video transcripts and metadata:


Sample search app for Google developer videos


Screenshot of JSON response to


1. I work for a search company.

2. More and more content online is video.

3. Video is inherently opaque to textual search.

How can we navigate and search media content? Not least the thousands of videos on Google Developers, Android Developers and Chrome Developers.

Thankfully Google has a secret weapon: a crack team of transcribers who produce highly accurate, timecoded captions for Google videos. (Not  to be confused with the sometimes slightly surreal automated alternative.)

Some people prefer to access information by reading text rather than watching videos, so I also enabled access to downloadable transcripts:

The transcripts have Google Translate built in, so you can choose read them in a different language. Caption highlighting is synchronised with video playback — and you can tap or click on any part of a transcript to navigate through the video.

Web page screenshot showing transcript of Google Developer video HTTP 203: Pointer Events

HTTP 203: Pointer Events translated into French
(Apologies if the translation is dodgy…)

I hope the app and API are useful. As ever, your feedback would be much appreciated.

With some minor tweaking you could use my app and API to build search for any YouTube channels that have manually captioned videos — just tweak the channels in the code.

A quick hat-tip to the world’s transcribers, captioners and reporters.

These unsung heroes have amazing, hard-won skills! If you’ve ever seen a captioner at work at a live event, you’ll understand what a complex and difficult job it is.

Why are captions important? Because they give more people better access to media: those of us with impaired hearing, or whose first language isn’t the language of the video we’re watching.

Likewise, respect is due to the archivists who catalogue video after broadcast — the art of ‘shotlisting’. Without shotlists, history is lost (and it’s hard to resell footage…) Where was that sequence of Donald Rumsfeld getting down with Saddam Hussein? Shotlisters work long days faithfully cataloguing and timecoding news stories, often at double speed, one package (or rush) after another. One of my ex-colleagues at ITN, Jude Cowan, wrote a brilliant and moving book of poetry on the subject.


Search for something:

Transcripts for two or more videos:,3i9WFgMuKHs

Link to a query:

Data and transcript for a video:

Transcript only: or or

Multiple values — comma, semicolon or pipe delimiter, spaces OK:,iZZdhTUP5qg, iZZdhTUP5qg

Search any field for a query, spaces OK — can be a bit slow: 203

More shortcuts: c for captions, s for speaker — speakers are parsed from transcript:

Can specify ranges for commentCount, dislikeCount, favoriteCount, likeCount, viewCount:>10000

You can use any of these values to specify order:>10000&sort=viewCount

Add a hyphen for descending order:>10000&sort=-viewCount

Show items with titles that include ‘Android’ or

Items with speakers that include Reto and a title that includes Android:

Spaces are OK: Meier&title=Android

More complex stuff works too: Wear|description=Android Wear)&speakers=Reto Wear|description=Android Wear)&speakers=[Reto,Wayne]”Android Wear”|title=WebRTC Wear|description=Android Wear)&speakers=Timothy

Fuzzy matching — with apologies to Wayne, whose name I generally misspell :):

For dates, use ‘from’ and ‘to’, which can cope with anything Date can handle: // assumes text-only is a month this year 2014 // midnight, 1 January to midnight, 1 January

Get total for any quantity field — this query returns the total number of views for all videos:

Get total for any query and quantity field:

Get all individual values for any quantity field for all videos — returns an object keyed by amounts, values are number of occurrences for each amount:

Get all individual values for any quantity field for any query:

Build a chart from results (views for videos that mention ‘Chrome’):

The code

Available from GitHub:

Truth be told, it’s a bit of a dog’s dinner. I wrote most of the app and API on long flights and in the small hours under the influence of jet lag. E&OE! The JavaScript is a little… procedural, and I hereby pledge that I will mend my ways.

Issues and pull requests welcome.

There are three code directories:

app: the web client (as used at This will automatically choose the local Node middle layer (below) if run from localhost.

get: middle layer Node app to get data from the database. For testing, you can run this locally with the app running from localhost. I run the live version on Nodejitsu at, for queries like this: (same as

put: Node app to get YouTube data and transcripts, massage the response and put it in a CouchDB database at


Why didn’t you use Node on Google?

I’d like to, but Nodejitsu is very easy:

$ npm install jitsu
$ jitsu login
$ jitsu deploy
$ 🙂

Why didn’t you use Firebase?

I used Cloudant, which has Lucene search built in (and is based on CouchDB, and is very easy to use). Firebase can now be used with Elasticsearch, but when I started that required extra installation.

Why didn’t you just use MySQL or …

I probably should have. In fact, an SQL database with Lucene for full text search might have been much more appropriate than CouchDB. (This kind of search is actually much easier with Firebase now.)

How was CouchDB?

Good in some ways, and quick. In particular, the JSON/HTTP/REST styles feels fits well with Node/JavaScript development.

Problems came with full text search:
• Full text search is not built into CouchDB, though it can be added on with Lucene or other search engines.
• CouchDB searches return entire documents, with no ‘partial’ results. (In my case, a document represents all data for a video.) So, for example, if I want to return only captions that include ‘Android Wear’, I need to retrieve all the documents (in their entirety) that have captions that mention ‘Android Wear’ then filter.
• CouchDB search queries cannot be combined: for example, ‘get me all videos from 2013 with WebRTC in the title’. So, again, you have to add your own filter.

How big is the database?

Around 250MB, but more like 150MB without transcripts: the transcript for each document is really just a convenience to make it quick and simple to retrieve human readable transcripts, and replicates the captions (with a few tweaks).

How often is the data updated?

At present I’m updating the database manually to avoid code changes breaking it, but once the code settles down I’ll run automatic updates every (say) 30 minutes.

Why didn’t you use io.js?

No big reason. Node.js has been around longer.

How many documents have transcripts?

Last time I looked: 4312 videos, 3550 with transcripts.

How did you get the speaker names?

With a bit of sneaky regexing these are parsed from transcripts.

NB: speaker names are not parsable for many captions, so speaker search results may not always be complete.

Why are caption matches returned as span elements?

The primary use for the caption matches is within HTML markup. Returning JSON for each span might be neater and less verbose, but for most apps that would entail extra effort transforming to HTML. I could be persuaded otherwise.

How long does it take to store and index data?

This depends a lot on connectivity. From work, the app gets and inserts the video data and transcripts in under three minutes. From home, it takes about 10 minutes.

Indexing takes about 10 minutes.

What build tools do you use?

I use JSCS and JSHint with grunt and githooks to force validation on commit.

Chrome JSON formatting extensions, and were very useful.


  • I haven’t written any unit tests – yet.
  • Error handling is minimal.
  • Code refactoring is in the pipeline.
  • I don’t know a lot about working with sockets on Node, so a lot of the code has to be deliberately synchronous to avoid errors. I’m sure someone could help me…
  • The API is HTTP only as yet.
  • Use the official YouTube Captions API.
  • I wanted to use Firebase, but when I started it was a bit tricky to implement full-text search, so I opted for Cloudant. It’s now pretty simple to use Firebase with ElasticSearch, so I’ll port the data at some stage.
  • Database updates are done manually at the moment — mostly because I’m worried about messing up the sample app. Easily automated.
Posted in Uncategorized | Leave a comment

High performance HTML

How can you improve the performance of web pages?

Most developers look to JavaScript and image optimisation, server configuration, file minification and concatenation – even CSS tweaks.

Poor old HTML gets neglected, despite being the core language of the web.

HTML payloads are big and getting bigger. Pages on most top-100 sites require around 40k of HTML per page. Sites such as Amazon and Yahoo use thousands of lines of HTML per page. The home page currently clocks in at a whopping 3.5K HTML elements.

Reducing HTML complexity and the number of elements in a page won’t improve parse time much – but well crafted HTML is a crucial foundation for building fast-loading pages and layouts that respond successfully to different viewport sizes.

In this article you’ll find out how to write clean, concise HTML that enables you to create content that loads fast and works well across a variety of devices. In the process, you’ll learn how to build sites and apps that are easier to debug and maintain.

There is always more than one way to write code – especially HTML. Rather than begin every sentence in this article with ‘In general …’ we’ve gone ahead and prescribed what in our experience usually works best. That doesn’t mean that every suggestion is right every time.


Sample HTML document with guidelines

HTML, CSS and JavaScript

HTML is a markup language for adding structure and meaning to content.

HTML should not be used to style content.  Don’t put text in heading tags to ‘make it bigger’ or use blockquotes just for indentation. Instead, use CSS to change the appearance and layout of elements.

The default appearance of HTML elements is defined by a browser’s default stylesheet: Chrome, Firefox, Internet Explorer and Opera each have their own. For example, in Chrome the h1 element by default is rendered as 32px bold Times.

Three general principles:

  • Use HTML for structure, CSS for presentation and JavaScript for behaviour. CSS Zen Garden (12 years old this year!) shows this separation of concerns in action.
  • Use HTML, then turn to CSS if and when required – and, if really necessary, move on to JavaScript. For example: in many cases it’s possible to use HTML for form validation and CSS or SVG for animation – without resorting to JavaScript.
  • Put CSS and JavaScript in files separate from your HTML. This enables caching and makes code easier to debug. In production, CSS and JavaScript can then be minified, concatenated and inlined as part of your build process.

Document structure

  • Use the HTML5 document type. Here’s a barebones document:
<!DOCTYPE html>

 <title>Recipes: pesto</title>



  <p>Pesto is good!</p>

  • Link to CSS files at the top of the page, in the head element like this:
  <title>My pesto recipe</title>

  <link rel="stylesheet" href="/css/global.css">
  <link rel="stylesheet" href="css/local.css">


That way, browsers have CSS information ready before parsing HTML.

  • Put JavaScript at the bottom of the page, before the closing body tag. This speeds up page load – since the browser can render the page before parsing JavaScript – and has the helpful side effect of enabling JavaScript to refer to page elements:


  <script src="/js/global.js"></script>
  <script src="js/local.js"></script>
  • Alternatively, use the defer and async attributes – but be aware of their behaviour: script elements with an async attribute aren’t guaranteed to be executed in order. Also consider support: async is only implemented in Internet Explorer 10 and above; defer is only partially supported prior to Internet Explorer 10.
  • Add handlers in JavaScript code. DON’T add them inline in HTML. For example, this is error prone and hard to maintain:




  <script src="js/local.js"></script>


<body onload="init()">


  <button onclick="handleFoo()">Foo</button>



This is much better:







  <button id="foo">Foo</button>


  <script src="js/local.js"></script>



var fooButton =
fooButton.onclick = handleFoo();



A major reason for the success of the web is that browsers handle invalid HTML. There are even standardised rules for how browsers should render invalid code.

However, this is NOT a reason to be laissez-faire. Valid HTML is easier to debug and often smaller in file size, faster and less resource-hungry to parse and render. Invalid HTML can make successful responsive design difficult to implement.

Writing valid HTML is particular important when working with templates: what seems to work OK in an isolated chunk of code may go horribly wrong in combination with other content.

  • Incorporate validation in your workflow: use validation plugins such as HTMLHint and SublimeLinter with your editor and incorporate validation in your build process using tools such as HTMLHint with Grunt. You can check code online with tools such as the W3C HTML validator, and share configuration files with project contributors.
  • Use the HTML5 document type.
  • Make sure to maintain HTML hierarchy: nest elements correctly, and make sure no elements are left unclosed. It can be helpful for debugging to add a comment to the closing tag of an element that holds a large amount of complex content – especially when using templating:

<div id="foobar">

</div> <!-- foobar ends -->
  • Make sure to add closing tags to all elements that aren’t self-closing.

For example, this will work:

<p>Pesto is good to eat...
<p>...and pesto is easy to make.

But this is less likely to go wrong, since the end of each paragraph is made explicit:

<p>Pesto is good to eat...</p>
<p>...and pesto is easy to make.</p>
  • Closing tags are not required for list items and some very clever developers believe you should leave them out. Whatever you do, make sure to close every list element:
  <li>Pine nuts
  • One place you absolutely must include closing tags is with the video and audio elements. These are not ‘self closing’:
<!-- wrong: liable to cause layout grief -->
<video src="foo.webm" />

<!-- better -->
<video src="foo.webm">
  <p>Video element not supported.</p>
  • Link elements (used to include CSS) are self closing — it wouldn’t make sense for a link element to contain code — but a script element always requires a closing tag, even if it only links to an external JavaScript file:

<link rel="stylesheet" href="css/local.css">
<script src="/js/global.js"></script>

Conversely, cut clutter by removing unnecessary code:

  • There is no need to add a slash to ‘self closing’ (void) elements such as <img> and <link>. (You can enjoy a comprehensive list of self-closing elements here.)
  • Boolean attributes do not have a value: if the attribute is there, it’s true. In the following example, the video element will not autoplay and will not have controls (since this is the default):
    <video src="foo.webm">

    The following example doesn’t work as expected, because the presence of an attribute forces a true value:

    <video src="foo.webm" autoplay="false" controls="false">

    This works:

    <video src="foo.webm" autoplay="true" controls="true">

    This is more readable:

    <video src="foo.webm" autoplay controls>
  • Stylesheets and scripts don’t need a type attribute: CSS and JavaScript are the defaults.
  • Omit the protocol when linking to external content: this prevents problems with mixed content. For example:
    <a href="//">Tag soup</a>

Code formatting

Consistent formatting makes HTML code easier to understand, optimise and debug.

  • Maintain an HTML style guide for project contributors (or use an existing one like Google’s).
  • Use your editor to automate code beautification. For example, in Sublime Text add a shortcut for Reindent. You can check layout with code linters such as SublimeLinter or online tools such as CSS Beautify and JS Beautifier.
  • Don’t go mad with hierarchical HTML indentation! This can easily get out of hand, so set rational defaults for when to begin an element at the left margin. Conversely, deep hierarchies may mean you need to refactor.
  • Standardise on indentation and use either spaces or tabs, not both.
  • Improve readability with sensible nesting. For example, it’s clear that this is a heading:
      <h2><a href="/contact">Contact</a><h2>

    …whereas at first glance this just looks like a link:

    <a href="/contact"><h2>Contact</h1></a>
  • Order elements in ways that won’t be a surprise to other developers – or you in six months. For example, a footer element should go at the bottom of your .html page, even though (in theory) it could be put anywhere.
  • Standardise on single or double quotes.
  • Use lowercase code for tag and attribute names. UPPERCASE IS TIRESOME:
    <A HREF="/">Home</A>

    Mixed case is EVEN worse:


Semantic markup

Semantic means ‘relating to meaning’.

HTML markup adds meaning to content: element and attribute names describe the role of content.

HTML5 introduced a number of new ‘semantic elements’ such as <header>, <footer> and <nav>.

Using the right element for the right content is good for accessibility and helps ensure your code is understandable:

  • Use <h1> (<h2>, <h3>…) for headings,  <ul> or <ol> for lists.
  • Note that <article>  headings should begin with an <h1> (reasoning here).
  • Where appropriate, use the HTML5 semantic elements such as <header>, <footer>, <nav> and <aside>.
  • Use <p> for body text, HTML5 semantic elements (or as  a fallback) to structure content – not vice versa.
  • Use <em> and <strong> rather than <i> and <b>: use HTML to add meaning, not styling hints.
  • With forms use the element, input types, placeholder text, and the required attribute to enforce validation. (Pete LePage’s articles on Web Fundamental show how.)
  • Mixing text and elements, as children of another element, tends to lead to layout bugs. For example, this:
    <div>Name: <input type="text" id="name"></div>

    is better expressed as this:

      <label for="name">Name:</label>
      <input type="text" id="name">

    This has a bonus side effect: the for attribute means that clicking on the label automatically throws focus onto the input element. This is particularly useful for checkboxes and radio buttons.


To reiterate: HTML should be used to add meaning and structure to content, not for styling.

  • Use <p> elements for text, not for layout. By default, <p> has margins and other styles applied by the built-in browser stylesheet.
  • Avoid using <br> for line breaks: use block elements or the CSS display property instead. The <br> should only ever be seen within text – and even then, only very rarely (for example, as a form of punctuation within poetry).
  • Avoid using the humble <hr> to add horizontal lines: CSS border-bottom is a better option. It may make sense to use <hr> to denote a thematic break.
  • Don’t use divs unnecessarily: the W3C HTML spec describes the div as ‘an element of last resort, for when no other element is suitable’ ( Style inline elements such as links and img elements with display: block, rather than putting them in divs or (worse) using <br>.
  • Learn which elements are block level, to avoid unnecessarily putting block level elements inside divs. For example, there is no need to put a list inside a div element.
  • Do not use tables for layout. Do use tables for tabular data.
  • Flex box is now widely implemented: use it.
  • Use CSS padding for padding and margin for margins: understand the box model.
  • Standardise on margins: it’s often best to add margins to the bottom and the right of elements, rather than the top or left. Whatever you do, avoid mixing top and bottom or left and right. Use the last-of-type selector to avoid redundant margins.

HTML emails

Coding for email is nothing like coding for the modern web.

We won’t go into the gruesome details here – suffice to say that best practice for HTML email coding resembles web development from the late 1990s: tables, shim GIFs, inconsistent and minimal CSS, patchy image and media support, little or no support for JavaScript, and lots of minor hacks. (For an unpleasant taster, take a look at MailChimp’s most basic template.)

More information here, here and here.


This article is about HTML, but here are some basic CSS tips:

  • Avoid inline CSS. For performance optimisation, CSS files can be inlined as part of your build process.
  • Use an ID once and once only: there should only be a single element with id=”foo”, id=”bar”, or any other ID.
  • Use classes when you want to refer to multiple elements – and take a look at BEM syntax. Where possible, use class attributes on a parent rather than children. For example:
<!-- verbose :( -->
  <li class="ingredient">Basil</li>
  <li class="ingredient">Pine nuts</li>
  <li class="ingredient">Garlic</li>
<!-- better :) -->
<ul class="ingredients">
  <li>Pine nuts</li>


Consider the range of devices, contexts and input methods that will be used to interact with your HTML:

  • Use semantic elements.
  • Provide fallbacks: add captions and subtitles with the track element, include fallback text and/or images in video and audio elements; use poster images for video; add alt attributes to every image (give the alt attribute an empty value if the image is only for decoration).
  • Add title attributes to links – but only if the title adds meaning and doesn’t just repeat the link text.
  • Use type and placeholder elements in input elements.
  • Use ARIA attributes.

Random bonus extra suggestions

  • Make sure to encode characters with special meaning in HTML, such as < and &. For example:  <title>HTML &amp; JavaScript</title>.
  • Conversely, do not unnecessarily encode characters such as en dashes (for example, 4–5 weeks) or currency symbols such as ¢ and €.
  • Add comments if and only if it’s not obvious what’s happening in code. (And bear in mind that code commenting often shows a need for refactoring – good HTML, even when it’s complex, is generally self-explanatory.)
  • Where it makes sense – with all-capitalised headings, for example – apply text case via the CSS text-transform and font-variant properties, not by entering uppercase text. You may change your mind later!  Also, if users copy text, they probably want upper and lower case. The following <h4> is displayed in small caps, but when copied will be upper and lower case.HTML:
    <h4>W3C Web Accessibility Initiative ARIA guidance</h4>


    h4 {
      font-variant: small-caps;

And finally…

Whatever you do, test!

Build HTML testing into your workflow, toolchain and deployment processes.

Test page load on a variety of devices, on large and small screens, in a variety of connectivity contexts. Try interacting with your page with a text-only browser such as Lynx, or with a screenreader such as ChromeVox. Use emulators such as Chrome Dev Tools device mode to monitor changes. Page Speed, Web Page Test and other tools can be integrated with your workflow to automate testing before or after deployment.

For more information about how to write high performance HTML, follow the links in HTML, CSS and JavaScript resources and check out the guidance on Web Fundamentals.

Posted in html5 | Tagged , , , | 45 Comments

Media Newsletter: audio, video and realtime communications

I’ll be publishing a monthly roundup of news about media tech.

Sign up at

Archive at

Media Newsletter

Media Newsletter

Posted in Uncategorized | Leave a comment

Fundamentals of video on mobile

Watch my Google I/O video: Fundamentals of video on mobile:

  • Responsive media
  • Coping with variable connectivity
  • Accessibility and fallbacks
  • Formats and codecs
Video with captions on Chrome for Android

Video with captions on Chrome for Android



Posted in Uncategorized | Leave a comment

WebRTC in the real world: signaling, TURN and STUN

New on HTML5 Rocks: a detailed look at building servers for WebRTC.

New on HTML5 Rocks: WebRTC infrastructure

Posted in Uncategorized | 1 Comment simplest possible examples of HTML, CSS and JavaScript

I’ve built a site to provide simplest possible examples of HTML, CSS and JavaScript:


  • ‘Show me the code!’
  • ‘Does technology X work on platform Y?’
  • ‘Where the heck is that Foo example I saw?’
  • A minimum of ‘huh?’
  • Short, consistent, guessable URLs with sensible shortcuts, for example redirects to
  • Easy to maintain.
  • Works well on mobile devices.


  • Oriented to modern browsers.
  • No templating.

I hope it’s useful – comments and suggestions much appreciated.

Posted in Uncategorized | Tagged , , , | 3 Comments

WebRTC in Internet Explorer with Chrome Frame

It’s now possible to use WebRTC – PeerConnection and MediaStream – in Internet Explorer with Chrome Frame.

Best of all, getUserMedia no longer requires a flag to work with the Chrome stable channel – so, if Chrome Frame is installed, getUserMedia just works!

I’ve recorded a screencast that shows how to install Chrome Frame and configure Chrome in order to use WebRTC in Internet Explorer:

First, an explanation of how Chrome Frame works.

Google Chrome Frame is an open source plug-in that seamlessly brings Google Chrome’s open web technologies and speedy JavaScript engine to Internet Explorer 6, 7, 8, or 9.

When web developers add the Chrome Frame meta element to their web page, Internet Explorer will use Chrome Frame to render the page.

There’s more information about Chrome Frame for developers at

To try out WebRTC with Chrome Frame today, you will need to use Chrome’s Dev Channel. In the future, the WebRTC APIs will be available in both Chrome and Chrome Frame’s stable channels, without requiring any flags or other user intervention.

Installation steps

1. Download Chrome’s Dev Channel browser from (This does not work with Canary.)

2. Quit all of your browsers.

3. Install Chrome’s Dev Channel.

4. Start Internet Explorer and install Chrome Frame from

5. To enable PeerConnection, you need to set a flag by using regedit to create the following entry in your registry (as ever, be careful when using regedit!):


Just to reiterate: the WebRTC APIs will be ‘flagless’ in future versions of Chrome and won’t need this kind of intervention.

6. Re-start Internet Explorer.

One tip: you need 32-bit Internet Explorer to use Chrome Frame. It’s normal to have 32-bit Internet Explorer, even for 64-bit Windows, but you may want to check. Just look in All Programs for the version named Internet Explorer!

Once you’ve set up Chrome Frame in Internet Explorer, try out the getUserMedia demo at or the WebRTC video chat application at

If you want to know more about how to implement real-time communication in your web apps, take a look at the detailed introduction to WebRTC and getUserMedia at,

Let us know how it goes!

Posted in Uncategorized | Tagged , , , , , | 1 Comment

Introduction to WebRTC – now on HTML5 Rocks

I’ve written a detailed introduction to WebRTC on HTML5 Rocks.

I’ve tried to explain some of the more difficult concepts – please let me know if anything is still mystifying!

WebRTC NAT traversal

Posted in Uncategorized | Leave a comment

Chrome Developer Tools, Google I/O 2012

Pavel Feldman taking feature requests live at Google I/O

Pavel Feldman taking feature requests live from the audience

The Google I/O session I did with Chrome Dev Tools tech lead Pavel Feldman is now on YouTube.

Lots of new features to help you develop and debug on mobile and desktop: frame mode, the Sources panel, the new timeline, Source Maps, Web Worker debugging – and much more.

It’s a fun session, especially when Pavel shows how he uses the Dev Tools to build the Dev Tools…

Posted in Uncategorized | Leave a comment

Getting started with the HTML5 track element

If you haven’t had a look at the HTML5 track element — check it out my tutorial on HTML5 Rocks.

The track element provides a simple, standardised way to add subtitles, captions, screen reader descriptions and chapters to video and audio.

Tracks can also be used for other kinds of timed metadata. The source data for each track element is a text file made up of a list of timed cues, and cues can include data in formats such as JSON or CSV. This can enable DOM manipulation and other behaviour synchronised with media playback — as well as deep linking and media navigation via text search.

Posted in Uncategorized | Tagged , , , | Leave a comment

Got Raspberry Pi!

Raspberry Pi desktop

Raspberry Pi desktop

We got a Raspberry Pi in the office today, and hooked it up to a keyboard and monitor.

Raspberry Pi board

Raspberry Pi board, roughly Arduino size

In case you haven’t heard of it, Raspberry Pi runs Linux on an ARM processor and has a target price of $25/£15 for a pre-configured system.

Works a treat!

Just want to get Chrome on it now :^).

Posted in Google Chrome, Primary schools, School | Tagged , , , , | 8 Comments

Cherry Cream Delight

I can’t believe the things I’ll eat when I’m on a plane.

Cherry Cream delight label


Cherry Cream Delight ingredients

That's a lot of ingredients

Posted in Uncategorized | Leave a comment

Automatically pause video when it’s not visible

Download the Hold It! extension

I’ve built a Google Chrome extension called Hold It! that pauses video when it’s not visible.

For example, when you:

  • minimise a window with a video playing in it
  • move to a different tab
  • open a video link in a new hidden tab.

Video play resumes automatically when it becomes visible again.

Useful when viewing videos on multiple tab pages, or if you click a link to open a video in a new, hidden tab.

Works for YouTube, Vimeo and on any site that uses the HTML video element.

Caveats: does not work for YouTube advertisements, and does not work on and some other sites. If you have a solution, let me know!

You can get it (for free!) from the Google Chrome Webstore.

How to use the extension

After installing the extension, any playing video will be paused when you move to a different tab or minimise a window. If you click on a link to open a video in a new, hidden tab, the video will be paused until you move to the new tab.

How does it work?

This extension uses the Page Visibility API.

The API can be used to check when a web page is visible to the user or not.

If you minimise your browser window, or move to another tab, the API fires a webkitvisibilitychange event.

When a new page loads, the extension looks for videos on the page — including Flash video and HTML video elements. If the page is not visible, or becomes hidden, all playing videos on the page are paused. Play restarts (for videos that were playing) once they become visible again.

Posted in Uncategorized | 1 Comment

Win a Chromebook!

Chrome Web Store contest

Contest per lo sviluppo di applicazioni per il Chrome Web Store italiano.

Partecipa al contest.

Avete tempo fino a lunedì 12 Settembre 2011.

Posted in Uncategorized | Tagged , , , , | Leave a comment

Chrome extension to test navigation and page load speed

I’ve built a Google Chrome extension called Page Speed Test that uses the Navigation Timing API.

You can get it (for free!) at the Chrome Web Store.

The extension displays a timeline of navigation and page load events for the current page, and a historical chart of page load timing data for all visits to the page.

It’s still a bit rough around the edges, so I’d really appreciate any feedback.

Navigation and page load timing charted for all visits to the current page

Navigation and page load timing charted for all visits to the current page

Timeline of navigation and page load events for the current visit to the current page

Timeline of navigation and page load events for the current visit to the current page

Posted in Uncategorized | Tagged , , , | 2 Comments

Web apps need better context menus

Browser context menu

For web apps to be as good as native apps, they need better context (right click) menus.

Take a look at the screenshot above. This shows what happens when you click on a person in a Google+ circle: I’d like to move the person from the current circle to a different one.

A ‘proper’ context menu would be very useful in this case, but of course what I get is the usual generic browser menu with items that are irrelevant to the task I’m trying to accomplish.

I know that you can add items to context menus in Chrome apps, for example, or hack them in other ways, that there are security considerations (if people add deceptive menu items), that many (most?) users never use context menus, and so on.


There must be a way.

Posted in Uncategorized | Leave a comment