Christian Heilmann

Author Archive

Five things you can do to make HTML5 perform better

Friday, January 25th, 2013

During the last few weeks we were busy helping developers to convert their HTML5 apps from platforms like WebOS and ChromeOS to FirefoxOS and the target hardware this operation system is right now aiming for. As these are slow mobiles, we found that quite some tweaking had to be done. The reason was in most cases libraries using outdated ways to animate and position things on the screen. These old ways of working are needed to support legacy browsers and in a lot of cases are not needed as these legacy browsers will never see the apps in the first place.

Speeding Through The Klongs

Aside: I will cover a lot of this in my keynote at the jQuery Europe conference called “Helping or hurting?”.

Tip 1: Use CSS animations/transitions

Instead of using your library’s animate() which – for now – uses many badly performing technologies (setTimeout, top/left positioning) use CSS animations. In many cases actually Transitions are enough. The reason is that browsers optimise them for you and hardware accelerate them. Another benefit is that the animation is defined in the CSS with the rest of the look and feel and in an agreed standard syntax. CSS animations give you massively granular control over the effect using keyframes and you can even listen to events that happen during the animation. You can easily trigger the animations in CSS with hover, focus or target selectors or by dynamically adding and removing classes to a parent element. If you want to create animations on the fly or modify them in JavaScript, James Long has written a simple library for that called CSS-animations.js

Tip 2: Use requestAnimationFrame() instead of setInterval()

This has been explained many times – a setInterval() call runs code at an assumed frames per second speed that may or may not be possible. It tells the browser to render results even whilst the browser is currently not drawing as the video hardware is not in the next display cycle. On the other hand, requestAnimationFrame() will wait till the browser is ready and only send your changes when they will result in a visual display. Another great side-effect for using rAF is that animations don’t happen when the tab is inactive – that way your app is not responsible for hammering the CPU/GPU and sucking battery whilst it doesn’t do anything for the end user.

Tip 3: Use CSS transforms instead of position: absolute and top/left

Again the reason is hardware acceleration. CSS transforms using translate(x, y) run on the GPU whereas positioning absolutely and using top and left hammer the main processor. This is worsened by not rounding your pixel positioning. Using transforms also means that you have a much bigger arsenal at your proposal. Rotation and 3D transformations just mean adding to the transform string. With top/left you need to calculate them yourself and mess around with depth of field. Paul Irish has an in-depth analysis of the benefits of translate() from a performance point of view. In general, however, you have the same benefits you get from using CSS animations: you use the right tool for the job and leave the optimisation to the browser. You also use an easily extensible way of positioning elements – something that needs a lot of extra code if you simulate translation with top and left positioning. Another benefit is that the technique is the same in Canvas.

Tip 4: Make events immediate

As old-school, accessibility aware web developers we love click events as they also come with the added benefit of supporting keyboard input. On mobile devices these are too slow though and you should use touchstart and touchend instead. The reason is that these don’t have a delay that makes the interaction with the app appear sluggish. If you test for touch support first, you don’t sacrifice accessibility either. The Financial Times use a library called fastclick for that purpose, which is available for you to use.

Tip 5: Keep it simple and re-use as much as you can

One big performance issue we found in HTML5 apps was that moving lots of DOM elements around makes everything sluggish – especially when they feature lots of gradients and drop shadows. Simplyfying your look and feel and moving a proxy element around when you drag and drop helps a lot.

When you have for example a long list of elements (let’s say Tweets) don’t move them all but only keep the ones visible in the current screen and a few before and after live and hide or remove the others. Keeping the data in a JavaScript object instead of reading/writing to the DOM showed massive improvements. Think of the display as a presentation of your data rather than the data itself. That doesn’t mean you can not use straight HTML as the source. Just read it once and then scroll 10 elements changing the content of the first and last accordingly to your position in the results list instead of moving 100 elements that aren’t visible. The same trick applies in games to sprites – if they aren’t in the current screen there is no need to poll them. Instead re-use elements that scroll off screen as new ones coming in.

More reading:

