Using the PageVisibility API
Thanks to the new APIs and features coming to us through better implementations of HTML5, CSS3 and JavaScript, building a modern, usable web application with animations, notifications, real time communication and much more got a lot easier.
Introducing the PageVisibility API
One of the most overlooked APIs that we got is the PageVisibility API that lets you react to visibility changes of your website, e.g. when the user switches the tab. Sure, it’s not the first thing that comes to mind when you think of web development these days, but it allows for some nice features:
- stop animations when the page is not visible
- stop video playback when the user switches the tab
- stop playing sound when the page is not visible (you all know that annoying “Damn, which tab is playing that sound”-problem)
- give the user a digest of the latest changes when he comes back to the page
- stop polling to save some precious CPU cycles
- pause/resume a game
- mark the user as away from keyboard (or tab) in a chat application
- use Desktop Notifications to display important messages while the user is away (please only do that with user’s consent)
- only track the visit if the site is visible (not prerendered)
- a lot more
Demo
Check out the demo to see it in action and to get a hint of what’s possible.
Using it
Using the API is simple:
var onVisibilityChange = function(onVisible, onInvisible, onPrerender) {
var bindVisibilityChange = function(eventName, propertyName) {
document.addEventListener(eventName, function(event) {
switch (document[propertyName]) {
case 'visible':
if (typeof onVisible === 'function') onVisible(event);
break;
case 'hidden':
if (typeof onInvisible === 'function') onInvisible(event);
break;
case 'prerender':
if (typeof onPrerender === 'function') onPrerender(event);
break;
}
});
};
if (typeof document.visibilityState !== 'undefined') {
bindVisibilityChange('visibilitychange', 'visibilityState');
} else if (typeof document.webkitVisibilityState !== 'undefined') {
bindVisibilityChange('webkitvisibilitychange', 'webkitVisibilityState');
} else if (typeof document.mozVisibilityState !== 'undefined') {
bindVisibilityChange('mozvisibilitychange', 'mozVisibilityState');
} else if (typeof document.msVisibilityState !== 'undefined') {
bindVisibilityChange('msvisibilitychange', 'msVisibilityState');
}
};
onVisibilityChange(wakeUp, goToSleep);
This little snippet checks if the browser supports the API, binds the event
handler when the visibility changes and calls the connect
or disconnect
functions with the event
argument, based on the visibility of the page.
Browser support and possible fallbacks
Most browsers support the API nowadays, current Firefox versions even without the prefix. Only desktop and mobile Safari and the Android stock browser have to catch up.
When the browser supports the PageVisibility API it populates two properties
in the document
object. hidden
, a boolean determining if the page is visble
or not, and visibilityState
which is a string that can be one of these:
prerender
when the page is prerendered but not visible yethidden
when the page is hiddenvisible
when the page is visible
As for fallbacks, don’t be misguided by the pageshow & pagehide
events. Their names sound like the right tool, but in fact they’re just
load
& unload
with special cache semantics.
Luckily there are some polyfills that emulate
the behaviour by using focusin
, focusout
, focus
& blur
events.
‘Production’ example
With this tool in your belt you now have even more ways to explore the interactivity of web apps. This allows to save energy and spare battery life, for which especially your mobile users will be thankful. In spotify-remote we use this technique to recognize when the user does not see the remote interface and disconnect from the server. With no connections the server stops polling and the interface basically pauses, saving resources on both the client and server.
Further resources
The fine folks of html5rocks have also published an information filled article about this API. Also be sure to check the spec.
Now go ahead and build awesome stuff & let us know what you think and share your ideas on how to use this API.
Talk
I recently gave a talk about that topic at BerlinJS: You can find the slides here