Tales of a Developer Advocate

... and other things

Feature On Desktop On Mobile
PNG alpha transparency Yes Yes
querySelector/querySelectorAll   Yes
getElementsByClassName   Yes
CSS3 Multiple backgrounds   Yes
CSS3 Background-image options   Yes
CSS Table display   Yes
CSS Generated content   Yes
CSS 2.1 selectors Yes Yes
CSS3 selectors   Yes
CSS3 Text-shadow   Yes
CSS3 Colors   Yes
CSS3 Box-sizing   Yes
CSS3 Media Queries   Yes
CSS3 Multiple column layout   Yes
Canvas (basic support)   Yes
Cross-document messaging   Yes
Data URIs   Yes
XHTML served as application/xhtml+xml   Yes
CSS3 Opacity Yes Yes
JSON parsing Yes Yes
CSS3 Text-overflow   Yes
CSS3 Overflow-wrap Yes Yes
CSS min/max-width/height Yes Yes
CSS inline-block Yes Yes
dataset & data-* attributes Yes Yes
CSS Counters   Yes
getComputedStyle   Yes
contentEditable Yes  
Drag and Drop Yes  

Pretty damning.

At “100%” coverage of features that are in all browsers split by Mobile and Desktop then this is all we have to play with.

Ok, this is actually misleading. If you are willing to miss out on 1% extra reach for your desktop audience then you can get similar feature parity with mobile. But still the feature support that is ubiquitous across the web is actually pretty small especially if you are supporting IE8.

How do I know what the web platform is?

Last year I built iwanttouse.com to make it easier for you to determine the cost on your userbase supporting certain features will have. If I support X, I can only reach Y% of the web’s users

The project is pretty simple. It is a projection of the data on CanIUse.com. For a given “feature” it looks for the earliest version on a platform that it was supported on and sums the “usage”.

I split the feature set by Mobile and Desktop and it gives you some pretty interesting nuggets of data.

Two things that fell out of this:

  • Features for Free. If I choose Web Audio (43% on mobile) I can also safely use other features such as Server-sent DOM Events because all browsers that support the former support the latter. (Note: the inverse relationship is not always true)
  • Ubiquitous Platform features. As above but platform features that we can rely on being present in all browsers with any significant share.

I want to focus on Ubiquitous Platform features.

How do we improve the web platform?

As a web developer today I face a couple of problems: Legacy browsers that aren’t updated and inconsistent implementation across browsers.

The web feels like a pirate ship, everyone is hacking and slashing in different directions and we are lucky enough that the ship goes forwards. Slowly. How do we become a Ben Ainslie America’s Cup winning yacht?… (Ack, I can’t believe I said that). Point is, how can we improve the modern mobile web consistently if there are multiple large players in the eco-system?

  1. Wait it out and let the Browser vendors do their thing. This will change over time as people move off the platforms that have stopped progressing as their devices are renewed.
  2. Ignore the old browsers and the users that use them and go for it.
  3. Push for consistency across the platform.

My preference is for 2 and 3. But actually 1 is what we really really need to solve.

I like to solve level 1 problems — problems with a technical solution — they’re the things I can fix. I can meet developers and work with them on their sites to measurably make the web better one large site at a time, but it is all small scale…

I decided to take a peek at the features that are supported across the latest mobile browsers and the reach that will have: 44%. We can’t honestly say to a business that you should build experiences for 44% of your potential user base (well, it depends who you want to sell or attract - your demographics might be highly skewed - i.e.. Government legislation, Business demands.)

If you look at the head of the mobile web (44%) there is a compelling feature set. You can build some amazing applications with it.

