Julien Dollon | [HTML5] TP pour développeur migrant sur HTML5

A goal without a plan is just a wish

My blog in english is here.

Je m’appelle Julien, j'ai 27 ans et je suis un ingénieur logiciel et secondairement manager d'Hommes/projets. Je concois les produits et services de demain. J'ai entre autre participé au developpement de Windows, XBOX, Office, Surface chez Microsoft (Redmond) et je suis maintenant chez Amazon AWS (Seattle) pour Marketplace/EC2/Workspace.

Je travaille dur pour un jour avoir un grand impact sur ce monde.

Mais comme il n’y a pas de titans à combattre, que les monstres n’existent pas, je fais du dev sur des produits, qui je l’espère, vous apporteront de la joie.

Plus d'infos sur moi ici.

 

View Julien  Dollon's profile on LinkedIn

Tous les posts de ce blog ne reflètent que mon opinion et pas celui de mes employeurs et clients.

 

Service d'evaluation de competences et de creation de site webs sur cahors.

[HTML5] TP pour développeur migrant sur HTML5

Introduction

Suite a mon article expliquant que HTML5 allait devenir le Golden Language pour faire du B2C, il me fallait réagir et vous proposer un post sur le sujet!

Ce billet est a destination des développeurs .NET/XAML souhaitant passer sur tout ce qui gravite autour de HTML5.

Le but sera de concevoir une sorte de “home” a la Windows 8, avec des tuiles pour afficher les derniers billets d’un flux RSS, avec version pour mobile/tablette ainsi qu’une version offline et Windows 8.

Mais pour bien commencer, je vous recommande de regarder cette vidéo pour avoir une vue d’ensemble de ces langages:

Fonctionnalité et design

Le but de cette application va être de créer un site d’agrégation:

  • Un design métro, avec un fond avec photo aléatoire
  • Une compatibilité IE10/Mozilla/Chrome/Tablette iPad et Android
  • La possibilité d’ajouter la page en favoris, favicon and co
  • Deux box, l’une présentant les flux RSS de mes deux blogs
  • L’autre étant des liens vers projets et autres
  • Le tout dans des tuiles animées en CSS3
  • Version offline et stockage des articles hors ligne
  • Utilisation d’un maximum de features HTML5
  • Version spéciale compilée Windows 8 (sera l’objet d’un autre poste)
  • Version optimisée pour téléphone avec Media Queries et KendoUI
  • Utilisation d’un max de Framework du moment comme LESS/Knockout.js and co
  • Consommation de toutes les données sur un service Node.js

julien_thumb2

Développement

Création de la structure de la page en HTML5

La première chose que je vais réaliser, est la structure de la page. HTML5 apporte son lot de nouvelles balises comme <header>, <nav> et bien d’autres mais cela ce comporte comme des divs.

Ma page HTML5 va ressembler à cela:

image_thumb3

La structure reste simple: un header, un footer et au milieu un contenu représenté par une bullet liste.

Le header prendra cette forme:

<header id="headertop">
    <div id="backgroundtitle">
        <img src="Assets/images/logo.png" />
    </div>
                    

    <div id="title">
        <img src="Assets/images/logo2.png" /><label>  Home</label></div>
 
    <div id="loginbox">
        <div id="username"></div>
    </div>       
</header>

Le footer, tout aussi simple:

<footer id="bottomfooter">
    <div id="plusmenu">
        <img src="Assets/images/heart.png" /></div>
</footer>

Et au milieu, une bullet liste, avec pour chaque petites tuiles une <div>:

<div id="box3">
                        <nav class="navitems , secondnavitems">
                            <header class="headerclass">Projects</header>
                            <ul>
                                <li>
                                    <div class="box">
                                        <div class="image"><img src="" alt="" /></div>
                                        <div class="nomapp">Blog</div>
                                    </div>
                                </li>
//etc...

Organisation de la page avec CSS3