(Includes videos and all)

One step ahead and two steps back: are apps really the future?

Tuesday, January 15th, 2013

My esteemed colleague Luke Crouch put together an interesting piece entitled Packaged HTML5 Apps – are we emulating failure which resonates quite well with me. In it he describes the process of scanning a QR code on a phone to check into a restaurant with Facebook. This right now involves installing a QR code reader, the Facebook app and many in-between steps that can not be in the best interest of the restaurant owner and requires a lot of patience from the user.

Software!

My reservations towards QR codes aside (hey, with NFC, this would be “tap your phone here to check in” – you hear that, Apple?) I think Luke points to a much bigger topic here that very much annoys me: we are stalling, if not moving backwards in the evolution of content delivery.

Let’s reduce the use case to the bare minimum here: an end user wants to get some content. This could be music, video, photos, a book, a map with instructions or a game to play. It all is data, zeroes and ones that if arranged in the right format make up the thing I want. Our job as the data providers should be not to throw as many barriers in the way of the consumer to reach that – our job should be to make this dead easy.

Whenever people say that “users want apps” then what they really say is “people want a thing that uses their hardware to the best of its abilities and be able to find that in a simple way”. Doesn’t roll as well of the tongue and sucks as a rallying cry, but describes the thing much better. I remember the days before the Internet, when software came on floppy disks in the mail and had to be installed and the third install disk had a read/write error so you had to call the company or go back to the shop to get a replacement. I also remember having to install a tool to cut up images for table layouts or to plan a route for my holidays. I also remember buying games and being told my computer is not good enough – always the sound card, which wasn’t as “Soundblaster compatible” as it pretended to be.

This seems ridiculous now and we laugh at the idea of not being able to just type, “Hackney, London” into the search box of our phone or browser and get a map back. Yet this is exactly the world we seem to crave to go back to when we say that apps are a much better experience and the future of our jobs and what people want.

What we do by praising apps and their simplicity is reward companies for locking users out – demanding the real Soundblasters so to say. We claim that app stores are easier for recovery and yet these companies pay a lot of money to advertise their apps and games on TV, in newspapers and in banner ads on the web. App stores are not easier. They do not scale. I wait for the day – which will come very soon indeed – where you can buy better placement in app stores, much like you could in “price comparison web sites” and search results.

If you took the app store model and compare it with something that happened to the web then app stores are the Yahoo directory which got killed by search with Google being the big innovator. We realised that it is far too much work to curate and edit a list of web resources when the format of them would allow publishers to promote their content and make the amount of people clicking it determine what gets shown first.

If you care to remember, we already had a failed attempt at app stores. Tucows, Download.com, Freshmeat.net and others tried the same for Desktop apps and nobody cares about them right now any longer and they fall into disarray and become a spammer’s heaven.

The focus on apps right now and the repeated myth that they are a much better experience for end users than the web are based on man-made barriers for the web:

  • Apps have much more access to the device’s hardware
  • App stores are promoted with the sale of the hardware

For everyone proclaiming that app stores are the better way to distribute apps I propose to check out the hundreds of empty app stores mobile service providers set up or the ones of hardware that is less successful than Android or iPhone. Wastelands full of frivolous apps and overpriced quickly converted and packaged old titles that were a success on other platforms.

This is not about what users want – this is about what the industry and distributors are used to and don’t want to change. A packaged app can be much easier priced and its distribution planned and tracked than a web app. Much like physical CDs and DVDs and books still have quite some time to vanish, the packaged app to me is the last of the dinosaurs when physical distribution was all you could do.

A lot needs to change till we realise that we have a wonderful way to distribute media called the Internet. Media that can stay fresh, can get updated when we need and discarded when we don’t want it any longer without having to download lots and lots of data each time.

Most of it is based on business models that are not flexible and see full control over the distribution as the only means of making money. Some of it is psychological. A neatly packaged app you need to install and uninstall seems like something more solid than a web app. It seems more trustworthy, whilst it also can cause much more damage. It is the “20% more” on a fizzy drink can you never knew you missed so much.

