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
:
- high-resolution images are not loaded
- unnecessary fonts are not loaded
- Ajax polling is slowed down
- 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?