Avant de commencer, je vous conseil vivement de travailler avec LESS. LESS est un framework JS ou un compilateur CSS permettant d’améliorer le langage. Il est désormais possible de déclarer des variables, faire des conditions, de l’héritage… Pour l’exploiter plusieurs solutions: soit en JavaScript, qui se chargera au runtime de “compiler” le CSS. Soit en utilisant un outil qui le fera avant la publication du site. Si vous êtes sous Visual Studio, une extension existe: Dotless mais j’ai un petit faible pour http://crunchapp.net/.

image_thumb5[1]

Le CSS3 apporte son lot de nouveautés très appréciables.

J’ai eu l’occasion d’en utiliser quelques unes:

Importation de font

@principalfont: Segoe UI;

@font-face
{
	font-family:@principalfont;
	src: url('../Font/SEGOEUI.TTF');
}

Personnalisation d’une scrollbar

::-webkit-scrollbar {
    width: 12px;
    background-color:Gray;
}

::-webkit-scrollbar-track {
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
    border-radius: 10px;
}

::-webkit-scrollbar-thumb {
    border-radius: 10px;
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
}

Utilisation des animations

.anim {
	  -webkit-animation: monanim 80s infinite;
	  -moz-animation: monanim 80s infinite;
	  -ms-animation: monanim 80s infinite;
	  -o-animation: monanim 80s infinite;
	  animation: monanim 80s infinite;
	}

Sélection de contrôles et états

#username:hover
{
	opacity: 1;
}

.navitems > ul > li:nth-child(3n) > div
{
	background-color:   #db532b;
	
}

Utilisation de Box pour aligner les éléments

#site
{
	display: box; /* not supported by IE9, use table if we want IE support */
	box-orient:horizontal;
	box-pack:left;
	box-align:top;

	/* Firefox */
	display:-moz-box;
	-moz-box-orient:horizontal;
	-moz-box-pack:left;
	-moz-box-align:top;

	/* Safari and Chrome */
	display:-webkit-box;
	-webkit-box-orient:horizontal;
	-webkit-box-pack:left;
	-webkit-box-align:top;
	
	/* futur IE10, that's sucks */
	display: -ms-box;
}

Transformations 3D pour simuler un effet tilt:

.tilt {
    -webkit-transition: -webkit-transform 0.1s linear;
    -webkit-transform: rotate3d(20, 100, 0, -20deg);
    -moz-transition: -moz-transform 0.1s linear;
    -moz-transform: rotate3d(20, 100, 0, -20deg);
    -o-transition: -o-transform 0.1s linear;
    -o-transform: rotate3d(20, 100, 0, -20deg);
    -ms-transition: -ms-transform 0.1s linear;
    -ms-transform: rotate3d(20, 100, 0, -20deg);
    transition: transform 0.1s linear;
    transform: rotate3d(20, 100, 0, -20deg);
}

Résultat avec le CSS:

image_thumb8

Quelques codes JavaScript ont du être ajoutés pour mettre en forme certaines choses, par exemple pour coller la barre de défilement par rapport a la div <content>:

Avant image_thumb9, après image_thumb10

A ce stade, l’intégralité du code se trouve ici:

http://julien.dollon.net/html5/beta/

Vous pouvez le tester exclusivement avec Mozilla/Chrome/IE11 car mon composant Box n’est supporté que par les derniers navigateurs.

Capter le scroll de la souris et le clavier

J’ai voulu que le scroll de la souris provoque non pas le défilement en vertical de la page, mais en horizontal.

Pour cela il a fallut capter MouseWheel de la souris, trouver le sens, annuler la propagation de l’évènement pour annuler le défilement de la fenêtre et simuler le défilement de manière horizontal sur la div principale.

var iScroll = 0;
var lastScroll = 0;

$('#content').bind('mousewheel', function(event, delta) {

    $(this).scrollLeft(100 * -delta + (100 * iScroll));

    //Si a la fin
    if (!($(this).scrollLeft() == lastScroll)) {
        iScroll += -delta;
    }
    lastScroll = $(this).scrollLeft();

    event.stopPropagation();
});

Il peut être aussi intéressant de capter les évènements du clavier pour reproduire la même action. Forcement comme dab’ chaque navigateurs implémentent les évènements comme ils le veulent…

            $(document).bind('keydown', function (event) {

                event = event || window.event;
                var key = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
                switch (key) {
                    case 37: // left arrow key
                        ScrollAnimated(5);
                        break;
                    case 39: // right arrow key
                        ScrollAnimated(-5);
                        break;
                }
                event.stopPropagation();
            });

