Menu Search
Jump to the content X X
Smashing Conf Barcelona 2016

We use ad-blockers as well, you know. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. upcoming SmashingConf Barcelona, dedicated to smart front-end techniques and design patterns.

Creating Well-Behaved Sites With The Page Visibility API

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?

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 All1: 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 Link

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 Link

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 Link

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 excellent2: 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 Link

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.

(il, og, ml)

Footnotes Link

  1. 1 http://spacecraftforall.com/
  2. 2 http://caniuse.com/#feat=pagevisibility
SmashingConf Barcelona 2016

Hold on, Tiger! Thank you for reading the article. Did you know that we also publish printed books and run friendly conferences – crafted for pros like you? Like SmashingConf Barcelona, on October 25–26, with smart design patterns and front-end techniques.

↑ Back to top Tweet itShare on Facebook

Advertisement

Dudley Storey has been making web pages for almost has long as there has been a web to create them on. A writer, designer and teacher of web development and 3D, he is the recent author of Pro CSS3 Animation.

  1. 1

    Stig Kristensen

    January 20, 2015 3:49 pm

    Wasn’t aware of that API, but good to learn about it!

    Personally I’m glad that videos and audio continues playing even if the tab isn’t in focus. It would be like if iTunes paused every time I minimised it.

    Pausing costly animations on the other hand makes a lot of sense. There are definitely uses for this!

    18
  2. 2

    I hope youtube doesn’t implement this, often I put a song to play and then I have to do other things in another tab. It’d be annoying if it were to stop (;

    10
  3. 3

    “We’re all resigned to it: launching a browser reloads every tab you previously had open…”

    You know you can disable this behavior in your browser preferences, right?

    6
    • 4

      Mark Thompson

      January 26, 2015 8:11 pm

      “We’re all resigned to it: launching a browser reloads every tab you previously had open, blasting a cacophonous mix of sound and video.”

      I have never experienced this. You have to specifically tell the browser to act like this in the settings.

      0
  4. 5

    I like the idea of this spec, however in reality i like onblur() better. In my tests onblur() will pause my video if i switch to another application or browser tab, so whenever the video is not my focus it pauses; however, with the page visibility API if i switch to a different application the video does not pause. Switching applications should trigger a visibility change event in my opinion.
    I’ve only tests on Mac OSX so I can’t speak for how windows would react.

    1
  5. 6

    “Doesn’t it make sense that sites should only be active when they are the primary focused tab? ”

    This entirely depends on the purpose of the site. I’m often following a live blog/news page in one tab while working in another. I would not want to miss live updates because I wasn’t actively viewing the tab.

    4
  6. 7

    Shouldn’t `videoElement.play();` be invoked conditionally (only play the video if it was previously paused)?

    1
  7. 8

    Nice article for developers

    0
  8. 9

    Youtube does not only not implement this, it actually continues updating the dom for every page you have open playing… You can easily check setting a mutation observer log on the body, the seconds counter on an html5 video will keep being updated every second on every tab… which whatever the purpose of keeping the audio output (as it doesn’t require video focus of course, and pinning is to hard to implement i guess) is quite a shame.

    -1
  9. 10

    This might have interesting applications for automatic logout, for the few instances where that still exists.

    0
  10. 11

    That’s pretty interesting to know this, i am using Mac and i thought its pretty hard to try the API
    Considerate use of the API can help make the web a better, greener, and more responsible place. But i think it still need skills to try this.

    0
  11. 12

    Sean Dunwoody

    February 7, 2015 5:58 pm

    “We’re all resigned to it: launching a browser reloads every tab you previously had open”

    Not if you’re using Firefox:

    Options/Preferences -> Tabs -> Don’t load tabs until selected

    0
    • 13

      Sean Dunwoody

      February 7, 2015 8:03 pm

      Now that I’ve read the full article I feel I should probably add more substance than just the above minor complaint.

      This seems like interesting functionality, but I honestly think it’s use cases will be rather few and far between, to start with most users expect things to keep running when switching tabs, if they’d prefer this not to happen I assume they’re in the habit of pausing whatever video/audio is active before switching tab.

      Having said that, this could be useful for things like carousels etc. to try and save some processor cycles for the user, pausing every one of these element with custom JavaScript seems impractical though – what if a page were to have 6 carousel (an edge case I realise, but I think it illustrates the point well).

      For CSS animations maybe adding a ‘animations-disabled’ class to the html element or removing an ‘animations-enabled’ class would be a good idea, the question then is that increases specificity and complexity in the CSS – is there any way of avoiding it?

      And in terms of JavaScript, is there any reasonable/practical way to code things so that animations can be globally disabled rather than this needing to be done individually?

      0

↑ Back to top