⬆️ ⬇️

Page Visibility API and Visibility.js

Shroedinger`s cat



Page Visibility API is a new API in JavaScript that allows you to find out if a user sees your site or, for example, has opened another tab.



How can this API make our web friendlier and more comfortable? Well, the most obvious:



To make working with Page Visibility API more convenient, I (to the glory of Evil Martians ) developed the Visibility.js library. It allows you to forget about vendor prefixes and adds “sugar” of high-level functions to write short clean code (for example, Visibility.every is an analogue of setInterval , but only works if the site is in an open tab).

')

A nice example of a video player that stops a video when a page becomes invisible (open in Google Chrome 13).



Browser support



Page Visibility API is now supported in Google Chrome 13 and IE 10. For Firefox 5 and above, there is a MozVisibility hack from private_face that emulates the Page Visibilty API (this hack must be enabled in the page before Visibility.js).



There is already a draft of the W3C Page Visibility API standard, so support in other browsers is a matter of time.



But it’s not at all necessary that the browsers of all your users support this API — it’s just an improvement, not a new feature added, like the <video> . If there is support, it will be more convenient for the user; if not, the site will work like regular sites and think that the user always sees the site. High-level functions in Visibility.js are specifically made so that the developer can not think about whether there is support for the API or not.



States



Now there are 4 possible states of visibility of the page in the standard:



And what will happen when another state is added to the standard, and you will need to check whether the site is visible to the user or not. To do this, there is a document.hidden property (don't forget about vendor prefixes, in Chrome it will be document.webkitHidden ) or the Visibility.hidden() method in Visibility.js. If you need to check whether the site is visible - use this property, and not compare the name of the state with "hidden" .



Visibility.js



In order not to be intimidated by low-level code with a bunch of checks for vendor prefixes, I will show you how to work with the Page Visibility API right away using Visibility.js as an example, and at the end of the article I will talk about low-level API methods.



The library code is completely covered with modular tests , is documented and the library is already being successfully used in Russian Group . In the compressed version, it only weighs 1 KB, but it saves you a lot of extra code.



Visibility.every


Visibility.every(interval, callback) is an analogue of setInterval(callback, interval) , but starts the callback only if the user now sees the page.



For example, we will show the animation of the countdown only when the user sees the page:

 Visibility.every(1000, function() { updateCountdownAnimation(); }); 




Visibility.every(visible, hidden, callback) can take 2 time intervals - visible will use when the page is visible to the user, and hidden - when hidden.



For example, you can check new messages every minute when a user has opened a site (that is, it is important to him). And when the user does not see the site (reads another page) we will save his traffic and check mail every 5 minutes:

 var minute = 60 * 1000; Visibility.every(minute, 5 * minute, function () { checkForEmail(); }); 




But in general, to indicate the time in milliseconds is a mockery of a person. Therefore, Visibility.js supports integration with the jQuery Chrono plugin (you just need to connect it before Visibility.js). The code becomes clear and sweet candied:

 Visibility.every('minute', '5 minutes', function () { checkNewMails(); }); 




To stop a timer started using Visibility.every , use Visibility.stop(timerID) ( clearInterval will not work):

 var slideshow = Visibility.every(5 * 1000, function () { nextSlide(); }); $('.stopSlideshow').click(function () { Visibility.stop(slideshow); }); 




If the browser does not support the Page Visibility API, then Visibility.every will assume that the user always sees the site (that is, it becomes a complete analog of setInterval , but nothing terrible happens).



Visibility.onVisible


Another standard situation is when we wait until the user sees the site (for example, because he opened the link in the background tab). For this, there is a Visibility.onVisible(callback) method that executes the code only when the page becomes visible. If the page is already visible, the callback called right away.



For example, when visiting websites we show some kind of notification and after 10 seconds we hide it beautifully. But if the user opens the site immediately in the background tab, he can skip the notification. Let's then count down 10 seconds after the user actually sees the site:

 Visibility.onVisible(function () { setTimeout(function() { Notification.hide(); }, 10 * 1000); }); 




If the browser does not support the Page Visibility API, then the Visibility.onVisible(callback) will trigger a callback right away.



Visibility.afterPrerendering


Firefox has rel="prefetch" rel="prefetch" for links, which tells the browser that the user is likely to open the link later, so the browser loads its contents in advance. This is necessary, for example, to download the next chapter of the article or for the first result in search results.



Google chrome went ahead and did rel="prerender" rel="prerender" - it not only loads, but also renders the page in advance to open it instantly ( video example from Google).



However, there are many limitations when the page will not be displayed. It is forbidden to make AJAX requests, place audio or video, open pop-ups, carry out heavy calculations. Plus, it is advisable not to consider the user in the statistics of visits until he really opens the site.



For all these tasks, there is a Visibility.afterPrerendering(callback) , which will perform a callback only when the page opens for real (that is, leaves the state of pre-rendering) or performs a callback immediately, if the page was immediately opened normally. In the callback you can enable auto-update via AJAX, add it to the <video> page and count the user in the statistics.



 Visibility.afterPrerendering(function () { Statistics.countVisitor(); }); 




If the browser does not support the Page Visibility API or pre-rendering, then Visibility.afterPrerendering(callback) will trigger the callback immediately.



Low-level functions


If you want to understand on the basis of what all the “sugar” from the examples above works, or you can do something more complicated, then you will need low-level Visibility.js functions. I'll show you how the Page Visibility API works.



Visibility.isSupported() returns true if the browser supports Page Visibility API. The browser does not support Page Visibility API, you can easily find out - it will have document.hidden undefined , not true or false (just do not forget about the vendor prefix, for example, document.webkitHidden ).



Visibility.state() returns the state name ( "visible" , "hidden" or "prerenderer" ). This method simply looks at the document.visibilityState property, taking into account the vendor prefix (for example, document.webkitVisibilityState ). A small example to fix:

 if( Visibility.isSupported() ) { if ( 'hidden' == Visibility.state() ) { Statistics.userOpenPageInBackgroundTab(); } if ( 'prerender' == Visibility.state() ) { Statistics.pageIsPrerendering(); } }) 




If you just need to check whether the user sees the page or not, then it is better to use Visibility.hidden() (since the list of states can be replenished in the future). She just looks at the document.hidden property. The following example includes autoplaying video only if the page is opened immediately in the active tab (and not in the new background):

 $(document).load(function () { if ( !Visibility.hidden() ) { VideoPlayer.play(); } }); 




To monitor the page state change, the document has a visibilitychange event (in Chrome, webkitvisibilitychange ). In Visibility.js there is a shorter way - the method Visibility.change(callback) itself hangs up the event handler and calls a callback every time the page visibility changes. The first argument to the callback is the event object, and the second is the name of the state. Example:

 Visibility.change(function (e, state) { Statistics.trackChangeVisibility(state); }); 




Installation




Links



Source: https://habr.com/ru/post/125833/



All Articles