I am very afraid that if we do not stand our ground now and point out that apps are a distribution model of the past and not the future we’ll repeat the same mistake we did with Application directories in the past. Of course you can now list 23123 reasons why apps are better than web apps on mobile devices, but I dare you to find one that is not based on the device or OS vendor blocking access to functionality for non-native code. We praise a model of distribution for its simplicity based on lockout.

The argument you hear about this is that end users don’t care, they just want their apps. The fact here is that they don’t get told about alternatives. Again it is all marketing – damn good marketing, admittedly – but many demands from our end users come from seeing something and wanting it rather than needing it in the first place.

An open letter to Sony: your Ultraviolet Film service teaches people to trust malware

Monday, January 14th, 2013

Online piracy is a terrible thing. It is illegal. It does kill jobs and it does prevent products from being released and artists from becoming famous and being able to make a living. This is the truth, although when you hear it from labels and the film industry and seeing what is being promoted and sold it does lose some of its credibility.

Nevertheless, online piracy is a criminal actcivil matter (explanation) and should not be the norm. The best way to fight online piracy is to make it redundant. Purchasing a media and being able to watch it when I want as long as I want and as often as I want should be dead simple. This is what happened in the past when I bought physical media in the time of CDs and Vinyls and VHS tapes.

Even then the film industry made it hard for me to enjoy the things I bought. There were differences in TV formats (NTSC vs. PAL and the wonderful milky display of movies that were badly transferred) and different releases of vinyls in different countries had different tracks. Also, I was punished when I lived outside the US as I had to wait for half a year for a movie my friends on BBSes and later on in Newsgroups and IRC talked about.

I have not bought a CD in a while and I have not downloaded any pirated MP3 in years because of Spotify. I pay my monthly fee and I happily listen to as much music as I want. I download the music to play on my iPod in the gym offline and all is good. I pay, the artists get money, the labels get money, Spotify gets money and I can enjoy my stuff.

Now, on a flight lately I watched Total Recall, the remake (ironically released by “Original Film”) and I was almost ready to watch it on iTunes and buy it there. As it is a cool CGI movie, I thought I get the HD version and – if possible – check it on my Retina MBP. Then I thought that £13.99 is a bit much and as I want to see it next time I am in Sweden with my partner, I want to get it on the computer I take with me on Travels. Google Play was out of the question as it doesn’t let me access my UK account when I am out of the country.

So today I went to the shop and saw the DVD of Total Recall for £15 so I thought, OK, let’s buy a physical DVD. I could do it ironically and be a hipster about it. My plan was to rip the DVD to my computer and watch it with my partner whilst keeping the physical thing at home as none of my laptops have drives any longer.

But, oh wonder! You thought of this and gave me the awesome “Ultra Violet” film collection option. So I could go and get a digital copy of the movie I just bought for my convenience. Amazing! I was ready to download the hell out of this MP4 you’d offer me in a simple download, and went online to get the movie.

Now, the first thing I was asked to do was to fill out a form to sign up for your library. This form didn’t understand my perfectly valid 5 digit UK postcode and told me I need a 6 digit one – how dare I have a working address? It also asked me to have a password in a certain format after I entered mine twice instead of telling me after I entered it once that this will not do in your world of security.

OK, I signed up, giving you a wrong postcode to get in and a wrong birthdate as it is none of your business when I was born.

I then got to the download page which asked me to install Silverlight. Why is this not on the DVD pack? A simple “requires Microsoft Silverlight” would have told me that there is pain ahead.

I downloaded the Silverlight linked from the Download page and installed it. I restarted my Firefox and went to the download page and was asked to install it again. What? OK, I went to Safari, logged in and the login page told me my Silverlight is the wrong version. I installed the one not linked from your “download silverlight” button and hooray, I could now install the Sony Pictures Download Manager which is a secure and trustworthy and wonderful way of downloading movies I paid for. That is if it were a verified program file. As it was my browser told me that the publisher of this file is not verified:

unverified app