Feature Android Browser 4.4 iOS Safari 7.0 Chrome for Android 32.0 IE Mobile 10.0 Opera Mobile 16.0 Firefox for Android 26.0 Blackberry Browser 10.0
XHTML served as application/xhtml+xml Yes Yes Yes Yes Yes Yes Yes
XMLHttpRequest 2 Yes Yes Yes Yes Yes Yes Yes
WOFF - Web Open Font Format Yes Yes Yes Yes Yes Yes Yes
Web Workers Yes Yes Yes Yes Yes Yes Yes
Web Sockets Yes Yes Yes Yes Yes Yes Yes
Video element Yes Yes Yes Yes Yes Yes Yes
ECMAScript 5 Strict Mode Yes Yes Yes Yes Yes Yes Yes
Typed Arrays Yes Yes Yes Yes Yes Yes Yes
CSS3 Transforms Yes Yes Yes Yes Yes Yes Yes
CSS3 Text-overflow Yes Yes Yes Yes Yes Yes Yes
SVG in HTML img element Yes Yes Yes Yes Yes Yes Yes
Inline SVG in HTML5 Yes Yes Yes Yes Yes Yes Yes
SVG filters Yes Yes Yes Yes Yes Yes Yes
SVG in CSS backgrounds Yes Yes Yes Yes Yes Yes Yes
SVG (basic support) Yes Yes Yes Yes Yes Yes Yes
defer attribute for external scripts Yes Yes Yes Yes Yes Yes Yes
async attribute for external scripts Yes Yes Yes Yes Yes Yes Yes
requestAnimationFrame Yes Yes Yes Yes Yes Yes Yes
rem (root em) units Yes Yes Yes Yes Yes Yes Yes
querySelector/querySelectorAll Yes Yes Yes Yes Yes Yes Yes
PNG alpha transparency Yes Yes Yes Yes Yes Yes Yes
Page Visibility Yes Yes Yes Yes Yes Yes Yes
CSS outline Yes Yes Yes Yes Yes Yes Yes
Offline web applications Yes Yes Yes Yes Yes Yes Yes
Web Storage - name/value pairs Yes Yes Yes Yes Yes Yes Yes
CSS3 Multiple backgrounds Yes Yes Yes Yes Yes Yes Yes
CSS min/max-width/height Yes Yes Yes Yes Yes Yes Yes
matchMedia Yes Yes Yes Yes Yes Yes Yes
JSON parsing Yes Yes Yes Yes Yes Yes Yes
Range input type Yes Yes Yes Yes Yes Yes Yes
input placeholder attribute Yes Yes Yes Yes Yes Yes Yes
CSS inline-block Yes Yes Yes Yes Yes Yes Yes
sandbox attribute for iframes Yes Yes Yes Yes Yes Yes Yes
New semantic elements Yes Yes Yes Yes Yes Yes Yes
Session history management Yes Yes Yes Yes Yes Yes Yes
Hashchange event Yes Yes Yes Yes Yes Yes Yes
getElementsByClassName Yes Yes Yes Yes Yes Yes Yes
getComputedStyle Yes Yes Yes Yes Yes Yes Yes
Geolocation Yes Yes Yes Yes Yes Yes Yes
@font-face Web fonts Yes Yes Yes Yes Yes Yes Yes
FileReader API Yes Yes Yes Yes Yes Yes Yes
CSS3 Colors Yes Yes Yes Yes Yes Yes Yes
CSS3 Transitions Yes Yes Yes Yes Yes Yes Yes
CSS3 Text-shadow Yes Yes Yes Yes Yes Yes Yes
CSS Table display Yes Yes Yes Yes Yes Yes Yes
CSS3 selectors Yes Yes Yes Yes Yes Yes Yes
CSS 2.1 selectors Yes Yes Yes Yes Yes Yes Yes
CSS Repeating Gradients Yes Yes Yes Yes Yes Yes Yes
CSS3 Opacity Yes Yes Yes Yes Yes Yes Yes
CSS3 Media Queries Yes Yes Yes Yes Yes Yes Yes
CSS Gradients Yes Yes Yes Yes Yes Yes Yes
CSS Generated content Yes Yes Yes Yes Yes Yes Yes
CSS Counters Yes Yes Yes Yes Yes Yes Yes
CSS3 Box-shadow Yes Yes Yes Yes Yes Yes Yes
CSS3 Animation Yes Yes Yes Yes Yes Yes Yes
Cross-Origin Resource Sharing Yes Yes Yes Yes Yes Yes Yes
contenteditable attribute (basic support) Yes Yes Yes Yes Yes Yes Yes
classList (DOMTokenList ) Yes Yes Yes Yes Yes Yes Yes
Text API for Canvas Yes Yes Yes Yes Yes Yes Yes
Canvas (basic support) Yes Yes Yes Yes Yes Yes Yes
calc() as CSS unit value Yes Yes Yes Yes Yes Yes Yes
CSS3 Border-radius (rounded corners) Yes Yes Yes Yes Yes Yes Yes
CSS3 Background-image options Yes Yes Yes Yes Yes Yes Yes
Audio element Yes Yes Yes Yes Yes Yes Yes
Cross-document messaging Yes Yes Yes Partial Yes Yes Yes
CSS3 3D Transforms Yes Yes Yes Partial Yes Yes Yes
MPEG-4/H.264 video format Yes Yes Yes Yes Yes Partial Yes
Data URIs Yes Yes Yes Partial Yes Yes Yes
dataset & data-* attributes Yes Yes Yes Partial Yes Yes Yes
CSS position:fixed Yes Partial Yes Yes Yes Yes Yes
Content Security Policy Yes Yes Yes Partial Yes Yes Yes
Blob constructing Partial Yes Yes Yes Yes Yes Yes
CSS3 Overflow-wrap Yes Yes Yes Partial Yes Partial Yes
Progress & Meter Yes Partial Yes Partial Yes Yes Yes
Flexible Box Layout Module Yes Yes Yes Partial Yes Partial Yes

