Journal tags: detection

3

sparkline

A tiny lesson in query selection

We have a saying at Clearleft:

Everything is a tiny lesson.

I bet you learn something new every day, even if it’s something small. These small tips and techniques can easily get lost. They seem almost not worth sharing. But it’s the small stuff that takes the least effort to share, and often provides the most reward for someone else out there. Take for example, this great tip for getting assets out of Sketch that Cassie shared with me.

Cassie was working on a piece of JavaScript yesterday when we spotted a tiny lesson that tripped up both of us. The script was a fairly straightforward piece of DOM scripting. As a general rule, we do a sort of feature detection near the start of the script. Let’s say you’re using querySelector to get a reference to an element in the DOM:

var someElement = document.querySelector('.someClass');

Before going any further, check to make sure that the reference isn’t falsey (in other words, make sure that DOM node actually exists):

if (!someElement) return;

That will exit the script if there’s no element with a class of someClass on the page.

The situation that tripped us up was like this:

var myLinks = document.querySelectorAll('a.someClass');

if (!myLinks) return;

That should exit the script if there are no A elements with a class of someClass, right?

As it turns out, querySelectorAll is subtly different to querySelector. If you give querySelector a reference to non-existent element, it will return a value of null (I think). But querySelectorAll always returns an array (well, technically it’s a NodeList but same difference mostly). So if the selector you pass to querySelectorAll doesn’t match anything, it still returns an array, but the array is empty. That means instead of just testing for its existence, you need to test that it’s not empty by checking its length property:

if (!myLinks.length) return;

That’s a tiny lesson.

Detection

When I wrote about responsible responsive images a few months back, I outlined my two golden rules when evaluating the various techniques out there:

  1. The small image should be default.
  2. Don’t load images twice (in other words, don’t load the small images and the larger images).

I also described why that led to my dissatisfaction with most server-side device libraries for user-agent sniffing:

When you consider the way that I’m approaching responsive images, those libraries are over-engineered. They contain a massive list of mobile user-agent strings that I’ll never need. Remember, I’m taking a mobile-first approach and assuming a mobile browser by default. So if I’m going to overturn that assumption, all I need is a list of desktop user-agent strings.

I finished by asking:

Anybody fancy putting it together?

Well, it turns out that Brett Jankord is doing just that with a device-detection script called Categorizr:

Instead of assuming the device is a desktop, and detecting mobile and tablet device user agents, Categorizr is a mobile first based device detection. It assumes the device is mobile and sets up checks to see if it’s a desktop or tablet. Desktops are fairly easy to detect, the user agents are known, and are not changing anytime soon.

It isn’t ready for public consumption yet and there are plenty of known issues to iron out first, but I think the fundamental approach is spot-on:

By assuming devices are mobile from the beginning, Categorizr aims to be more future friendly. When new phones come out, you don’t need to worry if their new user agent is in your device detection script since devices are assumed mobile from the start.

Detection

One of the recurring themes at the Mobilism conference earlier this year—and more recently at the Breaking Development conference—was the subject of server-side user-agent detection. I posed the question in absurdum on the Mobilism browser panel:

A useful tool for developers or spawn of Satan: which is it?

It’s a contentious issue, as Alex’s strident defence illustrates. Personally, I’ve never been a fan but that’s mostly because of the long history of really, really bad UA-detection in the past. When I discussed this issue with Lyza we came to a détente, agreeing that there is nothing inherently wrong with server-side UA-detection: it’s what you do with it that counts.

In their presentation at Breaking Development Bryan and Stephanie outlined the kind of detection that they have used. Crucially, it assumes a very basic small-screen default—rather than assuming a desktop browser—and later double-checks the profile on the client-side using feature detection.

Luke recently outlined another kind of cautious device detection that he’s calling RESS: Responsive Design + Server Side Components, sending subtly-different DOMs to different classes of device. He also recently wrote about why Bagcheck has a separate mobile site and it strikes me that RESS could alleviate the concerns he mentioned regarding responsive design for Bagcheck.

I think that RESS could be a very useful technique as long as it assumes a safe default: a small-screen, low-bandwidth default. That way, any UA detection would be done against a fairly limited set of user agents: desktop browsers and maybe tablets. To me, that seems far more reasonable than trying to pattern-match against the sprawling jungle of mobile devices in the wild …not to mention the swampy morass of licensing issues with Device Atlas (and now too).

As ever, smart defaults are really important. Just as truly responsible responsive web design goes hand-in-hand with a mobile/content first approach, I think that any server-side detection should do the same. It completely inverts the problem space. Instead of thinking “How can I stop this nice-to-have content/functionality being sent to mobile devices?” you can assume a mobile device by default and then your question becomes “How can I make sure that this nice-to-have content/functionality is only sent to desktop devices?” (the answer probably involves some kind of conditional loading with JavaScript).

A thornier problem with server-side UA-sniffing is that, regardless of whether you’re testing against a list of mobile devices or you’re testing against a list of desktop devices, you’re still committing yourself to an arms race. You are now obligated to keep your list of browsers up to date.

Still, the rate of desktop browser releases is a lot slower than the rate of mobile browser releases. So if a new desktop browser is released and it ends up being served a mobile-optimised DOM, I think that’s better than inadvertently serving a desktop-optimised DOM to a whole bunch of mobile devices.

That’s just my opinion of course. As ever, the standard disclaimer applies.