Is it yours? Is it malware? Should I be concerned that you tell me as Mac user that I should double-click the icon of the download manager once it is on my Desktop which it never will be? Should I install the .app file that my operating system tells me I downloaded from the internet and could be anything?

unknown application

I did, this is how much I am happy to meet you halfway here. So I installed the download manager and started the download. And I felt the laptop giving off a warm glow when it started, seeing that your download manager sucks up 17% of this very, very beefy computer whilst downloading the movie.

activity detected

I can only imagine what watching the movie will be like.

So here is my advise: hire a few researchers to download and watch pirated movies. Learn from the way pirates distribute and make things available and then make it easier. Today you lost me as a customer. This is the first and last movie I bought from Sony Pictures as your interest is neither safety nor my enjoyment.

What you do right now is:

  • Make legal customers go through a broken sign-up process with strange rules
  • Make legal customers install strange software without verified publishers (with one download linking to the wrong version)
  • Slow down my computer unnecessarily with a heavy download client whilst I already have iTunes and Google Play

You know what that is? The same thing shady download locker sites do to lure people into downloading malware after entering a captcha most likely used to get into another site. Instead of making it easy for end users who just want to legally watch a movie you teach them that nothing on the web can be trusted, so we might as well install whatever promises us movies to watch. As a security conscious person, I consider this bordering on aiding the criminals you so loudly proclaim to fight.

Let me repeat: you only fight piracy by making it unnecessary. All the money you spend on building overly complex and ridiculously locked-in systems like that is what kills movies and hurts artists. Learn from the people who attack your business and you will come out a winner.

A total web recall?

Saturday, January 5th, 2013

I just spent 10 hours on a plane, watching movies and some presentations and thinking about the web, or, to be more precise, our work environment as web developers.

Two things triggered this: watching the remake of Total Recall and watching the first two talks of the Full Frontal conference.

Let’s start with the talks. A good conference organiser knows that opening with a controversial topic and allowing an immediate rebuttal brings good drama and gets the audience thinking. In this respect Remy Sharp landed a bulls-eye with last year’s Full Frontal conference.

The first talk was James Pearce’s All you need is body/

James raises a lot of great points and the one that stuck the most with me is that we are getting complacent about the idea that the web always wins and that the technologies and ideas we used in the past will still be the most important ones in the future. The structure of the presentation is incredibly well done: James starts with advocating a controversial approach to web development that a lot of new developers very much like to embrace and ends with an appeal to reconsider our dogmas when it comes to talking about web standards and development.

As a counterpoint, John Alsopp’s In Defense of HTML explains that using the web stack of HTML, CSS and JavaScript for what they are good at means using a stable set of technologies instead of re-inventing what we have just because we can and because we like to inject idioms of other platforms into the web. It also contains more or less the same passionate appeal to make the web more mature by using what worked but being open to new ideas and needs.

Mike Davies wrote a long and detailed article about these two talks, taking the stand that the web indeed is the right way to go and full reliance on JavaScript for everything is dangerous at best. As he put it, native apps need the web, not the other way around.

Whilst he makes some excellent points, I think that the subject matter is more subtle. As Nicholas Zakas explains being right doesn’t always matter and the how of why the web works is not the main issue here. It is about demands of the market and ideas of the next generation of developers.

Schwarzenegger in Total Recall

Which brings me to the subject of Total Recall. When the original movie came out it was amazing. The make-up and special effects were great and the story’s twists and turns kept it interesting till the end (despite the movie only being very, and I say very, very loosely based on the original “we can remember it for you wholesale” short story). The movie became a classic and people who grew up with it love to defend it as great even though watching it now makes it look rather camp and dated.

Collin Farrel in Total Recall

Fast forward to now where a remake of Total Recall was produced that is visually stunning and less “out there” sci-fi than the original. The reviews of the remake read a lot as “lots of special effects, shootouts and none of the original story”. The movie is very much measured in comparison with the old one. And, more importantly, not with how the movie holds up in nowaday’s competition, but in a more idealised version we have made up based on the great memories we have of the old one.