But like I said. 44%. It’s a big head but not a feasible platform for the vast majority of companies. I produced the following breakdown of features that we should get Chrome and other vendors to fix feature support at a tactical level to make for a more consistent web and make developers lives easier. The problem is we are only fixing it for 44% of the web’s users. Documented below for consistency

Feature Android Browser 4.4 iOS Safari 7.0 Chrome for Android 32.0 IE Mobile 10.0 Opera Mobile 16.0 Firefox for Android 26.0 Blackberry Browser 10.0
TTF/OTF - TrueType and OpenType font support Yes Yes Yes Unknown Yes Yes Yes
Touch events Yes Yes Yes No Yes Yes Yes
Navigation Timing API Yes No Yes Yes Yes Yes Yes
Mutation Observer Yes Yes Yes No Yes Yes Yes
Intrinsic & Extrinsic Sizing Yes Yes Yes No Yes Yes Yes
Font feature settings Yes Yes Yes No Yes Yes Yes
File API Yes Yes Yes No Yes Yes Yes
Server-sent DOM events Yes Yes Yes No Yes Yes Yes
CSS3 tab-size Yes Yes Yes No Yes Yes Yes
Channel messaging Yes Yes Yes Yes Yes No Yes
CSS3 Border images Yes Yes Yes No Yes Yes Yes
Blob URLs Yes Yes Yes No Yes Yes Yes
Viewport units: vw, vh, vmin, vmax Yes Partial Yes Partial Yes Yes Partial
SVG SMIL animation Yes Partial Yes No Yes Yes Yes
IndexedDB Yes No Yes Yes Yes Yes Partial
CSS3 word-break Partial Partial Partial Yes Partial Yes Partial
SVG fonts Yes Yes Yes No Yes No Yes
Download attribute Yes No Yes No Yes Yes Yes
Details & Summary elements Yes Yes Yes No Yes No Yes
CSS Filter Effects Yes Yes Yes No Yes No Yes
CSS3 Multiple column layout Partial Partial Partial Yes Partial Partial Partial
Date/time input types Yes Yes Yes No Partial No Yes
HTML5 form features Partial Yes Partial Partial Partial Partial Partial
Form validation No No Yes Partial Yes Yes Yes
CSS3 Box-sizing Partial Partial Partial Partial Partial Yes Partial
WAI-ARIA Accessibility features Partial Partial Partial Yes Partial Yes No
SVG effects for HTML Partial Partial Partial No Partial Yes Yes
matches() DOM method Partial Partial Partial Partial Partial Partial Partial
HTML templates Yes No Yes No Yes Yes No
Strict Transport Security Yes Unknown Yes No Yes Yes No
getUserMedia/Stream API No No Yes No Yes Yes Yes
Color input type Yes No Yes No Yes No Yes
CSS Feature Queries Yes No Yes No Yes Yes No
Clipboard API Partial Partial Partial No Partial Yes Partial
Canvas blend modes Yes Yes Yes No No Yes No
Ruby annotation Partial Partial Partial Partial Partial No Partial
Number input type Partial Partial Partial Partial Partial No Partial
DeviceOrientation events Partial Partial Partial No Partial Partial Partial
WebGL - 3D Canvas graphics No No Partial No Yes Partial Yes
Web Notifications Partial No No No Partial Yes Yes
Full Screen API No No Yes No Yes Partial Partial
WebP image format Yes No Yes No Yes No No
SVG fragment identifiers No No No Yes No Yes Yes
Shadow DOM Yes No Yes No Yes No No
WebRTC Peer-to-peer connections No No Yes No Yes Yes No
MathML No Yes No No No Yes Yes
Filesystem & FileWriter API No No Yes No Yes No Yes
CSS Masks Partial Partial Partial No Partial No Partial
Web Audio API No Yes Yes No No Yes No
WebM video format Partial No Yes No Partial Partial No
Datalist element No No No No No Yes Yes
CSS Hyphenation No Yes No No No Yes No
CSS Regions No Yes No Partial No No No
Promises No No Partial No No Partial No
Scoped CSS No No No No No Yes No
Shared Web Workers No No No No No No Yes
Opus No No No No No Yes No
Ogg/Theora video format No No No No No Yes No
JPEG XR image format No No No Yes No No No
Drag and Drop No No No Yes No No No
CSS resize property No No No No No Yes No
CSS Grid Layout No No No Yes No No No
Pointer events No No No Partial No No No
CSS3 object-fit/object-position No No No No No No No
Toolbar/context menu No No No No No No No
CSS Variables No No No No No No No
Blending of CSS image No No No No No No No

