Utiliser l'API PageVisibility

| Joe Marini | Bovino |

Traducteur

Didier Mouronval

Cet article est la traduction de Using the PageVisibility API, par Joe Marini publié sur le site HTML5 Rocks.

Commentez

- Titre : Utiliser l'API PageVisibility

- Auteurs : Joe Marini, Bovino

- Traducteur : Didier Mouronval

- Parution : 2 novembre 2012

- Mise à jour : 26 décembre 2012

- Licence : Le contenu de cet article est rédigé par Joe Marini et est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.

Sommaire

- I. Introduction

- II. Propriétés de visibilité du document

- II-A. Gérer les préfixes vendeurs

- II-B. Exemple de propriétés du document

- III. L'événement visibilityChange

- IV. Exemples pratiques

- IV-A. Démarrer et mettre en pause une vidéo

- IV-B. Afficher une notification lorsque l'onglet est masqué

- IV-C. Gérer Google Analytics si la page est préchargée

- V. Conclusion, références et remerciements

- V-A. Conclusion

- V-B. Références

- V-C. Remerciements

I - Introduction

En tant que développeurs Web, nous sommes toujours curieux des nouvelles techniques permettant d'obtenir des pages Web plus riches et interactives.

Des graphiques 3D avec WebGL ? Absolument ! Des capacités audio avancées avec WebAudio ? Je prends ! Des applications participatives en temps réel utilisant la webcam et le micro ? Je signe où ?

Moins spectaculaires mais tout aussi importantes, des technologies existent permettant de créer des applications plus efficaces et améliorant l'expérience de l'utilisateur. L'API Page Visibility en fait partie. Cette API a un rôle simple, mais néanmoins important : elle permet à votre application de savoir si une page est visible par l'utilisateur. Grâce à cette information, vous pourrez créer des pages Web qui se comporteront différemment selon qu'elles sont visibles ou non. Prenons quelques exemples :

- une page récupérant des informations depuis le serveur peut ralentir son cycle de mise à jour lorsqu'elle n'est pas visible ;

- une page affichant une galerie d'images ou du contenu audio/vidéo peut se mettre en pause tant que l'utilisateur ne revient pas sur la page ;

- il se peut qu'une application n'affiche de notifications que lorsque la page n'est pas visible.

Au premier abord, cette API peut ne pas sembler très utile pour l'utilisateur, mais si l'on considère l'augmentation de la navigation depuis un appareil mobile, toute technique permettant d'économiser la batterie devient rapidement importante. En utilisant l'API PageVisibility, votre site pourra aider l'appareil à consommer moins d'énergie et donc augmenter son autonomie.

La spécification de l'API, qui n'en est, au moment d'écrire cet article (N.D.T. : 25/10/2012), qu'à l'état de recommandation, propose des propriétés pour connaître l'état de visibilité du document, ainsi que des événements indiquant le changement d'état. Dans cet article, je traiterai des bases de l'API et montrerai des exemples concrets d'utilisation.

II - Propriétés de visibilité du document

La version courante des spécifications de l'API PageVisibility définit deux propriétés pour le document : la valeur booléenne hidden et l'énumération visibilityState. La propriété visibilityState peut avoir quatre valeurs : hidden, visible, prerender et unloaded.

Actuellement, ces propriétés ne sont disponibles qu'à l'aide de préfixes vendeurs. Vous devrez donc utiliser les versions préfixées (comme webkitHidden ou webkitVisibilityState) tant que la spécification n'aura pas le statut de recommandation et que les navigateurs n'implémenteront pas les versions sans préfixe.

Comme vous pouvez vous y attendre, l'attribut hidden renvoie true si le document n'est pas visible. Typiquement, cela signifie que le document est réduit, dans un onglet non actif, etc. L'attribut vaut false si au moins une portion du document est partiellement visible sur au moins un écran. De plus, afin de s'adapter aux outils d'accessibilité, l'attribut hidden peut valoir false si un outil comme une loupe masque le document en en montrant une vue.

II-A - Gérer les préfixes vendeurs

