HTML5 Full Screen Mode: Quick Notes

Just been playing with full-screen mode in Chrome, which lets any element become full-screen (not just video, as I think it was envisioned in earlier days). Wanting to get this working nicely on mobile devices, I’ve also done some experimenting with graceful degradation / progressive enhancement as it applies to full-screen mode.

Basic Version

Although you can full-screen any element, I decided to full-screen the entire body, then use a kind of classy HTML to show what needs to be shown in full-screen mode. (Mainly because I’m using a component that wasn’t immediately working when I full-screened it directly.)

I’m using a full-screen toggle element, here’s the CoffeeScript:

  1. $('#fullScreen').click (ev) ->
  2.     if document.webkitIsFullScreen then document.webkitCancelFullScreen() else document.body.webkitRequestFullScreen()

Note that you cancel on document (that’s the only thing you can cancel on), but you set it on any element (though you actually can’t set it on document!). Also, note that the user could manually hit escape to exit, so don’t think that you’re always in control of full-screen state. Hence the webkitIsFullScreen check instead of trying to maintain state in a flag variable.

Following the Classy HTML pattern, the CSS here is based on a new pseudo-selector which gets applied to the body element. We can easily decide what to include in full-screen mode. In this case, as the SCSS below shows, I’ve simply elevated the map element above everything else, but knock yourself out.

  1. :-webkit-full-screen {
  2.   #map {
  3.     position: absolute;
  4.     z-index: 2000;
  5.     top: 0;
  6.     left: 0;
  7.     width: 100%;
  8.     height: 100%;
  9.   }
  10. }

And no, it’s not just for Webkit…go check out MDN’s full-screen docs for more info.

Graceful Degradation Version

But what if there’s no full screen mode? We can still make that full-screen toggle useful by expanding content to max out the browser screen, even though the browser itself can’t switch into full screen mode. So here’s another crack at it, where we use the true Classy HTML pattern, i.e. instead of styling according to the built-in full-screen pseudoselector, we make our own “fullScreen” class. If the document is in either :-webkit-full-screen or “fullScreen” state, we’ll max out the important content.

  1. fullScreenEnabled = (typeof(document.webkitCancelFullScreen)!='undefined')
  2.   $('#fullScreen').click (ev) ->
  3.     if fullScreenEnabled
  4.       if $('body:-webkit-full-screen').length
  5.         document.webkitCancelFullScreen()
  6.       else
  7.         document.body.webkitRequestFullScreen()ยท
  8.     else # oh well, at least we can big up the content inside the browser
  9.       console.log('full not enabled')
  10.       if $('body').hasClass('fullScreen')
  11.         $('body').removeClass('fullScreen')
  12.       else
  13.         $('body').addClass('fullScreen')

The style is exactly the same as before, just with two selectors involved. Something like this, in theory:

  1. :-webkit-full-screen,.fullScreen {
  2.   #map {
  3.     position: absolute;
  4.     z-index: 2000;
  5.     top: 0;
  6.     left: 0;
  7.     width: 100%;
  8.     height: 100%;
  9.   }
  10. }

But in practice, for some hair-pulling reason, non-webkit browsers will ignore that entire rule, so I had to duplicate it:

  1. :-webkit-full-screen {
  2.   #map {
  3.     position: absolute;
  4.     z-index: 2000;
  5.     top: 0;
  6.     left: 0;
  7.     width: 100%;
  8.     height: 100%;
  9.   }
  10. }
  11.  
  12. /* As DRY as mud...but I found this duplication required */
  13. .fullScreen {
  14.   #map {
  15.     position: absolute;
  16.     z-index: 2000;
  17.     top: 0;
  18.     left: 0;
  19.     width: 100%;
  20.     height: 100%;
  21.   }
  22. }

Now the full-screen toggle works for all browsers. But full-screen enabled browsers get the nice bonus of busing out of the browser tab and taking up the entire desktop.

(Again, I confess, this is me messing around with webKit only for now. The graceful degradation stuff does work with Firefox of course, though it could do more than just that. I haven’t used full-screen on Firefox simply because there are other components not working on Firefox, and this post is based on practical experience. It’s well-supported on both Firefox though as well as Chrome.)

HTML5 App Themes Are Coming

There are plenty of premium theme markets out there. Many are for vanilla websites, where they provide you with the entire HTML, CSS, and JavaScript, while some are for specific frameworks, e.g. WordPress themes aplenty.