Getting these features implemented would be cool but there is no additional reach at all. More users will not be affected by these new features. We didn’t increase the size of the user base. Yes we might get an amazing WebGL based WebComponents app that people use but will they upgrade their browser or phone to be able to use it? Probably not.

So what do we do?

How do we move the web platform forward in a meaningful way?

It is hard.

Do we want to get back to a world where this is a thing?

best viewed in

Maybe.???

At a minimum we should:

  • Build for the 90% and get your partners and customers to see at a minimum the experience that you can build with a huge amount of reach.
  • Understand the choices you make and the impact they have. Push your customers and partners to use progressive enchancement. Don’t exclude a huge number of users for a single feature.
  • Push for consistency over new platform features across all browser vendors.

Tell me I am wrong

It is no secret that Github is amazing. I don’t think it is widely known that they also have a very comprehensive Developer Platform.

Developer Landing Page

I admit it. I love the API. It’s an amazing example of how to build a platform.

Rather than fawning over Github, I really want to talk about the projects that I have worked on recently that take advantage of the API and roughly how we utilised this platform to optimise our workflows and experiences.

The first is HTML5 Rocks and the second is DevArt. I will only focus on HTML5 Rocks in this article (it turned out to be a lot longer than I planned).

HTML5 Rocks is a resource that we manage for web developers. It is entirely open source and the content licenced under Creative Commons. We host the site on AppEngine and the code on Github. Admittedly it is not obvious how we could use the Github API to help us.

The original process for deploying to HTML5Rocks was for a weekly “Sheriff” to monitor Github for any commit from the team or pull-request, git pull to a local repository, check the changes locally, run the site through a compressor and finally upload it to AppEngine.

Not only was it manual, you were flying blind. If you were the Sheriff you had no idea what was due to be launched that week. We used the issue tracker to manage the article pipeline but we couldn’t use the Milestones effectively because as a content site we didn’t work to milestones.

This process was tedious and could often be error prone. You were not a happy bunny if you were the weekly sheriff.

The first task was to make our article pipeline more visible for the entire team. We needed some sort of dashboard…

Working with Github Issues API

The Github API offers the ability to nearly fully manage your repositories issues. All of our articles that are due to be delivered are in the issue tracker. Combing the two we can automatically get a list of articles that are delivered and article that are yet to be completed.

Our new Workflow is:

  • Create an issue with some meta data (about the owner, the reviewer and the due date)
  • Work on your article in your own repo
  • Issue a pull request with the title “Fixes #[your issue number]”

That’s it. The system does the rest.

  • Github automatically closes the issue when the pull request is merged.
  • The system picks up this change, pulls down the latest code,
  • Regenerates the Calendar Dashboard
  • Commits the change and pushes it back up to Github.

This is pretty cool. We now have automated our article pipeline. This gives us greater visibility across the team as to what changed on a week by week basis. In this scenario, commits are not important but delivery of articles is.

Issues dashboard

The full code for this report generation is in our repository. We used PyGithub to simplify access to the API. To show how simple it is to use a summary appears below.

open_issues = repo.get_issues(state="open")
closed_issues = repo.get_issues(state="closed")

