[JS] API Fullscreen : déclencher le plein écran

Lorsque vous naviguez, vous pouvez presque tout le temps passer en plein écran : via la touche F11 si vous avez un clavier ou une option d’un quelconque menu sur vous êtes sur un appareil tactile. Ceci permet de masquer le navigateur (barre d’adresses, menus, …) pour ne voir que ce qui vous intéresse, à savoir le contenu de la page en cours. C’est très pratique si vous présentez une application web à un client par exemple 😉
Toutefois la manipulation à effectuer n’est pas à la portée de n’importe qui, vous avez donc peut être envie de proposer un joli bouton à vos utilisateurs.
Mais si vous êtes sur un site où une miniature est disponible, souvent un bouton « zoom » permet de l’afficher en plus grand. Vous aimeriez pourtant qu’une photo haute résolution prennent 100% de l’espace disponible en plein écran !!

Solution : ces deux options sont disponibles grâce à l’API « Fullscreen ».
Problème : c’est un API non finalisé, et donc chaque navigateur a fait son truc dans son coin…

Dans cet article, je vous propose une solution pérenne pour utiliser l’API tranquillement et facilement.

Présentation de l’API

  • element.requestFullscreen() : passage en mode plein écran
  • document.cancelFullscreen() : sortie du mode plein écran
  • document.fullscreenElement : élément actuellement en plein écran
  • Vous ne pouvez pas décrire l’API plus simplement…

    L’élément sur lequel la première méthode est appelée sera mis en plein écran, c’est à dire que les tous les autres éléments HTML de la page qui ne sont pas enfants de cet élément deviendront invisibles pour l’utilisateur.

    Hélas il y a plusieurs petits détails qui ont leur importance.

    Le premier est que chaque navigateur a fait son truc dans son coin, et différemment d’une version à l’autre d’un même navigateur ! Vous pourrez donc trouver :
    – element.requestFullscreen()
    – element.requestFullScreen()
    – element.webkitRequestFullscreen()
    – element.webkitRequestFullScreen()
    – element.webkitEnterFullscreen()
    – element.webkitEnterFullScreen()
    – element.mozRequestFullscreen()
    – element.mozRequestFullScreen()
    – etc.
    (Notez la casse de « fullscreen/fullScreen » qui en Javascript est primordiale)

    Le deuxième est que les méthodes ne peuvent être utilisées que lors d’un événement « click ».
    C’est plutôt rassurant car ainsi une action de l’utilisateur est requise, il n’est donc pas possible de faire exploser l’écran et déclencher une crise d’épilepsie par exemple. Enfin pas avec cet API en tout cas…

    Le troisième est que chaque navigateur a encore fait son truc dans son coin, et par exemple Firefox mettra l’élément en pleine page (100% de l’espace disponible) tandis que Chrome conservera la taille de l’élément en le centrant sur un fond noir. Vous devez donc galérer un peu pour normaliser tout ça en attendant qu’ils se mettent d’accord.

    La quatrième est qu’il n’y a pas de moyen de faire un thème CSS différent en plein écran et hors plein écran. Chrome propose un :-webkit-full-screen mais selon mes tests il ne fonctionne pas correctement, par exemple impossible de faire un :-webkit-full-screen > span pour thèmer les éléments enfants de l’élément en plein écran. Sous Firefox je n’ai même pas essayé mais j’ai l’habitude d’être déçu par Mozilla donc je vais leur accorder le bénéfice du doute et dire qu’ils ont géré, eux :p

    Enfin un dernier petit détail : au moment de la première utilisation de l’API, un message propose à l’utilisateur d’autoriser le site à passer en plein écran.

    Mon cahier des charges

    Comme d’habitude je vais utiliser mon style de programmation objet : des méthodes définies indépendamment et utilisées en une seule classe.

  • GFullscreen(handler,target) : fait tout à ma place
  • Si l’API est disponible la fonction renverra « true » et un clic sur l’élément « handler » va activer ou désactiver le plein écran sur l’élément « target ».
    Si l’API n’est pas disponible la fonction renverra « false » et l’élément « handler » sera masqué.

  • private GFullscreen.toggle(event) : passe en plein écran ou sort du plein écran
  • Ainsi on peut lier cette méthode à l’événement « click » de l’élément « handler » qui fera l’action adaptée à la situation (c’est un bouton « plein écran »).

  • private static GFullscreen.available() : l’API est-il disponible ?
  • Avant que quelqu’un imagine l’API, il n’existait pas. Avant que votre navigateur ait implémenté l’API, il ne l’implémentait pas.
    J’ai donc besoin d’une méthode pour savoir cela, elle doit renvoyer « true » le cas échéant ou « false » dans le cas contraire.

  • private static GFullscreen.check() : ajout/retrait de la classe CSS « g_fullscreen » sur l’élément
  • À intervalle régulier je vérifie si on est en plein écran.
    J’ai besoin d’avoir une classe en CSS pour thèmer tendrement, donc si elle n’est pas présente sur l’élément actuellement en plein écran, je la rajoute.
    Si elle est présente sur des éléments qui ne sont pas en plein écran, je l’enlève.

  • private static GFullscreen.compat(affix) : renvoi le nom de la méthode ou de la propriété à utiliser
  • C’est pour la gestion de la compatibilité entre les navigateurs, dans la famille « request » je demande la méthode de l’élément, dans la famille « cancel » je demande la méthode du document, dans la famille « element » je demande la propriété du document. Et plus vite que ça !

    Le code

    var GFullscreen = function(handler,target) {
        if(!GFullscreen.available()) {
            handler.style.display = 'none';
            return false;
        }
        handler.onclick = GFullscreen.toggle;
        handler.g_fullscreen_target = target;
        return true;
    };
    GFullscreen.toggle = function(event) {
        event.stopPropagation();
        if(!document[GFullscreen.compat('element')]) {
            this.g_fullscreen_target[GFullscreen.compat('request')]();
            GFullscreen.check();
        }
        else document[GFullscreen.compat('cancel')]();
    };
    GFullscreen.available = function() {
        return typeof(document.documentElement[GFullscreen.compat('request')]) == 'function';
    };
    GFullscreen.check = function() {
        var space = ' ';
        var classname = 'g_fullscreen';
        var full = document[GFullscreen.compat('element')];
        var has = full && (space+full.className+space).indexOf(space+classname+space) != -1;
        if(full && !has) {
            full.className += (full.className?space:'')+classname;
            GFullscreen.check.last = full;
        }
        else if(!full && GFullscreen.check.last) {
            GFullscreen.check.last.className = (space+GFullscreen.check.last.className+space).replace(space+classname+space,' ');
            if(GFullscreen.check.last.className == space) GFullscreen.check.last.className = '';
            return;
        }
        setTimeout(GFullscreen.check,100);
    };
    GFullscreen.compat = function(affix) {
        if(typeof(GFullscreen.compat.names) == 'undefined') GFullscreen.compat.names = {};
        if(typeof(GFullscreen.compat.names[affix]) == 'undefined') {
            GFullscreen.compat.names[affix] = [];
            var prefixes = ['','webkit','moz','o','ms'];
            var methods = ['fullscreen','Fullscreen','fullScreen','FullScreen'];
            var affixes = [affix,affix.substr(0,1).toUpperCase()+affix.substr(1)];
            var alternative = '';
            if(affix == 'request') alternative = 'enter';
            if(affix == 'cancel') alternative = 'exit';
            if(alternative != '') {
                affixes.push(alternative);
                affixes.push(alternative.substr(0,1).toUpperCase()+alternative.substr(1));
            }
            for(var p=0; p<prefixes.length; p++)
            for(var m=0; m<methods.length; m++)
            for(var a=0; a<affixes.length; a++)
                GFullscreen.compat.names[affix].push(prefixes[p]+(affix=='element'?'':affixes[a])+methods[m]+(affix=='element'?affixes[a]:''));
        }
    
        var obj = affix == 'request' ? document.documentElement : document;
        for(var n=0; n<GFullscreen.compat.names[affix].length; n++) {
            var name = GFullscreen.compat.names[affix][n];
            if(typeof(obj[name]) != 'undefined') {
                if(GFullscreen.compat.names[affix].length > 1) GFullscreen.compat.names[affix] = [name];
                return name;
            }
        }
        return null;
    };
    

    Démonstration

    Un peu de HTML

    <div id="g_fulldemo">
        <input type="button" id="g_fulldemo_handler" value="Démo" />
        Je suis le texte contenu dans le div mis en plein écran si vous cliquez sur le bouton !
    </div>
    

    Un peu de JS

    $ = function(id){return document.getElementById(id);}
    GFullscreen($('g_fulldemo_handler'),$('g_fulldemo'));
    

    Résultat :

    Et ensuite ?

    Ensuite il n’y a plus qu’à attendre que la spécification soit terminée et que tous les navigateurs fasse la même chose.
    Pour l’instant vous pouvez voir où en est qui sur caniuse.com

    5 réflexions au sujet de « [JS] API Fullscreen : déclencher le plein écran »

      1. Geompse Auteur de l’article

        Bonjour JC ! Sous IE 11 impossible de tester, à cause d’une allergie terrible. Toutefois sous Firefox 25.0.1 cela fonctionne (Firefox : http://up.neissa.org/5f4G2), bien que pas de la même façon (Chrome : http://up.neissa.org/6eiFJ). Je passe rapidement là dessus (cf paragraphe « Et ensuite ? » > « attendre [..] que tous les navigateurs fassent la même chose ») ; c’est hélas encore une nouveauté bien que maintenant l’API date quelque peu, et de là à ce que ce soit standardisé il va falloir se faire des cheveux blanc… Merci d’avoir participé !

        Répondre
    1. niconil

      interessant, et marche avec firefox (récent v30)
      merci pour ce script

      si j’ai bien compris pas de css à coder spécifiquement

      par contre ne marche pas avec mon firefox corporate (17.0.2 ESR) ?
      alors que la page « caniuse/fullscreen  » indique support partiel depuis la version 10 jusqu’à la version actuelle.
      existe-t-il une solution ? ou dois-je attendre un demi siecle pour que ma boite change de version du navigateur 🙂 (humour)

      Répondre
      1. Geompse Auteur de l’article

        En effet, ça ne marchait pas dans Firefox 17.0.2 ; voici ce qui était fait : document.documentElement.mozRequestFullScreen.apply($(‘#g_fulldemo_handler’));
        Firefox 17.0.2 et surement d’autres versions renvoyait l’erreur « NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object ».

        J’ai modifié l’article pour avoir ceci, qui ne déclenche plus d’erreur sous Firefox 17.0.2 :
        $(‘#g_fulldemo_handler’)[‘mozRequestFullScreen’]();

        J’ai vérifié qu’avec cette modification ça fonctionne aussi sous Firefox 30.0 et 31.0 et surtout sous Chrome 36.
        Merci d’avoir signalé le problème ! Attention Firefox et Chrome dans leurs dernières versions n’ont toujours pas le même comportement donc il faut encore ajouter un peu de CSS pour avoir un résultat identique.

        Répondre

    Laisser un commentaire

    Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *