Marching ants in CSS

A couple of days ago I noticed that Goooogle uses a marching ants effect on their new mini-calendar event view. It highlights the target time frame for the event you’re editing, and it indicates a draggable and expandable area. (It’s probably been there for ages, but I’m slow like that.)

Marching ants effect in Google Calendar.

Being a colossal geek, the first thing I did was run up Firebug to see how they’re doing it, because there is no “border-style: marchingants” in CSS. It looks like Google is doing it with JavaScript. The area in question is bounded by four long but thin div elements (tall and narrow for the vertical borders, short and wide for the horizontal borders).

<div class="sc-ants sc-ants-top"></div>
<div class="sc-ants sc-ants-left"></div>
<div class="sc-ants sc-ants-right"></div>
...
<div class="sc-ants sc-ants-bottom"></div>

These divs sit inside a parent container with overflow:hidden, so you only see a small slice of their full extent. The border divs themselves have size, but no content. Their entire area is taken up by a 2px-wide dashed border:

.sc-ants-top  {
    border-top:2px dashed #6688EE;
    height:0;
    top:0;
    width:10000px;
}

Finally, there is a JavaScript timer that changes the position of these divs, moving them a pixel at a time to achieve the marching ants effect.

Even in native applications, marching ants are not all that common, and I think this is the first time I've seen them in a web application. Given that draggable/resizeable areas are also not all that common in web apps, I think it's a clever and elegant way of highlighting that there is something different an unusual about that area.

On the other hand, I'm not mad keen on keeping JavaScript timers running just to keep screen elements in their appropriate position, so I wondered if there was a way of doing this with just CSS instead. And of course there is: have a look at the demo page.

I started with a block of HTML in the standard module format, because it's a good basis for isolating areas of content. The div.bd holds the actual content to be highlighted, and the other parts of the module are used for creating the borders, as follows:

  • The outermost div is given a left-hand pseudo-border by using a background image with repeat-y only, positioned slightly to the left of the left edge, so that only the rightmost two pixels of the image are visible.
  • Likewise, the .inner container is given a top pseudo-border.
  • The .hd block makes the right-hand border. It is positioned absolutely on the right edge of the module, 2px wide and 100% tall, and has a background image with repeat-y.
  • The .ft block makes the bottom border. It is 2px tall and 100% wide, and also has a background image.

Here's how it looks inline:

Marching ants!

The actual animation is achieved with a couple of old-skool animated GIFs, ants-horizontal.gif and ants-vertical.gif. The horizontal GIF contains two checkerboard patterns, one moving to the left, and one moving to the right; the vertical GIF has the checkerboard patterns moving up and down. Each border only uses half of one of the GIFs, which is you only need two images rather than four.

If you are content with the border being a single pixel thick, and the ants flowing from one corner to the opposite, then you could get away with just one animated GIF — see the wikipedia article on marching ants for an illustration. Personally, I prefer the animation to flow round the border in a continuous pattern.

Of course, this is far from the only way you could implement the marching ants effect. You could use webkit's CSS animations instead. The demo page includes an example of how to do this as well. The basic principles are exactly the same: set up a standard module, and use GIF images to form the necessary borders. But instead of using animated GIFs, you can use just a single static checkerboard image, and use up/down/left/right animations to move around the background instead:

.marchingants {
	-webkit-animation-name: march-up;
	-webkit-animation-duration: 0.3s;
	-webkit-animation-iteration-count: infinite;
	-webkit-animation-timing-function: linear;
}
@-webkit-keyframes march-up {
	from {
		background-position-y: 8px;
	}
	to {
		background-position-y: 0;
	}
}

One neat thing about the CSS animation version is that you can vary the speed of the animation without having to edit the GIF file. The obvious drawback is that it (for now) only webkit browsers support CSS animations. But given how easy it is to implement this in a cross-browser compatible manner, right now I'd suggest sticking to the animated GIF version.

Second-hand 80s

Alex and Fiona were both singing Harold Faltermeyer’s Axel F in in their shower and bath this evening. The funny thing about this is that they had probably never heard the original. They picked it up from watching Monsters vs. Aliens on DVD, in which there is a scene where the President of the USA (Stephen Colbert) tries to make contact with the aliens by playing the five note message from Close Encounters of the Third Kind. He doesn’t quite manage it, so he breaks into a spontaneous rendition of Axel F instead.

Although I listen to a lot of music when I’m alone, we don’t listen to much in the family spaces around the house. The kids both have stereos on their rooms, but they don’t listen to the radio on their own. Yet they are constantly exposed to musical and cultural references in the films and TV they watch, and the games they play. I always find it fun to see how they react when I connect something they’ve just heard or seen to the “original” from twenty years ago (which itself generally has roots in a still earlier era).