Afin de rester concentré sur le code et non sur tous les préfixes vendeurs spécifiques, je vais créer des fonctions utilitaires pour gérer les différentes notations.

function getHiddenProp(){
var prefixes = ['webkit','moz','ms','o'];

// si 'hidden' est supporté nativement, le retourner
if ('hidden' in document) return 'hidden';

// sinon, boucler sur les préfixes connus pour trouver le bon
for (var i = 0; i < prefixes.length; i++){
if ((prefixes[i] + 'Hidden') in document)
return prefixes[i] + 'Hidden';
}

// sinon, la fonctionnalité n'est pas supportée
return null;
}

II-B - Exemple de propriétés du document

Nous pouvons maintenant écrire une fonction compatible pour tous les navigateurs, isHidden(), pour savoir si le document est visible.

function isHidden() {
var prop = getHiddenProp();
if (!prop) return false;

return document[prop];
}

Pour connaitre de façon plus précise l'état de visibilité du document, on utilisera plutôt la propriété visibilityState. Cette propriété retourne l'une des quatre valeurs suivantes :

- hidden : le document est complètement caché ;

- visible : au moins une partie du document est visible sur au moins un écran ;

- prerender : le document est chargé hors écran et n'est pas visible (cette valeur étant optionnelle, tous les navigateurs ne l'implémentent pas nécessairement) ;

- unloaded : le document n'est pas chargé (cette valeur étant optionnelle, tous les navigateurs ne l'implémentent pas nécessairement).

III - L'événement visibilityChange

En complément des propriétés de visibilité, il existe un événement visibilityChange déclenché chaque fois que l'état de la visibilité du document change. Vous pouvez donc utiliser un gestionnaire d'événements directement sur l'objet document :

// utiliser les noms de propriété pour trouver le nom de l'événement préfixé
var visProp = getHiddenProp();
if (visProp) {
var evtname = visProp.replace(/[H|h]idden/,'') + 'visibilitychange';
document.addEventListener(evtname, visChange);
}

function visChange() {
var txtFld = document.getElementById('visChangeText');

if (txtFld) {
if (isHidden())
txtFld.value += "Onglet non visible !\n";
else
txtFld.value += "Onglet visible !\n";
}
}

Vous pouvez voir comment fonctionne le code ci-dessus dans le champ suivant. Essayez de masquer puis d'afficher cet onglet et regardez le contenu du champ.

Le contenu dynamique ne peut pas être affiché dans ce support, veuillez consulter la page en ligne.

Si le message « L'API PageVisibility n'est pas supportée ! » est affiché, c'est que votre navigateur ne supporte pas cette API.

IV - Exemples pratiques

IV-A - Démarrer et mettre en pause une vidéo

Cet exemple montre comment utiliser l'API PageVisibility pour lancer et mettre en pause une vidéo.

