How to Use the Network Information API to Improve Responsive Websites

Responsive Web Design has revolutionized the web. A single site can adapt its layout when viewed on a range of differing devices and screens. All that’s required is a few media queries to detect the screen size and load alternative styles or stylesheets.

However, using the screen size to detect browser capabilities is akin to judging a car’s speed by looking at its radio. Modern smartphones and tablets have increasingly large resolutions and will happily show a typical desktop view. If that view adds numerous fonts, images or other assets, the mobile user may receive a degraded — and expensive — experience because they’re on a slower or metered connection.

The Network Information API

The Network Information API may help. It indicates whether the user is on a metered connection, such as pay-as-you-go, and provides an estimate of bandwidth. Using this information it’s possible to conditionally load images, videos, fonts and other resources. At a basic level, you could override a media query to ensure the mobile layout is retained on a limited network.

Browser Support

Despite the Network Information API draft specification being released in 2011, only Firefox and Chrome offer experimental support at this time. Until we have vendor consensus, the API is subject to change:

  • assessing bandwidth is difficult. It may change frequently as you move around or switch between mobile and wi-fi networks. Network capacity may be good, but it doesn’t follow that a connection to a specific server will be. Keeping the bandwidth estimate up-to-date may also be processor and network-intensive.
  • how can the device know whether your connection is metered? Even fast wi-fi may have ludicrously extortionate costs at some hotels and airports I could mention. One option would be for the device to prompt you when a new connection is made.

Fortunately, we can use object detection to detect for the presence of the API.

API Basics

The Network Information API object is returned by navigator.connection. To ensure cross-browser compatibility, we need:

var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;

You may want to add navigator.msConnection to that list, although IE normally implements non-prefixed APIs.

Our connection object provides two read-only properties:

  • bandwidth — a double representing an estimation of the current bandwidth in MB/s (Megabytes per second). The value will be zero if the user is offline and Infinity if it cannot be determined. Note most network providers quote values in Megabits per second and a typical busy mobile 3G connection will be around 400Mbps ~= 400,000 bits/s ~= 50Kb/s ~= 0.05MB/s.
  • metered — a Boolean which, when true, means the user’s connection is subject to limitation and bandwidth usage should be limited where possible.

For example:

if (connection && !connection.metered && connection.bandwidth > 2) {
  // load high-resolution image
  var img = document.getElementById("kitten");

  img.src = "/images/kitten_hd.jpg";
}

Finally, we can execute a change event handler when the connection status changes, e.g.

// default bandwidth
var highBandwidth = false;

// bandwidth change handler
function BandwidthChange() {
  highBandwidth = (!connection.metered && connection.bandwidth > 2);
  console.log(
    "switching to " +
    (highBandwidth ? "high" : "low") +
    " bandwidth mode"
  );
}

// Network Information object
var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;

// initialize
if (connection) {
  connection.addEventListener("change", BandwidthChange);
  BandwidthChange();
}

In this code, the global highBandwidth variable will be set true when high bandwidth is available. Other code could react accordingly, e.g. when highBandwidth is false:

  1. high-resolution images are not loaded
  2. unnecessary fonts are not loaded
  3. Ajax polling is slowed down
  4. Ajax timeout parameters are increased

To make things a little easier, you could append a class to the body tag in the BandwidthChange function, e.g.

// bandwidth change handler
function BandwidthChange() {
  highBandwidth = (!connection.metered && connection.bandwidth > 2);

  var body = document.body;

  if (highBandwidth) {
    body.classList.add("hibw");
  }
  else {
    body.classList.remove("hibw");
  }

  console.log(
    "switching to " +
    (highBandwidth ? "high" : "low") +
    " bandwidth mode"
  );
}

This allows us to conditionally load items such as background images in CSS, e.g.

/* low bandwidth plain-color background */
#myelement
{
  background-color: #ccc;
}

/* high bandwidth image background */
body.hibw #myelement
{
  background: url(image.jpg) 0 0 no-repeat;
}

This condition can still be checked in desktop layouts loaded by media queries.

Should You Use the Network Information API?

At the time of writing, the Network Information API has little browser support and could change. That said, if you’re creating a website or application which must work on mobile devices, a little planning now could prevent your pages from reaching 1.7Mb. If the API changes, you’d simply need to update the BandwidthChange function and your site would react appropriately.

I certainly think the Network Information API is worth consideration. Do you?

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://jaf.ar.com/ Jafar

    Interesting API, can’t wait to use it, even if it’s like 2 years down the road.

  • Aurelio De Rosa

    Hi Craig. When you say “experimental”, do you mean under a flag?

    • Craig Buckler

      It’s available without flags. I must remember not to use such words – everything has a double-meaning in IT!

      • Aurelio De Rosa

        Strange. I asked you because I tried in last version of Chrome (32) and got “undefined” in either case (unprefixed and prefixed version).

        • Craig Buckler

          Hmm. Perhaps it’s only available on Chrome Mobile? I’ll dig a little further…

          • http://bluesmoon.info Philip Tellis

            Yes, only on mobile. Boomerang has supported navigator.connection for a while now and we’ve seen mixed results. At first there was navigator.connection.type, then that went away and bandwidth and metered showed up.