We’re all resigned to it: launching a browser reloads every tab you previously had open, blasting a cacophonous mix of sound and video. While browsers have made it easier to control this experience with tab icons and extensions like MuteTab, for most people this behavior presents a confusing and disorienting experience. As developers and designers it’s our job to make the web welcoming, not overwhelming.
Doesn’t it make sense that sites should only be active when they are the primary focused tab? Why are we burning up batteries and processor cycles with animation that can’t be seen?
Further Reading on SmashingMag:
- Building A Cross-Platform WebGL Game
- CSS3 Transitions: Thank God We Have A Specification!
- Creating Responsive Shapes With Clip-Path
- Hybrid Mobile Apps: Providing A Native Experience
Thankfully, there is a solution: the HTML5 Page Visibility API. You can see it used particularly effectively in recent projects by Active Theory, such as their work for Under Armor and A Spacecraft For All: click to another tab and you’ll find that the multimedia presentation pauses and the music fades away. This behavior typifies what I like to call the “polite web”: sites that are considerate of users’ attention, bandwidth and abilities.
In the past developers have tried to create this behavior by adding onblur()
and onfocus()
window handlers. While they are considerably better than nothing, the approach is limited by the fact that it can’t tell if the window is actually hidden to the user. For example, having two browser windows side-by-side and switching between them would still register as onblur()
or onfocus()
, even though the content in each remains perfectly visible.
Implementing Page Visibility
While there are many possibilities for using the Page Visibility API, perhaps the most obvious use case is when a page contains video: there’s usually little point in continuing to play video content if the user can’t see it.
<video autoplay controls id="videoElement"> <source src="rar.mp4"> <source src="rar.webm"> </video> <script>
var videoElement = document.getElementById("videoElement"); document.addEventListener("visibilitychange", function() { if (document.hidden) { videoElement.pause(); } else { videoElement.play(); } });
</script>
The one problem with this is that it’s a little abrupt: the audio on the video starts and stops as if cut off with a guillotine when the user switches tabs. The presentation could be improved significantly by fading the audio in and out as the tab is focused. If we’re using jQuery, we can employ a neat use of the animate
method to do so.
<script>
var videoElement = document.getElementById("videoElement"); document.addEventListener("visibilitychange", function() { if (document.hidden) { $("#videoElement").animate({volume: 0}, 1000, "linear", function() { videoElement.pause(); }); } else { videoElement.play(); $("#videoElement").animate({volume: 1}, 1000, "linear"); } });
</script>
The Spec
The Page Visibility API spec is surprisingly simple, consisting of just two methods: document.hidden
returns true
or false
depending on the status of the browser window; and those same states are reflected in string form for document.visibilityState
(hidden
and visible
, respectively, with two optional values of prerender
and unloaded
), with visibilitychange
available as an event. document.visibilityState
can be useful in determining why a document is not visible, but otherwise document.hidden
covers most needs.
Precautionary Principles And Browser Support
The Page Visibility API takes a deliberately conservative approach to reporting a hidden document: your page will be reported as hidden if the user switches to another tab in the same browser window, but not if you move another window to obscure your page. The API is not foolproof, and will return false positives in some circumstances, erring on the side of caution.
Support for the Page Visibility API is excellent: all modern browsers, with the exception of Opera Mini, fully support the API, including IE10+. Vendor prefixes are also refreshingly absent from implementation of the spec: the only browsers that currently need a –webkit
prefix are Android and Blackberry. For that reason (and for the sake of simplified illustration) I have not included any prefixes in the code samples above, although they are easy enough to include and test for.
The Page Visibility API is also an excellent example of progressive enhancement. If the browser doesn’t support the API, the script will be ignored, and the user will simply be subjected to the usual uncontrolled cacophony.
Other Uses
While audio and video content are obvious candidates for using the Page Visibility API, there are many other possibilities: pausing a slider or presentation while the site remains out of focus, or changing the visual state of the page as it remains neglected.
Considerate use of the API can help make the web a better, greener, and more responsible place, and I would strongly encourage developers to consider how to integrate it into their projects.