issues = []
[issues.append(i) for i in open_issues]
[issues.append(i) for i in closed_issues]
today = datetime.today()
completed_articles, late_articles, due_articles = ParseIssues(issues)

print "HTML5 Rocks Quarter Report for %s" % today.date()
print "=========================================\n"

print "Articles due this quater"    
print "------------------------\n"

if len(due_articles) == 0: 
    print "There are no articles due this quarter, either all is good, or something messed up!\n"
else:
    print "|Author|Article|Delivery date|Tech Writer|State|"
    print "|------|-------|-------------|-----------|-----|"

    for article in due_articles:
        print "|%s|[%s](%s)|%s|%s|%s" % ((article.assignee or article.user).name, article.title, article.html_url, article.due_on.date(), article.tech_writer, article.state)

See. Pretty simple.

This is great, but once the author has committed their article they still can’t see it live on the web. To make this easier we need to do a little more work.

I have not seen anyone auto deploy to App Engine via Github yet so I hope this serves as an example of how it is possible.

Deploying to App Engine from Github

If you have ever used AppEngine you will know that deploying a new build is often a manual process. It is a pain. Most developers don’t know that you can automate it using the command line tool.

If you can push live automatically, then all you really need to do is push the changes as they happen. The question is how do you get notified about changes to a repository as it happens? Polling? No.

Github use Webhooks. They are Amazeballs. WebHooks let you register a url that Github will call whenever there is a change to the repository. When you get this call you can automate some process on your system. It is that simple. It is very very powerful.

We then used a custom version of Github-Auto-Deploy to manage two read-only versions of site (staging and live.)

Github-Auto-Deploy is a rather amazing micro-server, it simply listens to GitHub Webhooks, pulls in the changes to the repository and runs a command. In our case the example command is as follows:

versionStr=${1:-master}
appcfg.py --oauth2 --version=$versionStr update ../

See the first line above? That lets us choose which appengine version we will deploy to, it is based off the name of the branch. By default any commit to the repository will push to our staging server. Any commit to repository to the live branch will push to the live site.

The interesting part here is that we can simply create a pull request from our master branch to our live branch branch and via the WebHook system we will have all the staged changes live and available to all of our users.

Merge from staging to live

We are pretty pleased with this process. We made it far easier to test changes on the web site and more importantly we took getting a change “live” from about 8 minutes to 10 seconds (excluding deploy time to appengine - about 30 seconds) and we saved our team a lot of frustration. An added benefit, although I can’t prove it, is that since the increases in deployment and testing efficiency we have seen a massive increase in external developer contributions.

With HTML5 Rocks we have only touched the surface of the API, but I encourage every developer who uses Github to check out the API and think about how you can integrate it in to your workflow to improve your efficiency.

There has been a lot of great discussion about standardising the “Add to Homescreen” functionality across browsers.

Before I dive in, catch up with the latest thinking:

We have an obsession with Apps and the deployment models that they present: Upload to a store, drive the user to go to the store, download and install.

Web Developers want installable web apps. They want a place on the homescreen eschewing the need for the (App Play *) model for App delivery. I get it.

We have had this on iOS for a long time via <meta name="apple-mobile-web-app-capable" content="yes"> — if I remember correctly this has been here since the first version of iOS — it was the only way to get apps on to your device. Developers even made promo widgets that let users know they can “install” the web app. Yet it wasn’t enough, developers and users didn’t actually want this, they wanted more capable installable apps. Installing a web page? Are you nuts.

We (web developers) pushed and pushed for installable web apps from the browser even more. It landed in Chrome for Android and developers loved the idea. Not many people have implemented it (even including the Apple syntax). Not many people use it.

When was the last time you added an App to the homescreen? When was the last time you saw any site mention installing a web-app? Thought so.

I am not opposed to making web-apps more integrated with the systems on which they live but we are focusing on the wrong solution to the problem. Ideally you should never be able to tell if you are usage a web page, or using an installed app. But …

No one has made the case that on mobile users want the ability to install web apps to the home screen. Seriously. Apple has had this feature yet users and developers wanted native apps, so they made a new platform whilst solving a huge number of other problems developers were facing that the web never solved: Simple payments and monetisation, better discovery, offline usage (in theory), perfomance and features.

Add to Homescreen is us trying to play in the “apps” league. A league we won’t be able to compete in.