Proposer un bouton “fullscreen”

Voici un petit script pour mettre le site en fullscreen.

function InitFullScreenButton() {
    $("#pluscentre").click(function () {
        //Chrome/Safari
        if (document.body.webkitRequestFullScreen != null)
            document.body.webkitRequestFullScreen();
        //Mozilla
        else if (document.body.mozRequestFullScreen != null)
            document.body.mozRequestFullScreen();
        //Opera
        else if (document.body.oRequestFullScreen != null)
            document.body.oRequestFullScreen();
        //IE11
        else if (document.body.msRequestFullScreen != null)
            document.body.msRequestFullScreen();
        else if (document.body.requestFullscreen != null)
            document.body.requestFullscreen();
        else
            alert("Your bullshit browser doesn't support the fullscreen features");
    });

Création d’une tuile avec Adobe Edge

Pour la tuile, il existe deux solutions.

Dans un premier temps, je vais utiliser Edge en Preview de Adobe afin de vous montrer les capacités de ce logiciel. Edge est une sorte de Expression Blend version HTML5/JavaScript (jQuery pour être plus précis).

L’avantage de cet outil est qu’il ressemble fortement a Blend. L’inconvénient est que les animations ne sont pas faites pour être éditées par la suite, c’est pourquoi, dans une second temps, je préfère opte pour une tuile faite main.

Apres avoir lancé Edge, je crée un nouveau projet et  je commence par dessiner un petit rectangle représentant ma tuile:

image_thumb1

image_thumb4

image_thumb15
image_thumb20
Je configure mon rectangle (qui est en réalité une div) grâce au panneau de gauche.

Changement de curseur par une main.

Positionnement en haut a gauche.

Mise en place du “Clip” pour que tout ce qui déborde de la div ne s’affiche pas.

Changement de la couleur de fond.

J’insère ensuite un texte et une image avec cette hiérarchie:

image_thumb23

image_thumb26

Puis j’anime la div appelée secondRect en enregistrant son positionnement en Y. Pour cela, il faut faire un clique droit sur secondRect->Add Key Frame->Translate(Y).

Puis grâce au storyboard viewer du bas, j’anime le tout.

image_thumb29

Il faut ensuite mettre un peu d’easing animation pour rendre le tout plus naturel.

image_thumb32

Ainsi qu’un trigger pour capter la fin de l’animation et la relancer.

image_thumb35

 

Création de la tuile “a la main”

Pour cela, j’utilise les animations CSS3, c’est a dire un KeyFrame definissant une translation sur une division.

En HTML, la tuile est représentée comme ceci:

<div class="box">
   <div class="imageXL"><img src="assets/images/windows.png" alt="" /></div>
   <div class="nomappXL">Kinect</div>
</div>

L’objectif étant d’avoir ceci (3 états, la durée de l’animation variant suivant la tuile):

image_thumb12image_thumb16image_thumb201

L’animation CSS3 est définie de cette manière:

@keyframes tuileTranslation {
	0% 
	{
		transform: translateY(0em);
	}
	25% 
	{
		transform: translateY(-3.75em);
	}
	75% 
	{
		transform: translateY(-7.5em);
	}
	100%
	{
	    transform: translateY(0em);
	}
}

La div “mère” est clipped avant de ne pas voir l’image déborder lors de la translation:

.box > .image
{
    width:80px;	
    height:80px;
    margin: auto;
    clip:rect(15px, auto, auto, auto);
}

Et le JavaScript s’occupe d’initialiser l’image de la div pour la mettre en “background” (plus facilement manipulable pour moi). Il lance aussi l’animation CSS3 avec un temps “aléatoire”:

    $(".imageXL").each(function () {
        /* animation for tiles with random duration */
        var randomnumber = Math.floor(Math.random() * 6) + 1;
        $(this).css('animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
               .css('-moz-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
               .css('-webkit-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
               .css('-ms-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
               .css('-o-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
               .next(".nomappXL")
                    .css('animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
                    .css('-moz-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
                    .css('-webkit-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
                    .css('-ms-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
                    .css('-o-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite');


        /* initilization of the background of the div depending of the image in it */
        $(this).find("img:first").css("visibility", "hidden");
        var imageUrl = $(this).find("img:first").attr("src");
        $(this).css('background-image', 'url(' + imageUrl + ')');
    });

Mise en place d’un fond METRO

Le but est d’afficher de manière random, un léger fond en mouvement.

Nous allons utiliser les animations et transformations CSS compatibles avec les derniers browser du marche (sauf IE9 –> voir IE10).

Mise en place du code HTML:

    <body onload="MaMethod();">
        <div id="container">
            <div id="fond">
                <img src="D3B_2156q.jpg" id="img" alt=""/>
            </div>
            <div id="site">
               <!-- Site ici -->
            </div>
        </div>
    </body>

La div “fond” représente l’image à afficher, le reste du site étant place dans “site”.

Body va appeler une fonction JavaScript permettant d’attribuer au chargement de la page, une classe CSS à “fond” qui déclenchera l’animation.

    <script>
        function MaMethod() {
            var div = document.getElementById("fond");
            div.setAttribute("class", "anim");
        }
    </script>

La partie CSS reste simple:

body 
{
    padding: 0;
    margin: 0;
    background-color: black;
    overflow-y: hidden;
}

#fond > img {
    opacity: 0.5;
    position: fixed;
}
.anim {
      animation: monanim 60s infinite;
    }

@keyframes monanim {
    0% {
           transform: translateY(0em);
           transform: translateX(0em);
    }
    25%{
           transform: translate(-15em,-5em);
    }
    75% {
           transform: translate(-15em, -10em);
    }
    100% 
    {
           transform: translate(0em, 0em);
    }
}

#site 
{
    background-color: transparent;
    width: 2000px;
    height: 700px;
    opacity: 0.5;
}

Le résultat:

http://julien.dollon.net/html5/fond/index.htm

image_thumb21

Création du service Node.js

Introduction

Il y a dix ans, quand j’ai comence le JavaScript, la première chose qu’on m’a appris: Le JS tourne cote client.

Et bien plus maintenant! Node.js est l’un des nombreux Framework permettant de faire des services avec JavaScript.

Je conseil l’editeur en ligne si vous voulez tester/debuguer du node.js: http://c9.io/

Les avantages d’utiliser Node.js sont:

  • Si vous avez du code JS a porter cote serveur, c’est très simple
    • Ici pas notre cas
  • Si vous êtes un pro du JS/dev web et que vous ne connaissez pas bien un langage d’Homme (Sourire) comme Java ou C#, node.js vous sauve la vie
  • Si vous voulez faire un service léger et rapide, restfull, avec CouchDB ou autre, un truc code a l’arrache from scratch c’est pas mal.

Les désavantages:

  • C’est du JavaScript. Autant cote client je comprends l’utilisation d’un langage dynamique est intéressant, mais la cote serveur c’est risque des erreurs dans tous les sens
  • L’API est clairement instable, et en plus manque d’optimisation (du style réutilise pas le thread courant pour re-exécuter un service etc…)
  • Manque de librairies, comment accéder a mon SQL Server? A mon API S3 ou Azure? etc… Les APIs dispos sont très maigres

Création du service

Le service doit être capable de retourner:

  • La dernière vidéo du compte Soumow de youtube
  • Les 5 derniers articles de mes blogs perso et pro
  • Mes 6 contacts réseaux sociaux
  • Mes 5 derniers projets

Le tout en JSON avec un service RESTFULL.

Je pourrais utiliser un routeur de requête type Journey, mais j’ai voulu me débrouiller de A a Z.

Je commence donc par initialiser mon fichier JavaScript:

var http = require("http");
var url = require("url");
var querystring = require("querystring");

var handle = { };
handle["/"] = rootCall;
handle["/lastarticles"] = lastArticles;
handle["/lastprojects"] = lastProjects;
handle["/lastvideo"] = lastVideo;
handle["/socialnetworks"] = socialnetworks;

Mon objet handle contient des pointeurs de fonctions vers les méthodes a appeler.

Je démarre ensuite un serveur sur le port 8888 et je route le tout (merci au livre sur Node.js).

function route(handle, pathname, request, response) {
    console.log("About to route a request for " + pathname);
    if (typeof handle[pathname] === 'function') {
        handle[pathname](request, response);
    } else {
        console.log("No request handler found for " + pathname);
        writeFast(response, "Error, no method found");
    }
}

http.createServer(function (request, response) {
    //
    var pathname = url.parse(request.url).pathname;
    console.log("Request for " + pathname + " received.");
    route(handle, pathname, request, response);
}).listen(8888);

Résultat, quand j’appelle l’url /socialnetworks, la fonction socialnetworks est appelée.

function socialnetworks(request, response) {
    response.writeHead(200, { "Content-Type": "text/json" });
    var socials = new Array();
    socials.push(new DataContractElement("Facebook", "fb.png", "", "https://www.facebook.com/julien.dollon"));
    socials.push(new DataContractElement("Twitter", "twitter.png", "", "https://twitter.com/#!/juliendollon"));
    socials.push(new DataContractElement("Google+", "google.png", "", "https://plus.google.com/110722800174049431616/posts"));
    socials.push(new DataContractElement("Linkedin", "linkedin.png", "", "http://www.linkedin.com/profile/view?id=7903132&trk=tab_pro"));
    socials.push(new DataContractElement("Resume", "", "", "http://julien.dollon.net/dollon_en.pdf"));
    socials.push(new DataContractElement("MVP Profil", "", "", "http://www.microsoft.com/france/communautes/annuaire/acteurs.aspx?auteur=Dollon"));

    response.write(JSON.stringify(socials));
    response.end();
}

De même pour les autres fonctions du service.

Pour le téléchargement des divers flux rss j’ai utilise la librairie Future qui permet de faire des ForeachAsync et des .Then() plutôt pratique.

La méthode permettant de retrouver la dernière video YouTube nécessite de faire une requête GET a l’API Youtube.

    var options = { host: "gdata.youtube.com"
			, path: "/feeds/api/users/" + account + "/uploads?v=2"
    };
    //make the request server side
    http.get(options, function (resp) {
        //console.log("hi",response);
        response.writeHead(200, { 'Content-Type': 'text/plain' });
        var pageData = "";
        resp.setEncoding('utf8');
        //stream the data into the response
        resp.on('data', function (chunk) {
            pageData += chunk;
        });

        //write the data at the end
        resp.on('end', function () {
            response.write(pageData);
            response.end();
        });

        });

Mise en place du service

Node.js est supporte par Azure mais comme ca coute un bras je vais opte pour un déploiement standard sur mon serveur perso avec IIS7.

Ce lien nous explique comment héberger un service node.js dans IIS:

http://www.amazedsaint.com/2011/09/creating-10-minute-todo-listing-app-on.html

En gros il faut:

Voici le résultat:

http://home.dollon.net/node/service/personalservice.js/

Comme en Silverlight et WCF, il faut initialiser le clientaccesspolicy.

Attention aux failles de sécurité avec une “*” en cas d’injection de code XSS.

response.writeHead(200, {
		'Content-Type': 'text/plain',
		'Access-Control-Allow-Origin' : '*'
	});

Typage du JavaScript et mode strict

A ce stade, J’ai commence a utiliser du JS par ci par la mais je n’ai pas fait attention au best practices.

Tout d’abord en terme d’architecture mais j’en parlerai a l’étape suivante.

Mais aussi en terme de typage et propreté du code.

Il existe un mode en JavaScript (ECMAScript 5) qui permet d’être dans un contexte plus stricte que celui de d’habitude. Cet environnement impose certaines règles de développement et désactives des fonctionnalités de JS pouvant être dangereuse.

Pour l’utiliser il faut rajouter:

"use strict";

Au niveau du scope du code a protéger.

Désormais, si j’utilise une variable non déclarée, j’aurai une erreur dans la console JavaScript:

image_thumb2

Plus d’infos sur le mode strict ici:

http://hacks.mozilla.org/2011/01/ecmascript-5-strict-mode-in-firefox-4/

Une deuxième chose qui existe et qui améliore le code JavaScript est TypedJS.

TypedJS permet d’annoter nos fonctions avec un commentaire précisant le type de retour et des params.

Ce commentaire est lu par des le lancement dans une console JS de “TypedJS.run_tests()”.

A noter que TypedJS supporte Node.js.

Mise en place de l’architecture avec Knockout.js

Depuis le début, je n’utilise aucune architecture. Normal cote front end, puisque que ce soit en MVVM en Silverlight ou JS, tant que le code touche des aspects purement graphiques, je le laisse dans la vue.

Sauf que la, je vais avoir du code pour consommer mon service! Je décide donc de partir sur Knockout.js.

Un seul lien pour l’apprendre: http://learn.knockoutjs.com/

Knockout fournis un framework MVVM avec tout ce qui tourne autours comme le Binding, Observables…

Pour l’installer, tout est explique ici: http://knockoutjs.com/documentation/installation.html

Notre ViewModel a besoin d’exposer:

  • Une propriété représentant la vidéo
  • Une collection de projets
  • Une collection de réseaux sociaux
  • Une collection d’articles
  • Une propriété IsBusy pour dire que le chargement est en cours
  • Une prop pour afficher si il y a une erreur

Tous les liens auront le même model (attention au context “this” qui peut bouger):

function DataContractElement(title, image, description, link) {
    var self = this;
    self.title = title;
    self.image = image;
    self.description = description;
    self.link = link;
}

On crée le ViewModel, ici par exemple avec une propriété Observable qui sera l’url vers la vidéo youtube:

"use strict";
function principalViewModel() {
    var self = this;

    self.isBusy = ko.observable(true);
    self.videoUrl = ko.observable("");
    self.error = ko.observable("");
    self.projects = ko.observableArray([]);
    self.sociallinks = ko.observableArray([]);
    self.lastarticles = ko.observableArray([]);

    $.ajax({
        type: "GET",
        url: lastvideourl,
        success: function (json) {
            var mapped = new DataContractElement(
                json[0].title, json[0].image, json[0].description, json[0].link);
            if (mapped.title == null) {//Bug Firefox
                mapped = new DataContractElement(
                JSON.parse(json)[0].title, JSON.parse(json)[0].image, JSON.parse(json)[0].description, JSON.parse(json)[0].link);
            }
            self.videoUrl(mapped.link);
            self.isBusy(false);
        },
        error: function (xhr, textStatus, errorThrown) {
            self.error(xhr.responseText);
        }
    });
}

On instancie, dans le load de notre page, le ViewModel de cette façon:

ko.applyBindings(new principalViewModel());

Et cote vue, on réalise un binding sur l’iframe de Youtube:

<iframe data-bind="attr: {src: videoUrl}"></iframe>

De même pour la liste des articles, sauf que cette fois ci je travaille avec un observableArray et des templates.

        <ul data-bind="foreach: lastarticles">
            <li>Name: <span data-bind="text: title"> </span>
        </ul>

Je termine avec la capture de l’évènement clic et ouverture du lien dans une popup:

<li data-bind="click: $parent.launchLink">

Téléchargement des images

Dans la version non public du site, j’ai voulu utiliser le web worker (un thread JS grâce a HTML5) pour télécharger les images de fond.

Le problème est que très peu de navigateur le supporte, mais si vous souhaitez voir comment j’ai fais pour downloader une image, c’est par ici:

http://www.html5rocks.com/en/tutorials/file/filesystem-sync/

Splash screen

Tout d’abord, je souhaite dessiner mon logo.

Pour cela deux options s’offre a moi:

Le canvas, qui va générer un bitmap, c’est a dire quelque chose de “plat” et fixe en 2d tel une image. Par default on dessine en 2D mais WebGL permet de faire de la 3D. On l’utilise avec une balise en HTML5 et on pilote le dessin avec JavaScript.

Les points positifs: performant, possibiliter d’exporter le resultat en image.

De l’autre cote, nous avons un format vectoriel, SVG, base sur du XML.

Les points positifs: j’ai déjà au format Illustrator mon logo, facile a  convertir en SVG, facilement animable.

Je decide donc de partir sur SVG. Je rajoute une progressbar (nouveauté HTML5) avec un petit skin CSS3 et un binding en MVVM sur la propriété isBusy:

<div id="loadingpage" data-bind="visible: isBusy"> <!---->

    <svg version="1.1" id="svglogo"
	        xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
	        x="0px" y="0px" width="500px" height="500px"  viewBox="-96.46 -235.46 595 842" 
	        xml:space="preserve">
    <defs>
    </defs>
    <polygon fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" points="115.874,202.54 115.874,65.874 180.54,1.207 
	    180.54,360.54 0.707,180.707 47.707,133.707 "/>
    <polygon fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" points="214.54,360.54 395.207,180.874 214.54,1.207 
	    214.54,91.874 304.874,180.874 214.54,271.207 "/>
    </svg>
            
    <div id="loadingElement">
        <progress max="100" data-bind="value: pourcentage">
        </progress>
        <span  data-bind="text: pourcentage"></span>
    </div>
</div>

image_thumb211

 

Un hack en CSS?

A ce stade, on a presque fini… Mais on va pas se leurrer, seul peu de navigateurs le supporte.

Le constat est le suivant:

  • Aucun pb pour Mozilla
  • Aucun pb pour WebKit (Chrome, Safari)
  • Opera chie dans la colle
  • IE9 a des pbs aussi (mais IE10 fonctionne)

Normalement, je devrais faire plusieurs fichiers CSS et des hack JS pour que tout fonctionne sur tous les navigateurs… mais j’ai pas envi!

Bon je sais bien, on peut pas dire ca entreprise mais comme c’est mon site perso, je m’en fou Sourire.

Donc direction modernizr, un petit outil JS me permettant de tester les capacités d’un navigateur.

http://www.modernizr.com/

Je configure donc toutes les features dont j’ai besoin:

image_thumb31

function VerifyBrowserCapacities() {
    Modernizr.load();
    var listOfNonSupported = [];
    for (var propertyName in Modernizr) {
        if (!Modernizr[propertyName])
            listOfNonSupported.push(propertyName);
    }

    if (listOfNonSupported.length > 0) {
        var root = window.location.toString().toLowerCase().replace("index.html", "");

        //alert(root.split('')[root.length - 1]);
        if (root.split('')[root.length - 1] != '/')
            root += '/';
        //alert(listOfNonSupported.toString());
        window.location = root + "notsupported.html?error=" + listOfNonSupported.toString();
        

    }
}

A ce stade, voici le rendu:

http://home.dollon.net/node/website3/

Utilisation de Media en CSS

Les media queries permettant de filtrer le CSS suivant le device.

Je vais l’utiliser pour imposer une résolution minimum.

@minwidth: 800px;
@minheight: 700px;
@media screen and (max-width: @minwidth) or (max-height: @minheight) {
       .popuppage 
    {
        .popuppageabstract;
	    visibility:visible;
    }
}
@media screen and (min-width: @minwidth) and (min-height: @minheight) {
    .popuppage 
    {
        .popuppageabstract;
	    visibility:hidden;
    }
}

image_thumb2[1][1]

De même, mes images de fonds ont une taille maximum de 2598x1417 + l’effet de translation. Sur de gros écrans ou sur un iPad, le résultat n’est donc pas terrible. Pour cela je désactive le background pour ces résolutions trop haute.

Une autre problématique, qui ne se résout pas avec le CSS mais que je met ici quand même: le viewport.

Il faut pouvoir empêcher les tablettes de pouvoir zoomer/dezoomer et forcer le scale de base de la page.

<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1, maximum-scale=1, user-scalable=no"/>

une autre chose importante, est d’imposer a l’utilisateur le mode landscape. Mon site rendant clairement mieux tout en longueur.

Pour forcer l’utilisateur, je pourrai utiliser body[orient="landscape"] en CSS mais cette propriété ne marche pas partout.

J’utilise donc un petit hack JavaScript:

 <body onload="OnLoad();" onorientationchange="updateOrientation();">

Version offline et stockage des articles hors ligne

L’objectif de la version offline va être de pouvoir montrer mon beau site quand j’ai pas internet.

Je vais devoir mettre en cache, la page, les scripts, les images mais aussi les données venant du service.

Pour les données j’ai le choix entre les stockes dans un indexeddb ou dans le webstorage. Indexeddb n’est pas encore bien supporte par Safari, j’opte donc pour le second.

Plus d’infos sur ces types de storages ici:

http://stackoverflow.com/questions/6849798/html5-client-storage-websqldatabase-vs-webstorage-vs-indexed-database

Pour commencer, je vais mettre en cache tout le site grâce a l’applicationcache feature.

  • Mise a jour du web.config pour gérer les fichiers manifest
<configuration>
 <system.web>
  <httpHandlers>
   <add verb="GET,HEAD" path="*.appcache"        type="System.Web.StaticFileHandler" />
  </httpHandlers>
 </system.web>
 <system.webServer>
  <staticContent>
   <mimeMap fileExtension=".appcache"      mimeType="text/cache-manifest" />
  </staticContent>
 </system.webServer>
</configuration>
  • Création du fichier manifest qui décrit les éléments accessibles offline
CACHE MANIFEST
# version 1

CACHE:
Index.html
notsupported.html
favicon.ico
Font/SEGOEUI.TTF
Assets/less.css
Assets/jquery-1.5.1.min.js
Assets/jquery.mousewheel.min.js 
Assets/principalViewModel.js
Assets/wallpaper/0.jpg
Assets/wallpaper/1.jpg
Assets/wallpaper/2.jpg
Assets/images/book.png
Assets/images/df.png

NETWORK:
*
  • Eviter les conflits and client et browser caching en désactivant le caching du browser:
    <meta http-equiv='Pragma' content='no-cache'>
    <meta http-equiv='Expires' content='-1'>
  • Tester!

Il faut maintenant stocker les données du service dans le storage.

Le webstorage propose deux types de stores: local et Session.

Local storage fonctionne comme un cookie, l’information pouvant être récupérer a tout moment alors que la session a une durée de vie plus limitée.

Pour mon cas, ca sera donc le localstorage (taille entre 2 et 10mo, amplement suffisant).

Désormais, même sans internet, ma page sera accessible.

Simplifier les fichiers JS et CSS

Me voici dans la phase avant déploiement: quelques petites choses sont encore a finaliser:

Ce compilateur de Google se décrit comme un compilateur qui compile du JS en JS, mais un JS plus rapide, plus optimisé.

Pour faire un test:

http://closure-compiler.appspot.com/home

Pour ma part:

image_thumb5

  • Nettoyer le HTML (et si vous avez le courage, le faire passer W3C)
  • Optimiser les performances

Résultats

Résultat sur PC

55_thumb2

WTF WINDOWS ON A MAC!!!! Sourire

Grace au site http://browserling.com/ je peux émuler le site web sur tous les navigateurs.

Tous les derniers navigateurs de la famille IE, Chrome, Safari et Mozilla sont capables de l’afficher correctement.

Le site final:

home.dollon.net

Résultat sur tablette

Android

WP_0000461_thumb1[4]

iPad

WP_0000451_thumb1[4]

Windows 8

WP_0000481_thumb1

Conclusion

HTML5 pour le web est la, s’apprend assez vite et est un plaisir a utiliser.

Cependant, il n’est la que depuis peu, car seul les derniers navigateurs (encore parfois en beta) le supporte.

Internet Explorer est le navigateur un peu en retard par rapport aux autres. Mais le 10 corrige tout. C’est donc pour la sortie de IE10 RTM (fin 2012/début 2013) que je conseillerai le développement HTML5. D’ici la, nous avons le temps de monter en compétence.

HTML5: Oui!

Avant 2013? Non!

Posté le: Apr 12 2012, 06:46 | Commentaires
Catégorie(s): .NET | HTML5 | Général

blog comments powered by Disqus
Anciens commentaires (archive):