Lancez la vidéo (si elle n'est pas supportée, testez avec Chrome), puis changez d'onglet. Vous pourrez alors constater qu'elle se met automatiquement en pause, puis reprend la lecture lorsque vous revenez sur l'onglet.

Le contenu dynamique ne peut pas être affiché dans ce support, veuillez consulter la page en ligne.

Ceci est réalisé en utilisant un gestionnaire pour l'événement visibilityChange et en modifiant l'état de lecture de la vidéo.

window.addEventListener("load", function vidDemo() {
sessionStorage.initialPlay = false;
var vidElem = document.getElementById("video-demo");

var visProp = getHiddenProp();
if (visProp) {
vidElem.addEventListener("play", function() {
sessionStorage.initialPlay = true;
});

var evtName = visProp.replace(/[H|h]idden/,'') + 'visibilitychange';
document.addEventListener(evtName, startStopVideo);
}

function startStopVideo() {
if (document[visProp]) {
vidElem.pause();
}
else if (vidElem.paused && sessionStorage.initialPlay == "true") {
vidElem.play();
}
}
});

IV-B - Afficher une notification lorsque l'onglet est masqué

L'API Notifications permet d'afficher des bulles d'informations au niveau du navigateur pour attirer l'attention de l'utilisateur. Cependant, lorsque l'utilisateur se trouve déjà sur la page, attirer son attention n'est pas nécessairement utile. Grâce à l'API PageVisibility, nous allons pouvoir afficher les notifications uniquement lorsque l'onglet n'est pas actif.

Vous devez d'abord activer les notifications (en cliquant sur le bouton ci-dessous avec un navigateur compatible, par exemple Chrome). Cliquez ensuite sur « Envoyer une notification ! » et changez d'onglet. Après cinq secondes, le code va vérifier l'état de l'onglet et afficher soit une notification, soit une boîte d'alerte classique.

Le contenu dynamique ne peut pas être affiché dans ce support, veuillez consulter la page en ligne.

Voici le code correspondant :

window.addEventListener("load", function notifyDemo() {
var propName = "";
var oNotify=null;
var visProp = getHiddenProp();

document.getElementById("notify-demo").addEventListener("click", function() {
oNotify = null;
if (window.webkitNotifications) {
setTimeout(showNotification, 5000);

if (window.webkitNotifications.checkPermission() == 0) { // 0 = PERMISSION_ALLOWED
oNotify = window.webkitNotifications.createNotification('', 'Notification', 'Vous avez reçu une notification !');
}
}
});

document.getElementById("notify-enable").addEventListener("click", function() {
window.webkitNotifications.requestPermission();
});

function showNotification() {
if (document[visProp] && window.webkitNotifications && oNotify) {
oNotify.show();
}
else {
alert("Vous avez reçu une notification !");
}
}
});

IV-C - Gérer Google Analytics si la page est préchargée

Certains navigateurs (comme Chrome), permettent de précharger des pages (voir plus d'informations ici). Ce procédé implique de charger toutes les ressources nécessaires au rendu de la page, y compris les scripts. De nombreux sites utilisent Google Analytics pour avoir des statistiques sur la fréquentation du site. Cependant, ces données peuvent être faussées si certaines pages sont préchargées mais jamais réellement vues.

Pour pallier ce problème, vous pouvez utiliser l'API PageVisibility afin de savoir si la page est en mode de préchargement et, dans ce cas, ne pas charger le script. La page contient normalement une portion de code similaire à celui-ci :

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXX-X']);
_gaq.push(['_trackPageview']);

Dans ce cas, l'événement _trackPageview est toujours déclenché, même si la page n'est pas affichée. Un script permettant de détecter le préchargement ressemblerait à celui-ci :

var bHavePV = getHiddenProp();
var bInitialShow = false;
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXX-X']);

if (bHavePV) {
document.addEventListener("visibilityChange", handleVisEvt);
}
else {
_gaq.push(['_trackPageview']); // si l'API n'est pas reconnue, charger normalement le script
}

function handleVisEvt() {
if (document.visibilityState == "prerender") {
_trackEvent("pagedata", "prerender"); // garder une trace du préchargement
}
if (document.visibilityState == "visible" && !bInitialShow) {
bInitialShow = true; // ne charger le code qu'une fois
_gaq.push(['_trackPageview']);
}
}

V - Conclusion, références et remerciements

V-A - Conclusion

Créer une bonne application Web ne se limite pas à des effets spectaculaires ou des interactions poussées avec l'utilisateur. Il est aussi nécessaire de prendre en considération et de préserver les ressources de l'appareil de l'utilisateur. De ce point de vue, l'API PageVisibility est d'un grand intérêt. Pour aller plus loin sur ce sujet, vous pouvez consulter les autres articles liés aux performances de HTML5 Rocks.

V-B - Références

- Spécifications de l'API PageVisibility (W3C).

- Groupe de travail sur les performances Web.

- Exemple de PageVisibility pour IE10.

- Visibility.js : solution de contournement de PageVisibility.

- IsVis : autre solution de remplacement.

V-C - Remerciements

Cet article est la traduction de Using the PageVisibility API, par Joe Marini publié sur le site HTML5Rocks.

Nous tenons aussi à remercier ced, ClaudeLELOUP et _Max_ pour leur relecture attentive de cet article.