In this case, their interest turned into dance. While they were still getting clean and ready for bed, I burned a selection of 80s hits onto CDs for them. The playlist opens with Axel F, of course, but there’s some Michael Jackson on there, a bit of ABC, a bit of Human League, a bit of Boomtown Rats. They eagerly stuck the discs into their players, and just minutes later Alex was breakdancing to Axel F, and Fiona had put together a short ballet to the sounds of “Girls Just Wanna Have Fun.” I was completely enchanted.

Music is so important to me that I’m always delighted whenever they take any kind of interest in it. I need to work on getting more of it into their lives.

Grandma

After a long, full, and happy life, my grandmother Florence McLean died peacefully this morning.

Grandma McLean with Alex, 29 April 2001

We miss her a lot.

Leaving Facebook

I don’t make a secret of the fact that I don’t like Facebook. Where others find it playful, I find it intrusive and annoyingly attention-seeking. I don’t like its attitudes towards content ownership and privacy. I particularly don’t like its sense of self-importance, and the greedy way it tries to assume control of my social graph. It’s not that I don’t want to connect with my friends over social networks, but I want it to be on my terms, not theirs.

Additionally, whenever you’re dealing with a company that handles anything of value to you (with banks it’s money, with Facebook and Google it’s personal data), you have to weigh up the trust you have to place in them against the benefit you expect to receive. Google passes that test for me (for now), but I don’t trust Facebook not to try and screw me over.

What happens when you try to leave Facebook is emblematic of this. Here’s the page you get when you try to disable your account:

Facebook's disable account page

Asking me to confirm that I want to deactivate my account is appropriate. Using my social connections in a clear attempt to trigger an emotional response that will keep me on the service is absolutely not.

“Your 32 friends will no longer be able to keep in touch with you” is nonsense. I assume that since they know how to use a web browser, they’re reasonably familiar with a computer, and probably have an email account they can use to reach me.

Below that, they display a random selection of my Facebook contacts with above each one the text “XXX will miss you”. Not only are these statements factually incorrect — they won’t miss me because I never used Facebook to communicate with them in the first place — but Facebook is almost literally putting words in the mouths of these people. Facebook has not asked them if they will miss me; it is using them as sock puppets to push its own message, which is “don’t go.” By using the emotional “miss you” phrase, Facebook is using its knowledge of my social connections to make me feel bad about leaving.

They are abusing my social graph for their own ends. It’s manipulative, unethical, and downright slimy.

Furthermore, if they are using my contacts to try to make me stay, it follows that if my friends have tried to leave Facebook, then Facebook may have used me, or at least my photo, to try to make them stay — something that I myself would absolutely not do.

Goodbye, Facebook. Martin will not miss you.

On refusing to be terrorized

When it comes to security, I’m firmly in Bruce Schneier’s “refuse to be terrorized” camp. I’m sick of the “we must do something” panic reaction that follows even minimal terrorist threats, and the security theatre it leads to. It’s not about the inconvenience it causes me and other passengers; it’s not even about the ridiculous costs that have to be borne by companies and taxpayers in order to implement measures that will do nothing to prevent a determined terrorist carrying out a attack — all they have to do, after all, is change their target.

Bruce Schneier:

It’s magical thinking: If we defend against what the terrorists did last time, we’ll somehow defend against what they do next time. Of course this doesn’t work. We take away guns and bombs, so the terrorists use box cutters. We take away box cutters and corkscrews, and the terrorists hide explosives in their shoes. We screen shoes, they use liquids. We limit liquids, they sew PETN into their underwear. We implement full-body scanners, and they’re going to do something else. This is a stupid game; we should stop playing it.

Edward Hasbrouck:

What’s most striking about the government’s response to this unsuccessful bombing attempt is the complete lack of any rational relationship between the actions that have been taken and are being proposed, any analysis of which of these and similar tactics did or did not contribute to the success or failure of the Christmas Day attack on Northwest Airlines flight 253, and any likelihood that they would make future attempts at terrorism less likely to succeed.

No, what bothers me is the fact that distorting public policy, removing individual liberties, and instituting a culture of irrationality and fear is exactly what the terrorists wanted in the first place.

Our job is to think critically and rationally, and to ignore the cacophony of other interests trying to use terrorism to advance political careers or increase a television show’s viewership.

