Tales of a Developer Advocate

Experiments in Buildinig a Mobile Friendly Table of Contents

My current focus is on the mobile web. Everything I do need should be to help developers “get” mobile. With this in mind, I was skiming html5rocks on my nexus, and I was struck by the fact that I could not see any content on the first page. Not good.

There are a couple of things that we need to fix on HTML5Rocks when it comes to mobile. Today I am going to focus on the Table of Contents.

The Table of Contents (ToC), depending on the article can be 1/2 a screen in height to 3 screens in height. However you look at the it, you have to scroll to be able to start reading the content. The Table of Contents is also rooted at the top of the document, which on mobile means that I have to scroll all the way to the top to be able to navigate around or understand the structure. Argh.

Just have a look at one of the current articles. Yes the header is too large, but even this small ToC is blocking us from reading the content.

I am working off the idea that if we can get the user to the content quicker, we will improve our read-time, reduce our bounce-rate and create an all-round better experience for developers who read the content we produce.

There are some constraints though:

  1. ToC help you navigate around the page so they need to be visible to the user on page load
  2. Ideally they should always be visible, or easily accessible so you can quickly jump to the parts you need
  3. Due to constraints on the screen size, they should get out of the way as quickly as possible
  4. There should be no rendered-html differences between the mobile and “desktop” versions
  5. If possible use no JS.

With all these in mind I have created my first experiemental ToC. I call it the “Bottom ToC”.

The Bottom ToC is simply a Table of Contents anchored to the bottom of the viewport. When the reader wants to get access to the page structure they simple tap the “ToC” area, it expands into view (whilst keeping them at the same point in their document) letting them select their next reading point. To dismiss the ToC the user can simply clicks back in the main document.

Bottom ToC in its natural state:

Bottom Toc expanded:

It’s not perfect, but I thought it was interesting enough to document.

So, how is it built?

It was a pretty simple build in the end, it required no Javascript and no changes to the rendered HTML. It uses a combination of position: fixed and the :active pseudo class.

Our ToC is structured as a nested set of <ul> elements inside a <nav> element - pretty much how every menu is structured.

<nav class="outline toc">
  <h3>Table of Contents</h3>
  <ul>
    <li><a href="#toc-introduction">Introduction</a></li>
    <li><a href="#toc-topic-sounds">Creating the sounds</a></li>
    <li><a href="#toc-topic-sound">Engine sound</a>
      <ul>
          <li><a href="#toc-topic-looks-like">Looks like this</a></li>
          <li><a href="#toc-topic-go">Give it a go</a></li>
      </ul>
    </li>
   <li><a href="#toc-topic-sync">Getting the sync</a></li>
</nav>

The CSS is simple too. To make it anchor to the bottom of the screen and open when the user clicks on it we do as follows:

.outline.toc {
   position: fixed;
   bottom: 0;
   left: 0;
   right: 0;
   height: 1em;
   overflow: auto;
}

.outline.toc:active {
   height: 5em;
}

That’s it. The important bits are the position: fixed, which takes the element out of the natural flow of the document and anchors it to a defined area in the viewport - in our case the bottom of the viewport. We used the :active psuedo class to manage the opening and closing of the table of contents.