I want to see something much more fundamental. The web offers something far richer: it encourages lightweight usage with no required installation and interaction with on-demand permissions. I never want to see an install button or the requirement to understand all the potential permissions requried before trying the app. The system should understand that I am using an app and how frequently that I use it and it should then automatically integrate with the launch points in the OS.

I don’t have the answer at the moment. Products like Aviate are starting to move to this model. I could have sworn that Firefox OS was doing something similar to this as one facet of their system.

I am goung to write a follow up post about abuse of the “Add to Homescreen” which is an area entirely.

If you are seeing this then everything worked fine and dandy. Woot.

It probably isn’t hard to tell that this Blog is built using Jekyll (Octopress actually) and one of the things that I have always wanted to fix was how I deploy the site.

The workflow that I have used in the past is to:

  • edit locally.
  • commit changes to a github repository
  • then rake deploy via ssh.

Whilst this flow works pretty well, there are number of times where I don’t have terminal access and even if I did, I don’t have my public keys.

I need to be able to make changes on Github (or any other system that I can use to access my repository) and have them live on my site shortly after.

The new process I have now uses Github’s WebHooks (they are amazing) to tell my blog to pull in the latest changes from the repository, build them and get them live. To integrate with Gihub’s WebHooks I use the amazingly simple Github-Auto-Deploy with some modificiation from the original project and simple build script.

There really isn’t anything to show you other than it just works. Now my deployment process is just a simple push up to Github. I even have the same ability to edit and test locally if I need to.

Oddly I rarely talk about Developer Relations, but I feel like changing that today.

I feel really uncomfortable when I hear people suggest Hackathons are a part of building a sustainable, scalable developer ecosystem.

They are not.

I have run hackathons. Some better than others. I have learnt a lot about them.

Businesses and Platform creators:

  • If you are thinking of running a hackathon to win potential new customers you are doing it wrong.
  • If you are wanting someone to start a business by using your platform at your hackathon you are doing it wrong.
  • If you are running hackathons to raise brand awareness you are doing it wrong.
  • If you are offering winners $SOMERANDOMLARGENUMBER you are doing it wrong.
  • If your product team (PMs through to Eng) are not at the hackathon you are doing it wrong.

Hackathons can be a thing of beauty, they can produce completely unexpected demos, but that is not your goal. You should be using it as a learning exercise for you, your team and fixing your product. It is the developer version of a beta test, not a marketing tool.

Learn from the developers using your platform. Ask yourselves the following questions:

  • Do your demos work? are developers using the demos to build on top of them?
  • Does your documentation work? can developers start by diving into the docs and following the guides step by step?
  • Does your platform work? Is your API intuitive? Are developers getting stuck on certain parts?
  • Is there value to your platform? Is it possible for people to build sustainable integrations on your platform?

You can answer all these questions at a Hackathon. That is what you should be concentrating on.

One little point, rather than just rewarding teams who produce a lot, reward filing bugs and issues on all parts of your product, the apis, the documentation, the demos and the value as well.

Page Speed Insights for Mobile launched the other week. It’s a tool that analyses your site in the context of a mobile device and tells you what you need to do to improve the network performance of the site.

In about an hour I had taken 3 seconds off my blogs page load time by removing JS files and adding Caching (doh!) and crunching PNGs (double doh!), going from a score of about 34 to 84.

One of the criteria it suggested “Reduce render blocking scripts in ‘Above the Fold’ content”, specifically fixing the blocking CSS. The theory behind this is that the reader should get the first screens worth of content to the user in the first few TCP packets of response. Any script or CSS file that is required to display content within the first screen of content is an additional network which will significantly slow down the apparent rendering of the page.

In my head this makes sense - Critical CSS is the minimum set of CSS I need to make my page look as I expect and readable to the user. Critical CSS in the context of Page Speed Insights for mobile is the Minumum set of CSS required to render the Above-the-fold content. Ignoring whether AtF is really a thing on the web these days, the concept is that often users load the page at the top of the screen and you want to get that set of data to the user as quickly as possible, especially on Mobile where every connection you make to a server slows your site down.

An example follows - the original CSS in this image includes a whole set of features that are not applicable, overriden or are not visible above the fold (if you read a couple of paragraphs down you will see the link to demo). In this code though, the last-child pseudo selector is not output because the content is not visible.

In practice determining what is considered the “Critical CSS” is rather complex. I have one rather huge CSS file that is used for all the content across the site. How do I determine what is critical to that page and what is not?

I have developed a quick proof of concept that will walk your Page’s DOM, and determine the minimal set of CSS. You can fork it on Github or use this code in a bookmarklet or DevTools Snippet. The general flow is:

  1. Iterate across every element in the DOM
  2. Accept elements whose “top” is within the height of window.
  3. Detect the list of styles that currently apply to the element in view using window.getMatchedCSS(node)
  4. Add them to a bucket.
  5. Return the list of CSS.

It works pretty well. If the element is not visible or not on the first screen of content then its matching CSS selectors are not returned in the output.

Possible uses:

  1. Determine the minimum viable set of CSS for a page so you can clean it up.
  2. Integrate into build and testing steps and warn on excessive CSS used on pages. Possibly using PhantomJS
  3. Make it a part of your build to construct the CSS files needed for each page and just the CSS needed for that page.

There are some caveats though.

  1. It only works in WebKit and Blink engines.
  2. It doesn’t know about Media Queries it only determines content based on the current viewport
  3. It will not find the CSS selectors for psuedo elements such as :hover etc.

Over the past week I have been working steadily to improve the mobile experience of html5rocks.com. Now don’t get me wrong, it already is responsive, I just don’t think it was hugely readable on a mobile or tablet device.

One of the areas that I have been focusing on is the “Time to first read”, that is how long does it take the reader to get their eyes on the text they want to read. In our case, sometimes it was three screens worth of vertical scrolling before you could start reading the article. The biggest culprit is the Table of Contents (ToC).

Almost exactly a week ago I wrote about experiments to remove the ToC burden. The experiement centred around moving the ToC offscreen and summoning via a user gesture - a tap in this case. My goal was to create this offscreen ToC just using CSS by hijacking the :active psuedo class. Whilst it was pretty easy in my browser of choice (Chrome) it turns out their are inconsistencies amoungst all browser that mean it is nigh-on impossible to create the consistent experience that I wanted.

All is not lost (hence this post).

Our site already had a piece of JS that would toggle a CSS class when the reader clicked the “Table of Contents” header. By using this, it is simple to hang off the relevant CSS styles to implement the table of contents. It uses the exact same principle as the article: Fix the ToC to the footer of the page, when toggled make the content visible. And that is it.

The “con” for this solution is that as of this moment there is a Javascript requirement and I am still trying to work out how to do this purely in CSS.

Given that this is really no different from my previous approach, why am I blogging about it? Well, I just really wanted to show something off.

In speaking with Paul Lewis we looked at the design of the final solution - in my eyes, the ideal solution was to have this small area on the bottom of the page that displays a scrollable ToC. Why? Because as a reader I could still see the content if I wanted to. Paul’s suggestion though was to just take the table of contents full screen.

I was a little sceptical at first (I always am, but Paul is correct 99% of the time). Paul’s suggestion does have the following benefits:

  • Less distraction . The reader wanted the table of contents so give it to them. Having the ToC popup and only take a portion of the screen leaves the user seeing 3 things, the top menu, the article and the ToC. The intent of the reader is not being clearly managed.
  • Less clutter. Scrolling elements in to take up a portion of the screen, but keeps everything else on the screen. There are too many things that the reader could accidentally click on.
  • More screen estate. I did not appreciate this at the time, but by giving the screen up for the ToC we get to do some really nice things that make sense including:
    • Displaying the entire ToC without scrolling in most cases
    • Making the content more readalbe by boosting the font size
    • Creating bigger touch targets through the increased font-size and padding so it is easier to get to the point in the article you want
    • With bigger type we could apply a subtle heirarchy to the content for nested ul by changing the colour of the font sligthly. When the type was smaller it was very hard to see any difference at all in the font colour.

Let’s have a look at the changes.

Before

This is just one example of an article, the header is in place with the title and the author, and then there is a table of contents stopping the reader from starting to read the actual article. Every artcile is currently like this.

After

Now you can see that the header is still in the same place and we can start reading the content straight away. If you want to navigate around the page you can bring up the Table of Contents by clicking the bottom footer.

And as you can see below, the ToC is now a full screen experience, the text is larger and clearer making it easier to interact with.

Overall I am pleased with the new experience and I hoping to get it live soon. The example shown in this article is one of the larger Table of Contents and I think it holds up well even if the user has to scroll through all the headings.

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.

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.

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!