andrew.hedges.name / blog

Stupid WebKit Tricks

July 19, 2009, 7:19 pm · 1 comment · Filed under: Apple, JavaScript, Web Development

With apologies to David Letterman’s Stupid Human Tricks segment, I presented a session at Barcamp Auckland (BCA3) on some WebKit-specific features you can leverage in web applications for iPhone, Android, and the Palm Pre. This is my synopsis, plus a bonus trick I didn’t present at the (un)conference!

WebKit is Apple’s open source HTML rendering engine. It is used to power several browsers and even a software platform, including Safari, Mobile Safari, Google Chrome, and the Palm Pre operating system. To see the following examples in action, you’ll need one of them.

Here are my presentation notes.

At BCA3, we were allotted just 30 minutes to present. That, plus the session I attended right before mine went a little over. After getting set up, I had approximately 23 minutes of talk time (you know, kind of like an iPhone).

I quickly ran through examples of CSS gradients, scaling, moving, & fading elements, flipping stuff over (best viewed on an iPhone), and finally CSS masks. It was a whirlwind, but I hope it gave a taste of what WebKit (and, hopefully soon, other browsers) can do. Best of all, most of it is hardware accelerated on the iPhone.

How it works

The basic pattern for all of the above mentioned animations is the following:

  1. In CSS, tell WebKit that, for an element or group of elements, when a specific property changes, it should transition from one state to another over a set duration and using a particular timing function (also called an “easing algorithm”).
  2. Also in CSS, set the initial state of the element and the state to which the element is to transition.
  3. Either in CSS (using the :hover pseudo-class) or in JavaScript (by toggling a class name), initiate the transition by setting a new state for the property in question.

Here’s a simple example. First, the CSS:

#mydiv {
  -webkit-transition-property: opacity;
  -webkit-transition-duration: 1500ms;
  -webkit-transition-timing-function: ease;
  opacity: 1.0;
}

#mydiv.faded {
  opacity: 0.0;
}

The CSS just implements steps 1 & 2 above.

Next, the JavaScript:

document
  .getElementById('mydiv')
  .addEventListener('click', function () {
  this.className = 'faded' === this.className ? '' : 'faded';
}, false);

The above code sets up our DIV to listen for click events. When you click the DIV, it checks whether the class name is ‘faded’. If it is, it sets the class name to nothing. If it’s not, it sets it to ‘faded’. Try it for yourself:

Click me!

Pretty cool, eh? Read everything there is to know about this stuff in the official documentation from Apple.

Bonus!

As promised, here is a little bonus technique: key-framed animations. This is sweet. First, try the example below:

Click me!

In a WebKit-based browser, you should see the DIV grow to about twice it’s “normal” size, then pop back to actual size. The code for this animation is only a little more complex than the previous example, and it builds on what we already know.

Here’s the CSS:

@-webkit-keyframes pop {
  0%   { -webkit-transform: scale(0.5); }
  70%  { -webkit-transform: scale(2.0); }
  100% { -webkit-transform: scale(1.0); }
}
#popper {
  -webkit-transform: scale(0.5);
}
#popper.popping {
  -webkit-transform: scale(1.0);
  -webkit-animation-name: pop;
  -webkit-animation-duration: 250ms;
  -webkit-animation-timing-function: ease-in-out;
}

In the CSS, the first thing we’re doing is creating an animation (@-webkit-keyframes) with the name “pop”. Our animation has three states: 0%, our starting state; 70%, the state we want our element in when 70% of the duration has elapsed; and, 100%, our ending state.

Next, we set the initial state for the element to be scaled down to 50% of “actual” size (-webkit-transform: scale(0.5);) and declare that when the class “popping” is added to the element we will use the “pop” animation sequence to transition to our ending state (-webkit-transform: scale(1.0);) over 250 milliseconds and using the ease-in-out timing function.

The JavaScript is essentially the same as before. Only the DIV ID and class names have been changed.

document
  .getElementById('popper')
  .addEventListener('click', function () {
  this.className = 'popping' === this.className ? '' : 'popping';
}, false);

So, that’s it. Pretty cool what WebKit can do. I mentioned earlier that other browsers will hopefully implement these techniques as well. Apple have proposed all of the techniques I’ve used in my examples to the appropriate standards bodies. My guess is Mozilla and Opera will get on board relatively quickly. When The Beast decides to grow a round tuit is anyone’s guess. IE12, perhaps?


Short URL to this article:

1 comment


Just ran into a bug in WebKit animations where timing functions are not applied correctly in Mobile Safari when only 2 keyframes are specified. Here is a test case. Works great on the desktop, but you should see non-linear easing for all elements on iPhone OS 3.0.

After puzzling over it a bit with @girlie_mac, @smfr, an Apple WebKit engineer, confirmed this was an actual bug. The workaround is to include a 3rd keyframe. So, instead of my original code, do something like the following:

@-webkit-keyframes spin {
    from {
        -webkit-transform: rotate(0deg);
        -webkit-animation-timing-function: linear;
    }
    50% {
        -webkit-transform: rotate(180deg);
        -webkit-animation-timing-function: linear;
    }
    to   {
        -webkit-transform: rotate(360deg);
    }
}

.loader {
    -webkit-animation-name: spin;
    -webkit-animation-duration: 360ms;
    -webkit-animation-iteration-count: infinite;
}

Say something!

Remember me?

Get your photo next to your comment by registering a Gravatar.

If you spam for a living, please be aware that all links in comments will be tagged with rel="nofollow". This means spamming my blog will not help your Google PageRank. Spam kills. Just say no.