:active is interesting on mobile as it is normally used to style an element with a id that matches the string in the document fragment of the URL (the bit after the #). This is often the case if you click on an anchor that points to an area inside the same document. On mobile browsers such as Safari and Chrome the :active class is also set when you press on any element, which leads to this effect. The really nice thing is that when you click back in the main article, the active element changes thus hiding the menu again.

There are still a couple of isses to resolve so it is not the perfect solution. For example, when the user scrolls up or down in the ToC and reaches one of the extremities the scroll event gets passed through to the parent document.

All in all, I think this is a neat little solution.

Installing Chrome for Android on an Emulator

Let me start by saying it is not possible. But I have a half solution.

If you have tried to install Chrome for Android before on an emulator you will be intimately familiar with the series of errors that occur, most noteably:

Arghhh… I am not going to document how you get this far because I will just be spreading alot of useless facts that ultimately lead you nowhere…

The problem stems from the fact that Chrome for Android is only available from the Play Store and is not available for general download. Luckily Chromium is an Open Source project and whilst we don’t have a full Chromium client available we do have access to the Test Shell.

The Test Shell is Chromium without Chrome’s Chrome. It doesn’t look as pretty but it is fully functional as a Browser (minus all the cool stuff such as bookmarking, sync etc). It even includes the ability for you to connect the Remote Debugger to it from your Desktop. Brilliant!

You can find all the recent builds at http://commondatastorage.googleapis.com/chromium-browser-continuous/index.html?path=Android/ and install the builds on your Android device or emulator by running the following command:

adb install [path to the APK you just downloaded]

This is all pretty cool but still a pain. Ideally what you want is a way to quickly install the latest build of the Chrome on Android Test Shell on all the connected devices and emulators. Fortunately, this is possible. The kind engineers on the chromium project have a file called LAST_CHANGE which gives us a pointer to the directory that contains the latest build. With this in hand we can script the entire process.

The following script will determine the latest build of ChromiumTestShell, download it to a temporary file, extract ChromiumTestShell from the archive (into another temporary file) and then install it on your connected devices and emulators.

#! /bin/sh

LATEST=`curl -s http://commondatastorage.googleapis.com/chromium-browser-continuous/Android/LAST_CHANGE`

echo Latest Chromium Android at $LATEST

TMP_DL=`mktemp -t chrome-android.XXXX`
TMP_APK=`mktemp -t chrome-android.XXXX`
REMOTE_APK=http://commondatastorage.googleapis.com/chromium-browser-continuous/Android/$LATEST/chrome-android.zip

echo Downlaoding $REMOTE_APK to $TMP_DL
curl $REMOTE_APK -o $TMP_DL

echo Extracting ChromiumTestShell.apk to $TMP_APK
unzip -p $TMP_DL chrome-android/apks/ChromiumTestShell.apk >> $TMP_APK
adb install $TMP_APK

And that’s it.

I recongnise that there probably a lot of things wrong with this, so I have made it available for modification and improvement on GitHub - https://github.com/PaulKinlan/chromium-android-installer.

Screen Recording From Your Android Device

In our talk for Google I/O 2013 — Mobile HTML: The future of your sites — we wanted a way to show actual real demos of Chrome in action without have to constantly switch to the projector over to a special device. Not only does switching cameras waste time, it is also easy to lose the context of what you are demoing in the first place.

The solution we came up with in the end was to record the videos of the device ahead of time and have them in-line in the slides. I think it worked really well and it looked pretty cool too. So how did we do it?

Well. It’s not easy. Nor is our solution cheap.

It turns out that a lot of Android based devices have the ability to output HDCP via a selection of different methods (MHI, MiniHDMI) and if you can take this stream you can record at the FULL 60FPS at the extact resolution of the screen. However the problem that you face with this is two fold:

  1. How do you get the output of the HDMI recorded to disk.
  2. HDCP.

Capturing the HDMI output from the device is pretty easy, but a little bit expensive. We used a device called ”Blackmagic Insensity Shuttle for Thunderbolt” - this device is AMAZING. It allows you to attach HDMI and S-Video outputs and stream it into your Mac (or other computer). You can then use their software to read the data from this new “Camera” and save it directly to a video.

One of the issues you will face is as soon as Android detects you have an HDMI output attached it will force itself into a landscape mode (which is not ideal). The best solution I have found so far is to use Orientation Control (Paid) which lets your force the orientation on the device to be Portrait.

The biggest issue you will face recording from devices is HDCP. HDCP is a form of copy protection which you should not try to break or subvert. The BlackMagic devices will not record anything with HDCP embeded in the HDMI output. After some experiementation I found that the Galaxy Nexus does not attach HDCP to the HDMI output and allows you to record the data from the web browser.

And that is pretty much it!

Bootstraping Your Own Mobile Web Testing Lab for Android Part 1

What do you do if you want to quickly test your sites on mutliple versions of Android at the same time?

There are couple of solutions, such as Adobe Edge Inspect, but what if you want to create and manage your own in your own workflow? I haven’t seen single solution yet.

Here is a simple shell script that I created that starts to get you on your way to your own testing lab. It connects to every single Android device that is attached to your machine by using adb (Android Debugging tool).

The process is as follows (and please suggest better ways):

  • Kill any existing adb servers
  • Get a list of attached devices
  • For each device set up port forwarding (required for Chrome Dev tools)
  • Fire Android intent to open the browser (with a url if one is on the command line)

It’s not a complete solution, but it is a nice way to start. My ultimate goal is to have a Raspberry PI hosting adb and all the devices that I can attach to it with an attached proxy that will route all my devtools requests to the correct device.

How do you test across mutliple devices?

Traffic-lights With CSS

Just before Christmas I wanted to build a site that helped developers understand the impact that using Web Platform features would have on there potential reach. For example, if I used WebGL what is my target reach and what additional features can I use without impacting my potential audience figures.

I launched iwanttouse.com. Sweet. Anyway, that is not the point of this post. One of the features of this site is.

One of the core features I wanted to implement was a traffic light system that graded the features like a traffic light. Green = Good, Red = Bad, Amber = Be Warned.

My original implementation was just using some simple CSS classes.

.good {
  color: green;
}

.ok {
  color: amber;
}

.bad {
  color: red;
}

I knew this was bad, but using RGB I couldn’t work out sanely how to grade between 255,0,0, 255,126,0 and 0,255,0 without having logic in my code that looked like:

if (support < 25%) then .bad
if (support >25% and support < 75%) then .ok
if (support > 75%) then .good

added to that, I wanted the color to be more red than amber if it was at 35%.

Anyway, after a little chat with the awesome Paul Lewis, he mentioned that HSL (Hue, Saturation, Light) color scheme would be good for this problem because naturally the Hue value (0-359) rotates from Red, through Amber to Green (0 = Red, 45 = Amber, 90 = Green)

Red = color: hsla(0, 50%, 50%, 1) Amber = color: hsla(45, 50%, 50%, 1) Green = color: hsla(90, 50%, 50%, 1)

It is then simple given a value for percentage support to map that to 0-90 range and produce your traffic light colors.

element.styles.color = "hsla(" + ((percentage / 100) * 90) + ", 50%, 50%)";

Dear AppCache We Need to Talk.

It’s not me. It’s you!

Ok. thats a little harsh. Without AppCache we wouldn’t even be able to think about building Offline enabled web apps. But it seriously does have some issues, one of which I am blogging about today has been not discussed in depth before (as far as I can tell).

Imagine you building an offline enabled app that integrates with registerProtocolHandler or registerContentHandler. These two API’s use query parameter substitution to pass data from the client page to the service page (http://mailfoo.com/createmail.php?t=paul.kinlan@gmail.com&s=Test Message for example opens up your mail client at createmail.php when you click on a mailto link). This works well for purely online apps, but as we will see when used with apps built with AppCache you won’t get the experience you are expecting, at worst you could DoS your site.

Your createmail.php will likely render a manifest=”cache.manifest” attribute in your html element, which when visited is cached offline and works as expected. The problem lies in the fact that AppCache treats the entire URI (including query strings) as an identifier to the page, therefore if you have a unique query string each of these pages are downloaded and added to the AppCache group.

Ok, cool, but what does this mean? Well it means that http://mailfoo.com/createmail.php?t=paul.kinlan@gmail.com is cached separeately to http://mailfoo.com/createmail.php?t=paul.kinlan@hotmail.com, all the resources will be quickly fetched as the manifest has already got hold of the data and they are already cached in AppCache.

Whilst you are online, this is all gravy. It works beautifully. However now go offline and create an email to paul.kinlan@gmail.com (it works because it is cached), but try instead creating an email to paulkinlan@google.com(via a mailto link)… hmm, where did my app go? It is not there because it has not yet been cached for offline use. Big problem.

You thought that was bad? Now for the kicker.

You happily make and send 100’s of emails over a couple of weeksr. Whilst you are online, all works well. The developer of the app decides to upload a new version of their code so updates their app cache. What happens? Every single unique url (so every email you might have sent via a mailto) is requested and downloaded again (even if it is not in the manifest, it is in the app cache group). If I have sent 100 unique emails via mailto, then every single page with that query sting is fetched quickly by the browser… Seems like a good way to add a lot of load to your machine.

It is pretty hard to change a specifictation in flight so we need to start documenting patterns for building offline apps than we do today because AppCache is not easy to use, and there are lots of gotchas like this that make developers not even bother using the API.

The New iPad Is the Perfect Name

I was thinking about this the other day. I remember being in the Apple store in Liverpool about 2 months ago and I distinctly remember hearing the following: "Do you have any of the new iPads in?" several times over the space of about 30 minutes (I was playing with MacBook Airs).

Come to think of it there were several other products people asked for as "the new X".

It is pretty cool. No product name obsolescence. You go in to a store you ask for the new product, they give it to you.

You either have the new one or the old one.

I predict the iPad series will only ever now be known as iPad and The New iPad. I also believe they will do it for more products the next being The New iPhone.

I Am Willing to Pay Someone to Move My Blog From Posterous.

Posterous has been great for me, but now it is time to move it. I don’t have the time to do this so I am very willing to pay someone a modest fee for managing the move of my blog to a platform that meets the following requirements: Mandatory Requirements: - not a hosted solution like Blogger or Tumblr - static output (no database) - can write posts in markdown, text or html - all content can be managed through git. - URL structure is kept exactly the same as now - will keep all the posts that I imported into posterous from blogger. - full control over templates Nice to haves: - preferably not a ruby based system Not bothered about: - any authoring or management front end. - auto posting networks - existing comments or future commenting systems

We Need to Kill Off the localStorage API

It is a failure of the web, browser vendors and developers that we are in this situation, but we need to stop advocating for and building examples that use the LocalStorage API's, it is simply not a scalable API and the more we build for it the harder it will be for us to ween ourselves off it.  

LocalStorage has poor querying capabilities, terrible performance, small storage in many browsers, crazily inconsistent eventing and a nasty habit of locking.  It's saving grace is simple semantics and "browser support".

Client-side and offline web-apps are not a reality with localStorage, and if we keep pushing it, we are never going to be in a situation where we have a compelling offline or client-side story.

We need to bite the bullet, move on and start building compelling apps, examples and demos build around IndexedDB, that is our only future (I am still aggrieved that the web dropped WebSQL, it was simple and familiar) and we need to do this by stopping to support localStorage. Period.

To this effect, I have taken the BackboneJS example in TodoMVC (by Addy Osmani) and added IndexedDB support using the Backbone JS adapter by Julien Genestoux. I quickly removed the LocalStorage interface, and in a couple of lines of config change I had IndexedDB support in.

On Vendor Prefixes

There is a lot of chatter about Mozilla considering implementing some webkit specific prefixes - I encourage everyone to read ”Platform/Layout/CSS compatibility

My personal take on this is “great” and I am glad they have the guts to start the conversation, but in my eyes it should only happen IFF the vendor is going to choose to stop supporting their existing prefix and start supporting the other parties prefix as what they agree to be the way they want the standard to move. 

I know a lot of people who targeted mobile saw that the audience they needed to target were using almost exclusively a WebKit based browser and thus chose that as the platform to target.  If the mobile device you want to target or your customers want you to target is pretty much a single choice then web developers naturally gravitate to the browser that is most popular and for a long time in the case of iPhone etc, WebKit was (up until recently) your only web platform you had to develop for.

Remy Sharp’s blog post is a good summary of the situation, but I don’t agree with most of the proposed browser solutions.  

To Quote:
Browsers need to:
  • Fucking drop experimental prefixes. It’s unacceptable and a disservice to the developers working with your browser. You need to give timelines to dropping these things.
  • Non-production ready browsers should support experimental prefixes, production ready releases should not. If it’s Chrome 16 - the stable version - experimental support should not be baked in. The properties should be full available without the prefix.
On dropping vendor prefixes, yes but only if they commit to move to another one.  The whole gradient syntax winded me up no end - if at this point WebKit had chosen to name it consistently with the -moz implementation and prefixed it so then we could have started to completely drop the old syntax that IMO would have been better.  At the same time though we should be educating developers about the tooling available to make the vendor prefixing become a non-story (in most cases).

I had a little chuckle about “production ready browsers” - I don’t think this is sensible or feasible given the update cycles of browser and that developers want what they have chosen to implement to look ace in the browsers that they have chosen to make it look awesome in.  If you have platform features that no other browser is going to support either now in the near future then we need to have a way to not have them in the base “namespace” - putting them in there is going to cause more problems.

Anyway, these are my thoughts and can be and sometimes are hogwash - my motto is “don’t hate, advocate” - and as Remy says “As developers we need to better educate.” to which I whole heartedly agree.