Iconography for meeting room layouts at Hotel Moskva in Belgrade.
About Sam Stephenson
Programmer at Basecamp.
The Office 2013 UI, as captured by Peter Bright of Ars Technica.
Announcing Pow 0.4.0 with xip.io support
We’ve just released version 0.4.0 of Pow, our zero-configuration web server for Rails development on OS X.
There are several new features in this release, including port proxying and better support for zsh users, but my favorite is a tiny addition that makes a huge difference when testing your apps on mobile devices.
Pow has always made it easy to access Rails apps on your computer with its built-in .dev
domain. Just symlink your app into the ~/.pow
directory and visit http://myapp.dev/
in your browser.
But what about testing your apps on mobile devices, or in IE? Pow’s .dev
domain only works on your local machine.
Until now, testing on other computers required modifying /etc/hosts
or setting up a custom DNS server on your router. Now we’ve fixed that, too.
Introducing xip.io, the magic domain name
Pow 0.4.0 has built-in support for xip.io, a free service from 37signals that provides wildcard DNS for any IP address.
With xip.io you can access your Rails apps from devices on your local network, like iPads, iPhones, Windows VMs, and other computers. No configuration required.
Say your development computer’s LAN IP address is 10.0.0.1. With the new version of Pow, you can now access your app at http://myapp.10.0.0.1.xip.io/
. And xip.io supports wildcard DNS, so any and all subdomains of 10.0.0.1.xip.io
resolve too.
Read more about xip.io at http://xip.io/ or check out the full source code on GitHub.
Installing and upgrading
See the full 0.4.0 release notes and install or upgrade with one simple command from your terminal:
curl get.pow.cx | sh
As always, the user’s manual and annotated source code are available for your perusal.
Using event capturing to improve Basecamp page load times
We’ve been busy tightening the nuts and bolts on the all-new Basecamp in the wake of last week’s launch. As part of the process, I decided to take a closer look at client-side page load performance. Shaving even a tenth of a second off of page load time can have a big impact on perceived performance, so it’s a worthwhile investment.
Profiling the JavaScript page load event led to a surprising revelation. On pages with many to-dos, an overwhelming majority of the time was spent initializing sortable behavior. The culprit looked something like this:
$.ready(function() {
$("article.todolist, section.todolists").sortable();
});
In other words, when you’d load any page with to-dos on it, Basecamp would make the items of each to-do list reorderable, then make the whole collection of to-do lists reorderable. That could take up to half a second on heavy pages.
Here’s the thing: you probably aren’t reordering to-dos every time you visit a project. It would be best if we could avoid initializing sortables until the last possible moment, just before you start to drag a to-do.
Deferring Initialization
That got me thinking. What would happen if we tried waiting until the first mouse press before initializing sortables? The mousedown
event gets us a lot closer to the intention of reordering than the page load event. I tried it out:
$(document).on("mousedown", ".sortable_handle", function() {
$("article.todolist, section.todolists").sortable();
});
The new code says that when we receive a mousedown
event on the page that comes from somewhere inside a sortable drag handle, we should go ahead and initialize all the sortables on the page.
Sadly, this code doesn’t work. The sortable()
initialization installs a mousedown
handler of its own, but by that time it is too late. The event has already bubbled its way up to our delegated event handler.
If only there were a way to catch the mousedown
event just before it begins its ascent up the DOM…
CSS tip: Spot unsized images during development
Have you noticed that software feels cheap when UI elements move around on the screen without notice? Web applications are particularly vulnerable to this problem. Browsers give image elements a default size if they do not have explicit width and height attributes. Once these images have loaded, they expand or contract to their full size, causing all other elements on the page to reflow in response.
Unsized images reflow the page when they load
We try to avoid this in our applications, but it’s easy for an image tag to slip through the cracks. That single tag might be repeated many times in a loop, each instance causing the on-screen furniture to shift around in an unseemly way.
Here’s a tip for catching unsized images during development. Add this CSS rule somewhere in your stylesheet:
img:not([width]):not([height]) {
border: 2px solid red !important;
}
Then any images without width and height attributes will be drawn with a red border so they’re easy to spot.
Motorola’s new Android phone truncates “Text Messaging” to “Text Messagin…” and “Text Mess.”
We’re all to blame.
Device-scale user interface elements in iOS Mobile Safari
When we set out to build finger-friendly controls for iOS devices in Basecamp, two major constraints informed our design.
In Basecamp on a PC, when you hover over a to-do, milestone, or file, you’ll see edit and delete controls. But as has been covered here and elsewhere on the web, there’s no way to hover on a touch device. So our solution to this first constraint is to show the controls when you tap instead of when you hover.
The second constraint is that the controls must be finger-friendly. That is, they should be sized such that they’re always big enough to operate with a thumb, but never too big to fit on the screen.
Our first attempt at these controls turned out to be too small when zoomed out…
…and too big when zoomed in.
Continued…This shipping notification email from Waterfield succeeds at conveying a personal and sincere tone even though I suspect it’s automated. The subject invites you to open it and the “thanks for tracking us down…” paragraph feels genuine. (Nice subtle dig at the USPS’s “tracking” service, too.)
Apple sweats the details, even in the most pedestrian corners of its software. (Finer Things in Mac, via Daring Fireball)