Archives pour la catégorie Non classé

[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

    [HTML] Tableau scrollé à en-têtes fixes

    Bonjour,

    Nous allons étudier un cas simple, un tableau avec plusieurs colonnes dont la hauteur est fixe et dont le contenu doit pouvoir défiler.

    <table>
    	<thead>
    	<tr>
    		<th>header1</th>
    		<th>header2</th>
    		<th>header3</th>
    		<th>header4</th>
    		<th>header5</th>
    		<th>header6</th>
    		<th>header7</th>
    	</tr>
    	</thead>
    	<tbody>
    	<tr>
    		<td>1azdad</td>
    		<td>2a</td>
    		<td>azdazdazdaz dzad azd azd azd az</td>
    		<td></td>
    		<td>azdazdazdzadaz</td>
    		<td>az dzad azd zad zad zadzad </td>
    		<td>7</td>
    	</tr>
    	</tbody>
    </table>

    Rien d’extravagant.

    La première des astuces va être de mettre le tableau dans un div, table avec une hauteur 100% et le div avec une hauteur de 100% également.
    Mais pourquoi ?! Les table ne supportent pas la propriété CSS overflow du coup si nous voulons une barre de défilement il faut mettre un div autour avec comme CSS
    overflow-y:auto; height:100%

    <div class="table_scroll">
    <div class="header_table"></div>
    <div class="div_table">
    <table>
    	<thead>
    	<tr>
    		<th><div class="h">header1</div></th>
    		<th><div class="h">header2</div></th>
    		<th><div class="h">header3</div></th>
    		<th><div class="h">header4</div></th>
    		<th><div class="h">header5</div></th>
    		<th><div class="h">header6</div></th>
    		<th><div class="h">header7</div></th>
    	</tr>
    	</thead>
    	<thead>
    	<tr>
    		<th><div class="hh">header1</div></th>
    		<th><div class="hh">header2</div></th>
    		<th><div class="hh">header3</div></th>
    		<th><div class="hh">header4</div></th>
    		<th><div class="hh">header5</div></th>
    		<th><div class="hh">header6</div></th>
    		<th><div class="hh">header7</div></th>
    	</tr>
    	</thead>
    	<tbody>
    	<tr>
    		<td>1azdad</td>
    		<td>2a</td>
    		<td>azdazdazdaz dzad azd azd azd az</td>
    		<td></td>
    		<td>azdazdazdzadaz</td>
    		<td>az dzad azd zad zad zadzad dzadad za dzad za</td>
    		<td>7</td>
    	</tr>
    	</tbody>
    </table>
    </div>
    </div>

    un tout petit peu de CSS pour agrémenter tout cela :

    /* reset CSS */
    table, td ,th{ border:1px solid red;}
    th, tr{ padding:0; margin:0; border:0;}
    table{  width:100%; border-collapse: collapse;}
    
    .table_scroll{ position:relative; padding-top:20px; height:250px; overflow:hidden;}
    .table_scroll .header_table{ position:absolute; top:0px; background:blue; height:20px;}
    .table_scroll .div_table{ overflow-y:auto; height:100%}
    
    .h{ position:absolute; top:0;padding-left: 5px;margin-left: -5px;}
    .hh{ height:0px; visibility:hidden;}

    Maintenant les explications :

    On met un padding à ce « table_scroll » afin de pouvoir loger le header fixe à cette place.
    Le « table_scroll » est en « relative » pour que nous puissions mettre les div avec la class « h » en « absolute » et qu’ils restent à l’intérieur de celui-ci.
    En les mettant en « absolute » le table va perdre leur dimension ( et ainsi changer la largeur des colonnes ) on rajoute donc un deuxième « thead » identique mais avec une « height » de 0px et une « visibility » hidden, les colonnes sont à la bonne largeur et le thead est bien au dessus de mon table.
    Une petite dose d’overflow-y:auto sur le div contenant le table et le tour est joué.
    Le div header_table permet de mettre un background à notre thead.

    On peut le faire beaucoup plus joliment avec des sélecteurs CSS, des :before, etc, mais là nous avons le mérite de fonctionner sur presque tous les navigateurs.

    DEMO

    Aide à la saisie de chèques

    Le français est une langue pleine de subtilités, en particulier à l’écrit. Une caractéristique est l’écriture des nombres, citons entre autres :

    • 20 : vingt ; 80 : quatre-vingts ; 84: quatre-vingt-quatre
    • 41 : quarante et un ; 61 : soixante et un ; 81 : quatre-vingt-un
    • 100 : cent ; 200 : deux cents ; 1000 : mille ; 2000 : deux mille

    Bref si c’est intuitif pour les plus vétérans, c’est un véritable casse-tête pour un développeur. Et justement, cette semaine, mon travail m’a amené à devoir me plier à cet exercice complexe.

    Pour rendre ce développement ludique, je vous propose cet outil (http://cheque.neissa.org/) permettant de faire un chèque sans se tromper… mais attention, même si les règles sont correctement appliquées, rien n’empêchera une personne tierce de vous signaler une faute 😉

    N’hésitez pas à signaler ici toute erreur… à l’avenir, les règles utilisées seront explicités en dessous du chèque virtuel.

    URL courte : lien.neissa.org

    Pour obtenir à partir d’une longue URL (comme celles de Google Drive) une plus courte, je vous propose cet outil : lien.neissa.org

    Il fait pareil que beaucoup d’autres outils en ligne, mais étant hébergé chez nous il nous est possible de :

    • personnaliser l’interface
    • modifier un lien à posteriori
    • choisir le nom du lien

    L’interface actuelle est la plus simple, épurée possible. Elle utilise la librairie maison Mini.JS pour laquelle je ferais un article un jour.

    Envoyer deux fois le même lien retournera la même url raccourcie. Les identifiants générés suivent la même logique que pour notre outil d’envoi de fichiers.

    Évolution future : pouvoir copier coller un lot d’URL (ex : une URL par ligne).

    Envoi de fichiers : up.neissa.org

    Au quotidien, j’ai souvent besoin de transférer des fichiers. Une ressource à déposer sur un serveur, une capture d’une partie de l’écran à joindre au gestionnaire de tickets, un fichier à utiliser sur un autre poste du réseau, un document à envoyer à des amis…

    Il existe une foultitude d’outils permettant de faire toutes ces actions mais peu les font toutes et peu les font parfaitement. Compression des images ? Retouches ? Envoi multiple ? Création d’archives (ZIP) ? Génération d’un lien court ? Pas de limite de taille ? Placement du lien dans le presse-papier en un clic ?

    C’est en ligne qu’on trouve les outils répondant le mieux à ce « cahier des charges », et étant développeur HTML5/PHP je n’ai pas résisté trouvé meilleure idée que d’en faire un moi-même : up.neissa.org.

    Ergonomie

    L’interface doit être agréable, pour ne pas dégoûter, pour cela elle doit être la plus simple possible… mais doit permettre de tout faire : drag & drop, ctrl+v ou sélection depuis le disque. L’outil doit être intuitif pour ne pas nécessiter d’expliquer comment on s’en sert !

    Ainsi s’il est indiqué qu’il faut déposer un fichier dans le cadre vert, il est en fait possible de déposer ce fichier n’importe où dans la page. De même, il est indiqué « Envoi de fichiers » alors qu’en collant (ctrl+v) le texte du presse papier sera envoyé.

    Si une image est envoyée, sa miniature apparaît sous l’interface. En cliquant dessus, il est possible de sélectionner un fragment de l’image originale à envoyer. À moins de décocher la case correspondante, les images envoyées seront au préalable compressées (taille réduite jusqu’à tenir dans un carré de 1280×1280, et mise en JPEG ou en PNG).

    Une fois envoyé, le lien vers le fichier (ou vers les fichiers, zippés) peut être copié en un clic. Ce n’est pas proposé automatiquement car c’est impossible parce que ce n’est peut être pas voulu (cas du redimensionnement).

    Les URLs générées doivent rester courtes, de manière à pouvoir ctrl+c/ctrl+v avec les yeux d’un PC à l’autre du réseau 🙂

    Cible : Le but est que ça marche sur la dernière version stable de Google Chrome, après si ça fonctionne tout seul sur les autres navigateurs (de bureau comme mobiles), c’est un plus certain !

    Technique

    Coté client j’ai utilisé du HTML5 et du Javascript, coté serveur du PHP. C’est mon choix 🙂 Pour copier-coller j’ai utilisé du Flash mais déjà tout fait, fourni par ZeroClipboard (merci).

    Drag & Drop : les events dragenter/dragover/dragleave sont désactivés, et drop est écouté. En accédant à event.dataTransfer.files, on obtient un tableau FileList contenant les fichiers dans des objets File.

    Ctrl+V : l’event paste est écouté. En accédant à event.clipboardData.files et event.clipboardData.items on récupère les données associées au presse-papier respectivement sous formes d’objets File et DataTransferItem. Attention la politique de sécurité du navigateur peut interférer et il n’est ainsi pas possible de copier coller un fichier depuis l’explorateur vers le navigateur… Les DataTransferItem peuvent être convertis en File ou en DomString (selon le type) via les méthodes getAsFile et getAsString.

    Sélection depuis le disque : la balise HTML <input> suffit. Pour permettre la sélection de plusieurs fichiers n’oublions pas l’attribut multiple= »multiple » et remercions le HTML5. Plutôt que d’écouter l’event change, j’ai préféré utiliser un formulaire avec un bon vieux bouton submit. Ainsi il est possible de corriger sa sélection avant d’envoyer les fichiers, ce qui est un peu plus fair play vis à vis de l’utilisateur. L’event submit est donc écouté, et c’est l’attribut files ($moninput.files) qui est un tableau FileList contenant les fichiers dans des objets File.

    Compression des images : les File dont le type correspond à une image sont lus sous forme de « Data URI« , et pour cela c’est l’objet FileReader qui est utilisé. Le résultat lors du loadend est défini comme source d’une image <img> créée à la volée. Au load de l’image, cette dernière est dessinée redimensionnée dans un <canvas>. La méthode canvas.toDataURL(mime) permet d’obtenir une « Data URI » recompressé de l’image redimensionnée. Il faut convertir ce « Data URI » en Blob pour continuer. Si la taille du Blob est plus petite que celle du File originel, c’est le Blob qui sera envoyé.

    Convertir une « Data URI » en Blob : c’est probablement l’étape la plus complexe, puisqu’il faut parser la chaine de manière à en extraire les données, puis charger ces dernières dans un ArrayBuffer, qu’on pourra utiliser dans un DataView pour créer un Blob. Sauf si comme dans Firefox 14 DataView n’existe pas, auquel cas on utilisera MozBlobBuilder qui est obsolète mais fonctionne très bien.

    dataURItoBlob = function(data)
    {
      var pos = data.indexOf('base64,');
      var mime = data.substr(0,pos).split(':')[1].split(';')[0];
      var bin = atob(data.substr(pos+7));
      var buff = new ArrayBuffer(bin.length);
      var conv = new Uint8Array(buff);
      for(var i=0; i<bin.length; i++)
        conv[i] = bin.charCodeAt(i);
    
      if(typeof(Blob) != 'undefined')
        if(typeof(DataView) != 'undefined')
          return new Blob([new DataView(buff)],{type:mime});
    
      if(typeof(BlobBuilder) == 'undefined')
        if(typeof(WebKitBlobBuilder) != 'undefined')
          BlobBuilder = WebKitBlobBuilder;
      if(typeof(BlobBuilder) == 'undefined')
        if(typeof(MozBlobBuilder) != 'undefined')
          BlobBuilder = MozBlobBuilder;
      if(typeof(BlobBuilder) == 'undefined')
        return alert('impossible de creer un blob a partir du base64');
    
      var builder = new BlobBuilder();
      builder.append(buff);
      return builder.getBlob(mime);
    }

    Fragmentation des données : si la taille des données à envoyer est supérieure à 4Mo, elles vont être découpées en morceaux de 4Mo maximum (pour un fichier de 25Mo : six fragments de 4Mo et un fragment de 1Mo). Pour cela le Blob/File en entrée est lu dans un FileReader, et le résultat au loadend est découpé via la méthode Blob.slice(start,end). On se retrouve donc avec 7 Blob. Pour pouvoir les rassembler coté serveur on fait tout de suite une requête Ajax de manière à obtenir un identifiant unique pour le lot.

    Envoi des données : il s’agit d’une requête Ajax, donc via l’objet XMLHttpRequest. On utilise la méthode open(mode,uri,async) en mode POST et évident en asynchrone. Il vaut mieux définir le Content-Type à multipart/form-data via la méthode setRequestHeader(key,value). J’ajoute aux en-têtes le nom, le type et la taille du fichier, mais aussi dans le cas de la fragmentation l’identifiant du lot, le numéro de fragment et le nombre total de fragments. Les données sont envoyées simplement via la méthode send(file), comme on l’aurait fait pour des données POST classique.

    Mise en file d’attente : étrangement en faisant glisser les 30 photos d’un coup, leur compression et leur envoi fige complètement le navigateur (vous avez dit « sandbox » ?). C’est parce que toutes les méthodes de lecture et d’écriture sont asynchrones. Pour pallier à ce phénomène j’ai construit deux files d’attentes, une pour la compression et une pour l’envoi. En clair, pas le droit de compression plus d’une image à la fois ou d’envoyer plus de 4 fragments à la fois. C’est surement un tout petit peu plus lent, mais au moins le navigateur reste disponible.

    Découpe d’image : en envoyant une image j’ai créé un objet <img>, que j’affiche en fait en dessous de l’interface. En cliquant dessus je l’affiche en taille réelle, et je propose de sélectionner deux coordonnées via un curseur fait avec deux <div>. L’image étant toujours dans le <canvas> il suffit d’en extraire la découpe, et de la traiter comme un nouveau Blob à envoyer.

    [PHP] key(), génération d’un identifiant : les identifiants ne doivent pas être consécutifs de manière à rendre complexe la découverte d’un autre fichier en possédant un premier fichier. De plus ils doivent être courts pour être mémorisables. Il faut aussi pouvoir envoyer un nombre conséquent de fichiers. J’ai donc choisi de générer 5 caractères, chacun parmi 0-9, a-z et A-Z. Ainsi il est possible d’envoyer 1 milliard de fichiers, et si cette limite est atteinte je passerais à 6 caractères : 60 milliards de fichiers. Aujourd’hui, après 6 mois d’utilisation, il y a 1600 fichiers envoyés… soit 10 fichiers par jour environ.

    [PHP] set(data), envoi : en utilisant $_SERVER pour récupérer les valeurs définies dans les en-têtes et file_get_contents(‘php://input’), on récupère toutes les données nécessaires au traitement du fichier. L’identifiant généré est renvoyé de manière à proposer le lien à l’utilisateur. Le dossier de stockage ne doit pas être accessible, ainsi on peut librement envoyer des scripts .php par exemple.

    [PHP] get(id), récupération : en utilisant $_REQUEST pour obtenir l’identifiant, il est facile de renvoyer le fichier correspondant. Il ne faut pas oublier de contrôler que l’identifiant correspond bien à un fichier envoyé…

    Conclusion

    Je me suis bien amusé à faire cet outil ! Il y avait beaucoup de notions à comprendre et surtout j’ai découvert que c’est vraiment utile. Depuis j’en ai un usage quotidien. J’ai même découvert que ALT+ImprEcran fait une capture de la fenêtre en cours et non de tout l’écran (mais ça n’a rien à voir hein).

    Une fonctionnalité à implémenter serait de pouvoir choisir l’identifiant généré au moment de l’envoi, bien qu’aujourd’hui ce soit déjà possible pour un administrateur de déplacer un fichier envoyé de manière à lui donner un nom plus facile à retenir.

    Pour finir je rajouterais que j’ai fait des choix techniques importants, en ne proposant qu’un fichier (au lieu de référencer JS et CSS) je suis certain que les utilisateurs ont la dernière version du code, et qu’elle n’a pas été altérée par exemple par SFR s’ils utilisent une connexion 3G. Ou encore en n’utilisant pas de base de données de manière à avoir un outil portable dont la sauvegarde est simple à mettre en oeuvre.

    Internet Explorer 9

    En ce moment passe en boucle cette publicité pour IE9 (sur le site n’oubliez pas de scroller ça vaut le détour).

    Utilisant Google Chrome depuis plusieurs années, et avant Mozilla Firefox, j’ai tout de suite noté que les vidéos présentes dans la pub laggent énormément… mais surtout j’ai été choqué par les citations.

    Bon, je peux comprendre que pour vendre un produit tout bon commercial cherchera à enjoliver la vérité et à amoindrir les défauts, mais tout de même, le contexte de ces citations doit forcément révéler qu’IE9 est… IE9 !

    « Internet Explorer 9 est moderne » – Clubic

    http://www.clubic.com/navigateur-internet/internet-explorer/article-397622-1-test-internet-explorer-9.html (15 Mars 2011)

    « De solides arguments technologies  » – LaTribune.fr

    http://www.latribune.fr/technos-medias/20110315trib000607923/microsoft-muscle-internet-explorer-pour-contrer-firefox-et-google.html  (15 Mars 2011)

    « Internet Explorer 9 … de loin le meilleur  » – PC Magazine

    Source… introuvable : le magazine n’existerait plus ?

    « Internet Explorer est rapide, design et moderne  » – Wired

    Source… traduite de l’anglais.

    « Epingler ses sites préférés est très utile  » – Journal du Net

    Source… introuvable.

    Conclusion

    Les deux sources trouvées mettent bien en avant que les mélioratifs s’applique en comparant IE9 à IE8 (ou inférieur). Il faut en fait lire « IE9, de loin le plus meilleur/rapide/design/moderne/technologique/fonctionnel des IE »…

    De plus les deux sources date de la sortie d’IE9 en France, le 15 Mars 2011, il y a un an, à l’époque de Firefox 4 et de Chrome 10. Aujourd’hui on peut considérer que toutes les caractéristiques de ces navigateurs ont été (au moins) doublées…

    En cherchant j’ai trouvé le blog de Rob Dudley, qui a eu la même idée mais avec la version américaine de la pub. Apparemment aux US Microsoft n’a pas hésité à utiliser des citations du 15 Septembre 2010, le jour de la sortie de la version « RC » en Amérique. Une version Release Candidate est une pré-version, permettant aux acteurs du marché de se faire une idée du produit pas encore finalisé.

    Pour aller plus loin

    Au vu de ces deux dates je me suis rendu compte que le débat autour des navigateurs n’est pas fondé sur de bonnes bases. En effet on parle souvent des performances alors que le point le plus déterminant est la fréquence des mises à jour. On peut considérer que Microsoft sort autant de correctifs que Chrome ou Firefox, mais concernant les versions majeures, proposant de nouvelles fonctionnalités ?

    Sur Wikipédia on trouve un document SVG retraçant l’évolution des navigateurs. Hélas pour le débat IE/FF/Chrome, voir les autres navigateurs (comme Lynx) gêne. De plus il n’est pas à jour.

    J’ai donc repris ce document pour en proposer la version ci-dessous facilitant la comparaison des versions majeures (cliquez pour agrandir).

    Et si vous voulez quand même comparer les navigateurs, ça se passe ici