This is what happens with the web. New developers do not violate best practices of the past because they want to. They violate them because they are not sexy or interesting.

What got us excited in the past seems outdated now and the new and shiny and fast-paced is much more appealing. Talking about build scripts, packaging and making CSS easier by pre-processing it is both closer to what we learn in university and sounds more challenging as an engineering task than separating look and feel from behaviour or using the right semantic HTML that browsers don’t do anything with in the first place.

Web Development is not the disruptive, sexy thing any longer it was in the past. We scoffed at desktop applications and their inflexibility and showed the web can do a lot better, faster and in a much more flexible manner. We hacked and did very random things to browsers to make ends meet. A lot of CSS hacks and JavaScript patches seem incredibly painful and odd now, but were needed back then. Nowadays, as the web is more ubiquitous and browsers offer much more than they did in the past this is not a challenge that is interesting and people are looking for building blocks rather than starting from scratch.

There is a massive demand for engineers out there, and they are expected to hit the ground running. This is why we should not be surprised that using existing libraries and frameworks is what engineers want to do instead of learning the trade from scratch.

Instead of advocating a very idealised and romantic version of what the web is and how to build for it it might just be the time to focus more on the building blocks people use and pool our knowledge and resources to make those better and result in clean code we all can enjoy. This is a big challenge, but I think it makes more sense than condemning what is new as shiny and short-lived considering that a lot we did in the past was exactly that. With more advanced technology we have a chance to make more complex and impressive looking mistakes. Maybe we are doomed to repeat this over and over again until we reach a level of understanding.

Conditional loading of resources with mediaqueries

Wednesday, December 19th, 2012

Here is a quick idea about making mediaqueries not only apply styles according to certain criteria being met, but also loading the resources needed on demand. You can check a quick and dirty screencast with the idea or just read on.

Mediaqueries are very, very useful things. They allow us to react to the screen size and orientation and even resolution of the device our apps and sites are shown in. That is in and of itself nothing new – in the past we just used JavaScript to read attributes like window.innerWidth and reacted accordingly but with mediaqueries we can do all of this in plain CSS and can add several conditions inside a single style sheet.

In addition to the @media selectors in a style sheet we can also add a media attribute to elements and make them dependent on the query. So for example if we want to apply a certain style sheet only when the screen size is larger than 600 pixels we can do this in HTML:

<link rel="stylesheet" 
      media="screen and (min-width: 601px)" 
      href="large.css">

Handy isn’t it? And as we applied the mediaquery we only request this file when and if it is needed which means we even save on an HTTP request and don’t suffer the latency issues connected with loading a file over the wire (or over a 3G or EDGE connection). Especially with movies and source elements this can save us a lot of time and traffic. Sadly, though, that is not the case.

Load all the things – even when they don’t apply

Let’s take this HTML document:

<!DOCTYPE HTML>
<html lang="en-US">
<head>
  <meta charset="UTF-8">
  <style type="text/css">
    body { font-family: Helvetica, Arial, sans-serif; }
    p    { font-size: 12px; }
  </style>
  <link rel="stylesheet"
        media="screen and (min-width: 600px)" 
        href="small.css">
  <link rel="stylesheet"
        media="screen and (min-width: 4000px)" 
        href="big.css">
  <title>CSS files with media queries</title>
</head>
<body>
<p>Testing media attributes</p>
</body>
</html>

If your screen is less than 600 pixels wide the paragraph should be 12px in size, over 600 pixels it is 20px (as defined in small.css) and on a screen more than 4000 pixels wide (not likely, right?) it should be 200px (as defined in big.css).

That works. So we really do not need to load big.css, right? Sadly enough though all the browsers I tested in do. This seems wasteful but is based on how browsers worked in the past and – I assume – done to make rendering happen as early as possible. Try it out with your devtools of choice open.

Chrome loading both CSS files
Firefox loading both CSS files

Update: As Ilya Grigorik points out in “Debunking Responsive CSS Performance Myths” this behaviour is by design. Make sure to read the comments on this post. However, stay with me as I think we should have a handle on loading all kind of resources on demand, which will be shown later.

I am quite sure that CSS preprocessors like SASS and LESS can help with that, but I was wondering how we could extend this idea. How can you not only apply styles to elements that match a certain query, but how can you load them only when and if they are applied? The answer – as always – is JavaScript.

Matchmedia to the rescue

Mediaqueries are not only applicable to CSS, they are also available in JavaScript. You can even have events firing when they are applied which gives you a much more granular control. If you want a good overview of the JavaScript equivalent of @media or the media attribute, this article introducing matchmedia is a good start.

Using matchmedia you can execute blocks of JavaScript only when a certain mediaquery condition is met. This means you could just write out the CSS when and if the query is true:

if (window.matchMedia('screen and (min-width: 600px)')){
  document.write('<link rel="stylesheet" 
                  href="small.css">');
}

Of course, that would make you a terrible person, as document.write() is known to kill cute kittens from a distance of 20 feet. So let’s be more clever about this.

Instead of applying the CSS with a link element with a href which causes the undesired loading we dig into the toolbox of HTML5 and use data attributes instead. Anything we want dependent on the query, gets a data- prefix:

<link rel="stylesheet" class="mediaquerydependent" 
      data-media="screen and (min-width: 600px)" 
      data-href="green.css">
<link rel="stylesheet" class="mediaquerydependent" 
      data-media="screen and (min-width: 4000px)" 
      data-href="blue.css">

We also add a class of mediaquerydependent to give us a hook for JavaScript to do its magic. As I wanted to go further with this and not only load CSS but anything that points to a resource, we can do the same for an image, for example:

<img data-src="http://placekitten.com/500/500" 
     data-alt="kitten" 
     class="mediaquerydependent" 
     data-media="screen and (min-width: 600px)">

All that is missing then is a small JavaScript to loop through all the elements we want to change, evaluate their mediaqueries and change the data- prefixed attributes back to real ones. This is that script:

(function(){
  var queries = document.
                querySelectorAll('.mediaquerydependent'),
      all = queries.length,
      cur = null,
      attr = null;
  while (all--) {
    cur = queries[all];
    if (cur.dataset.media &&
        window.matchMedia(cur.dataset.media).matches) {
      for (attr in cur.dataset) {
        if (attr !== 'media') {
          cur.setAttribute(attr, cur.dataset[attr]);
        }
      }
    }
  }
}());

Here is what it does:

  1. We use querySelectorAll to get all the elements that need the mediaquery check and loop over them (using a reverse while loop).
  2. We test if the element has a data-media property and if the query defined in it is true
  3. We then loop through all data-prefixed attributes and add a non-prefixed attribute with its value (omitting the media one)

In other words, if the condition of a minimum width of 600 pixels is met our image example will become:

<img data-src="http://placekitten.com/500/500" 
     data-alt="kitten" 
     class="mediaquerydependent" 
     data-media="screen and (min-width: 600px)">
     src="http://placekitten.com/500/500" 
     alt="kitten">

This will make the browser load the image and apply the alternative text.

But, what if JavaScript is not available?

When JavaScript is not available you have no problem either. As you are already in a fairyland, just ask a wandering magician on his unicorn to help you out.

Seriously though, you can of course provide presets that are available should the script fail. Just add the href of a fallback which will always be loaded and replaced only when needed.

<link rel="stylesheet" class="mediaquerydependent" 
      href="standard.css"
      data-media="screen and (min-width: 600px)" 
      data-href="green.css">

This will load standard.css in any case and replace it with green.css when the screen is more than 600 pixels wide.

Right now, this script only runs on first load of the page, but you could easily run it on window resize, too. As said, there are even events that get fired with matchmedia but pending testing according to the original article this is still broken in iOS, so I wanted to keep it safe. After all mediaqueries are there to give the user what they can consume on a certain device – the use case of resizing a window to see changes is more of a developer thing.

This could be used to conditionally load high resolution images, couldn’t it? You can grab the code on GitHub and see it in action here.