A huge gap in the market remains: Apps. Having trawled through a bunch of these — admittedly some months ago — I concluded the closest thing was some system admin templates for systems like CPanel. Yet every day, hobbyists and startups are creating thousands of apps. Not on the same scale as marketers are churning out WordPress blogs about <insert-niche-here>, but still, big enough to warrant art-less developers not having to cobble together their own look-and-feel for a v1.

A big part of the problem is lack of standardisation. HTML5 apps pretty-much have any arbitrary page structure and class names. The HTML5 semantic tags may have helped here to standardise on entities like “section” and “article”, but it’s not clear how many developers are using those elements. And I’m sure some, like me, are just using them as class names for divs (for improved compatibility), while others are using the actual tags, and some are doing the Right Thing by using both. Where WordPress themes can assume a lot about page structure, HTML5 app frameworks cannot.

In other words, HTML5 suffers from a lack of conventions. WordPress is not the only example of the power of conventions. Witness the vibrant marketplace of Rails gems, which can support powerful styles of reuse because they are able to build on conventions. Likewise, jQuery and Backbone plugins.

This will change soon because of two great frameworks: Twitter Bootstrap and HTML5 Boilerplate. These are becoming very common frameworks for HTML5 developers to get started and will soon be combined if this issue happens with Boilerplate 2.5. It will build a Bootstrap kickstart for Boilerplate. That’s a real Bootstrap.

You can start to see Bootstrap apps sprout like weeds across the web, marked by their characteristic Twitter-like black navbar. It’s a genius framework and one I’ve benefitted from immensely. But the problem is, for something called Bootstrap, it surprisingly doesn’t include any HTML at all. So that navbar is actually what people are mostly cut-and-pasting from the docs and examples. The lack of standards makes it hard to produce themes. There’s already a premium theme site out there, but it proves my point. If you look at the markup, it’s wide and varied, even for the navbar.

I’m hopeful the Boilerplate combination will rectify that situation. If apps can move towards a common page structure and naming conventions, a world of themes will blossom.

Imgur

Firefighting an RSS Aggregator’s Performance

chart

That’s a before-and-after shot of the database server’s CPU! I was watching it slowly creep up, planning to inspect it after some other work, before receiving mails from Linode that the virtual server is running over 102% capacity, then 110, 120, …

Three things made the difference in fixing this:

Feed Item Keys Must Be Unique

The most important thing was to nail down keys, which I noticed from looking at logs and the oddly cyclic nature of the graph above. I later on ran a query to see how many items were being stored for each feed, and sure enough, certain feeds had thousands of items and counting.

The RSS 2.0 spec (as official a spec as there is) says of individual items: “All elements of an item are optional, however at least one of title or description must be present.”. What’s missing there is a primary key! Fortunately, most feeds do have a unique <link>, <guid>, or both. But if you’re trying to be robust and handle unanticipated feeds, it gets tricky. There were also some boundary cases involving feeds which had changed their strategy (fortunately, improved it by adding guids) at some point, but never updated the old items. So the feed was a hybrid.

The net effect was a gigantic number of items being accumulated for certain feeds. Every hour, the server checked for updates, it decided that yes these key-less feeds had totally changed and we need to pull all the posts in again and save a record of it. That’s why you see the hourly cycles in the “before” picture. I still need to go and cleanse the database of those duplicate items.

By taking a step back and looking at what makes the items truly unique, and with the help of Rails’ handy collection methods, it was possible to make feed items unique again and smooth out crawling.

Indexing

Inspecting a handful of anomalous feeds once an hour, due to the problem mentioned above, is not the worst thing in the world. What made the server veer towards FUBAR was certain query that was being performed each time in the absence of indexes. I was able to see the heaviest queries in the Rails log using the grep/sed command posted here yesterday. I added those indexes and the queries went from ~ 1200ms to 20ms, with the overall throughput for a feed dropping down to about 20% of its former time.

Validation

A third issue was forcing the database to run the wheel all the time. This wasn’t a major hourly thrashing like above, but a few feeds that were being polled every few minutes.

I got a sniff of this problem when I noticed the same set of feeds would keep appearing when I looked at the logs. After grepping, I realised they were not obeying the rule of waiting an hour to re-check, but were in fact taking their turn to poll the external feed, then jumping right back in line for another go.

 

This really wasn’t having much performance impact, because these feeds weren’t adding new items with each check (as the item keys were sound). But with more feeds like this, it could have an impact, and more to the point, being polled every few minutes is not good for my bandwidth or the people on the receiving end!

The cause turned out to be some trivial problems with feed items, which were being blocked by Rails’ validation when trying to save the items. Because scheduling info is &emdash; for convenience &emdash; tied to the items’ records, the scheduling info was being lost. A bit of overkill to isolate out the scheduling info at this stage, so I switched the validation to a before_save which did some cleansing to ensure the format is right.

Update: IO Rate

IO Chart

Another issue I still had to fix was the IO rate. You can see it above, not in the spikes – which reflect me making the fixes above – but in the small wave pattern on the left. Those are actually very high in absolute terms, at around 1K blocks per second being transferred between disk and memory. This is due to swap thrashing and required updates to my.cnf. In particular, decreasing key_buffer. Also, I decreased max_connections, such that (with key_buffer change), https://github.com/rackerhacker/MySQLTuner-perl was content with the memory required, and also increasing innodb_buffer_pool_size. I haven’t measured the effect of that yet, need to let it run for a while in order to get that.

I’m sure plenty of other optimisations are possible, but the good news is that IO Rate has gone right down to near-zero and swap rate likewise. So no more thrashing.

Sorting a Rails log file by SQL duration

Rails’ ActiveRecord logger writes log files like:

Post Load (735.8ms) SELECT posts.* FROM posts where post.title = 'foo'

You may want to know the longest SQL queries for performance optimsation purposes, and general troubleshooting. To list recent queries in order of duration, with longest queries shown last, use this:

head -10000 development.log | grep '([0-9.]+ms)' | sed 's/.(([[:digit:].]+)ms./1ms &/g' | sort -n

(The sed expression was a little more work than I’d bargained for as sed regular expressions are always lazy; even with GNU/Posix extensions, non-lazy just doesn’t exist.)

The Non-Visual Web

Looking Forward

7 years on from Ajax, we have our JavaScript-fu down and the APIs we could ever have dreamt of are baked into the desktop browsers of note. So what’s next for the web? The latest 5×5 podcast with Jason Grigsby is illuminating on future trends (as well as being a must-listen for all its practical advice):

Episode Homepage

Here I want to outline a few specific features which will challenge the boundaries of the web as we know it. And then I’ll explain how the web community can meet those challenges.

Tip of the Iceberg

In 2009, I gave a talk at London Web Standards on eight features of HTML5 you won’t see, features such as offline storage, geolocation, and history API.

That’s the tip of the iceberg of the tip of the iceberg. An example in this podcast is walking down the street and having your phone’s navigation system vibrate once if you should turn left, twice if you turn right. Another example mentioned in the podcast is a JavaScript vehicle API! webinos.vehicle.addEventListener (webinos.vehicle.NavigationEvent.DESTINATION_REACHED, handleDestinations, false); Checking fuel level, engine condition, etc. via a high-level API. And of course, there’s the whole medium of sound…this post was kicked off by a podcast after all!

The web has traditionally been a visual medium. As Jen Simmons observes here, even when it’s not visual, we use the word “Screen Reader” to emphasise its visual foundations. While it’s moved from text to images to fancy graphics and multimedia, those things are still visual elements on the page. Yet all of the above are not about elements on the page. That’s where technology is headed. So is it even sensible to handle these things through the web?

Model-View Separation

On a technical level, what makes the web incredibly powerful is the DOM concept. DOM is sync’d to UI. Update the DOM and it changes the user-interface. Change the UI and the DOM updates. The programmer doesn’t have to facilitate this bidirectional sync; it just happens.

Really, on a technical level, this is an incredibly important and overlooked aspect of HTML5. Too many HTML5 APIs are pure JavaScript functions and ignore the DOM altogether. For the web to thrive, vehicle APIs should not just be webinos.vehicle.addEventListener. The vehicle itself should be part of the DOM. If that sounds too domain-specific, that’s okay, because look at the work of Web Components. These guys are bringing about a world where anyone, or any community, can create a first-class <x-vehicle> element with its own look-and-feel.

Open Standards

Of course, at a higher level, the web is about open standards. That’s really what sets it apart from iOS, Android, and .Net. There’s no single vendor in charge. Something like the Java Virtual Machine comes close, but the web stack stands out as a more balanced control system. If there are to be standards for things like vehicle APIs, the web is attractive as the best stab at a neutral ground with real developer buy-in.

For this reason, the web can successfully move beyond the visual medium without losing what makes it the web in the first place.