Marching ants animated selection rectangle in CSS

Marching Ants is a common technique for showing a selection area in an image. The selection border has animated dashes to help distinguish between the selection and the image contents.

Marching ants in Photoshop

Marching ants in Photoshop

This is a CSS technique for a rectangular marching ants that has advantages over other common techniques:

  • The contents of the selected area don’t need to be opaque
  • Doesn’t require divs several divs for each edge of the animation

The CSS property border-image will do the heavy-lifting for us. Border-image is a strange beast because the name makes it sounds like an alternative to border-style (e.g. solid, dashed, dotted), but it’s really a 9-slice technique that even can fill the padding and content area with an image.

We’ll start with a 10px x 10px animated gif that is composed of nine tiles: 1×1 in the corners, 1×8 or 8×1 on the edges, and 8×8 in the center. The center tile is transparent so that we can let the area behind out element show through.



Our CSS will set border-image and specify that the slice is 1px from the edge and that the image should repeat instead of being stretched.

.selectionIndicator {
    border-image: image-url('ants.gif') 8 repeat repeat;
    -moz-border-image: image-url('ants.gif') 1 repeat repeat;
    -webkit-border-image: image-url('ants.gif') 1 repeat repeat;

The result is very close to what you see in Photoshop or other programs. It’s great for creating a cropping UI.

marching ants

Major caveat: border-image isn’t supported in IE <= 10.

How setTimeout’s timer clamping works

This is a fantastic post on the blink-dev discussion list by Chrome dev James Robinson describing how setTimeout’s timer clamping works. James argues that setTimeout(fn, 0) behaves exactly as setImmediate(fn) would except in excessively-nested timers.

Nearly everything I’ve read starts off with an incorrect idea about how timer clamping works or why it’s in place.  The way timer clamping works [1] is every task has an associated timer nesting level.  If the task originates from a setTimeout() or setInterval() call, the nesting level is one greater than the nesting level of the task that invoked setTimeout() or the task of the most recent iteration of that setInterval(), otherwise it’s zero.  The 4ms clamp only applies once the nesting level is 4 or higher.  Timers set within the context of an event handler, animation callback, or a timer that isn’t deeply nested are not subject to the clamping.  This detail hasn’t been reflected in the HTML spec until recently (and there’s an off-by-one error in it right now), but has been true in WebKit/Blink since 2006 [2] and in Gecko since 2009 [3].  The practical effect of this is that setTimeout(…, x) means exactly what you think it would even for x in [0, 4) so long as the nesting level isn’t too high.

With a better understanding of timer clamping, let’s consider the possible use cases for scheduling asynchronous work.  One is to time work relative to display updates.  Obviously requestAnimationFrame() is the right API to use for animations, but it’s also the right choice for one-off uses.  To perform work immediately before the next display – for example to batch up graphical updates as data is streamed in off the network – just make a one-off requestAnimationFrame() call.  To perform work immediately -after- a display, just call setTimeout() from inside the requestAnimationFrame() handler.  The nesting level is zero within a rAF() callback so the timeout parameter will not be clamped to 4.

Essential JavaScript links


This is a continuously updated list of JavaScript articles and resources that I recommend to other Amazon developers.

Essential CSS links


This is a continuously updated list of CSS articles that I recommend to other Amazon developers.

Getting started with Ruby on Rails


These are some of the tutorials and guides I’ve found most helpful while picking up Ruby on Rails 3.

Ruby language:

Installing Rails on Windows:

Best “my first app” walk-through:

Using “remote” to ajaxify links and forms:

“Unobtrusive JS” library that ships with Rails 3:

Use Twitter Bootstrap with Rails:

Get Chrome “Side Tabs” back (kind of)

Thousands of people, including myself, cried out in terror when Google removed the “Side Tabs” from Chrome. I tried for one month to settle into Firefox + Firebug + Tree Style Tabs as my main browser, but that combination is nowhere near is snappy as Chrome for my workload.

My workaround has been to use the most recent build of Chromium (Chrome’s open-source alter ego) that still contained the Side Tabs feature. Because there are no security updates available for this version, I use NoScript and whitelist scripting on sites as needed.

Chromium 15.0.862.0 – Windows:, Mac:

A major advantage of using Chromium instead of an old version of Chrome that has Side Tabs is that Chromium can be run side-by-side with the latest version of Chrome.

Understanding WebKit composite layers and iOS Safari performance


I’ve made a video showing how Webkit handles animating of CSS3 transforms very differently from animating of CSS position (left, top) or margin. The are several different conditions that will trigger the browser to use a “composite layer” which minimizes repaints and allows for hardware-accelerated composting. The benefits are especially dramatic in iOS Safari.

This Chromium document explaining composite layers says that the following conditions all trigger a separate composite layer:

  • Layer has 3D or perspective transform CSS properties
  • Layer is used by video element using accelerated video decoding
  • Layer is used by a canvas element with a 3D context
  • Layer uses a CSS animation for its opacity or uses an animated webkit transform
  • Layer has a descendant that has a compositing layer
  • Layer has a sibling with a lower z-index which has a compositing layer (in other words the layer is rendered on top of a composited layer)

See Rich Bradshaw’s awesome CSS3/Transforms page for some great examples.

HTML5 DOM and CSS3 performance


I ran across an awesome presentation by Paul Irish discussing DOM and CSS3 performance issues:

The video:
The slides:
The blog post:

The top tips that were new to me:

New Firebug feature: console.timeStamp


Firebug recently added an awesome new API; console.timeStamp lets you to create named “events” in the Net panel:

This technique requires manual instrumentation and isn’t as detailed as the Timeline panel in Chrome/Safari or a heavy-weight tool like dynaTrace, but it’s a nice, simple, uncluttered view compared to those other tools.

I used it today on a machine where I couldn’t install dynaTrace, I’ll surely be using it again. Unfortunately it isn’t supported in Firefox 3.6 and older.

Optimal Apache compression and expire settings

Below are compression and expiration settings for Apache that I’ve found optimal for StepMania.  You can paste them into your .htaccess file.

  • Don’t mess with PHP’s ob_gzhandler.  The settings below enable compression at the Apache module level, are the cleanest way to handle compression of non-PHP types, and are better performing to boot.
  • If your PHP application has a option for compression (it’ll be using ob_gzhander), turn that off in favor of these settings.
  • Web-Sniffer is useful for testing whether your compression and cache-control settings are taking effect. It’s also useful for troubleshooting HTTP error responses that Firefox and Chrome hide with pretty error pages.
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/x-httpd-php
AddOutputFilterByType DEFLATE application/x-httpd-fastphp
AddOutputFilterByType DEFLATE application/x-httpd-eruby

<IfModule mod_expires.c>
ExpiresActive On

ExpiresByType image/x-icon "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType audio/x-wav "access plus 1 month"
ExpiresByType audio/mpeg "access plus 1 month"
ExpiresByType video/mpeg "access plus 1 month"
ExpiresByType video/mp4 "access plus 1 month"
ExpiresByType video/quicktime "access plus 1 month"
ExpiresByType video/x-ms-wmv "access plus 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"

ExpiresByType text/css "access plus 1 hour"
ExpiresByType text/javascript "access plus 1 hour"