So what can I personally do to refuse to be terrorized? Unfortunately, airlines and airports have a monopoly on air travel, and national governments have a monopoly on border control, so I can’t refuse to play the security game whenever I go abroad. I would if I could, because personally I feel more at risk from the security measures than I do from terrorist action. The risk of being subject of an attempted terrorist attack (much less a sucessful one) is, after all, less than being struck by lightning.

For one thing, I can help point out when people take the right approach. For example, The Register:

First: It is completely impossible to prevent terrorists from attacking airliners.

Second: This does not matter. There is no need for greater efforts on security.

Third: A terrorist set fire to his own trousers, suffering eyewateringly painful burns to what Australian cricket commentators sometimes refer to as the “groinal area”, and nobody seems to be laughing. What’s wrong with us?

I can also call bullshit on articles like this one on Travolution in which a tiny, poorly worded sidebar poll on a travel industry blog gets blown up to represent that a majority of all travellers are in favour of body scanners that would not have flagged the completely pants bomber in the first place.

But ranting about this stuff on my blog reminds me of the depressing inevitability of the war in Iraq in late 2002 and early 2003. No matter how much we, the people, protested — and the lead-up to the war we saw the biggest anti-war protests in history — our governments still went blithely ahead. I may have high hopes for the decade ahead, but an end to the ridiculous security theatre that plagues us is beyond even my wildest dreams.

How to detect a page request from Safari 4’s Top Sites feature

While reading Jeremy Keith’s blog entry “Safari Askew” I remembered that I had looked at this just before Christmas, and found an answer.

The problem is to do with Safari 4’s “Top Sites” feature, which shows you a pretty grid of thumbnails for the sites you visit most regularly (or that you have pinned in place). The interesting thing is that these thumbnails are live (ish) previews of what those pages currently look like. If you don’t happen to have a Top Sites page open in a tab, and if Safari considers that the current thumbnail is sufficiently out of date, it will automatically go and retrieve the latest version.

Safari 4's Top Sites feature

This can cause headaches for site owners, because in order to show the actual state of the page, Safari relies on full page requests: it downloads all the HTML, CSS, images, and JavaScript for the page, and then displays everything exactly as if the user were viewing the page in a standard tab. Adverts are rendered, page tracking scripts are executed, and to the server it looks just like a regular page hit. This can lead to the site recording unnecessary actions, and your site analytics being all messed up.

At Skyscanner, for example, we noticed this because Google Analytics was showing an unusually high number of Safari users (8.5%) with an abnormally high bounce rate (the proportion of sessions where users view a single page, then walk away with no further interaction): Safari 4 users were twice as likely to bounce as other browsers. Useless sessions generated by Top Sites were the problem.

As Jeremy noted, the user agent that Safari 4 reports for a Top Sites request is exactly the same as for a normal page request. Fortunately, there is a way to distinguish the two types of request: in the current version of Safari 4 (4.0.4) the Top Sites request for the base page (but not its JS/CSS/image resources) carries an additional HTTP header, namely “X-Purpose: preview“.

An easy way to verify this is to use an HTTP debugging proxy like Fiddler or Charles to watch what happens when Top Sites makes a request — see the screen grabs below:

Normal and Top Sites HTTP requests from Safari 4

If your pages are dynamically generated, you can adjust your server-side code to examine the HTTP headers of the incoming request, and take appropriate action if this is a “preview” request. Here’s some sample PHP code:

<?php
if ($_SERVER["HTTP_X_PURPOSE"] == "preview") {
	echo "preview";
} else {
	echo "normal";
}
?>

("X-Purpose" is not a standard HTTP header, and you won’t find “HTTP_X_PURPOSE” in the PHP documentation. It’s the CGI specification that specifies how HTTP headers should be handled: they should be made into an environment variable with an “HTTP_” prefix followed by the header name, with dashes replaced by underscores. Hence, the value of the "X-Purpose" header is placed in the "HTTP_X_PURPOSE" environment variable, and retrieved as $_SERVER["HTTP_X_PURPOSE"].)

If all you’re looking to do it fix your site stats in Google Analytics, then you should just make sure that you don’t write out the GA tracking code for preview requests. If you are concerned about excessive load on your servers, unwanted user actions, or spurious advert impressions, you can take more aggressive action, perhaps by rendering a lightweight version of the page. An extreme possibility I considered was generating a completely different version of the page, specifically designed to look good in the thumbnail format of the Top Sites preview page:

Safari 4 Top Sites with custom preview thumbnail: PROBABLY A BAD IDEA

However, doing this runs counter to the notion that these thumbnails represent previews, and I don’t know how your users would react. More importantly, Google might consider this cloaking, and come round your house in the middle of the night with a baseball bat. Just because it’s possible, doesn’t mean it’s a good idea…