Krazy Bald Head - Behind the scene

Artiste, qui es-tu ?

Krazy Bald Head

Réaliser le site d'un artiste demande toujours de s'imprégner de son univers. L'objectif est d'immerger l'internaute dans le monde de l'artiste.

En ce qui concerne Krazy Bald Head, la tâche aurait pu se révéler ardue. Son univers est éclectique. Sa musique prend son inspiration dans de nombreux genres, du classique à l'électro, des percussions aux mélodies minimalistes.

Visuellement, il travaille avec un VJ en concert mais le style des vidéos qu'il utilise, très "Super 8", n'ont rien à voir avec le visuel de ses pochettes d'albums ni même avec celui de ses clips. Les pochettes des 2 albums sont d'ailleurs très différentes elles aussi.

C'est ce mélange, ou plutôt cette juxtaposition foisonnante qui nous a donné le concept du site. Nous avons créé un site sur le mode d'un patchwork composé de mini-sites. Mais si, rappelez-vous, un patchwork, cette couverture bariolée qui reposait sur le lit de votre grand-mère. Une couverture composée de carrés disparates et colorés faits de tissus différents, tricotés, cousus et brodés avec amour par nos aïeules durant les longues soirées d'hiver avant que Derrick ne sévisse et vienne à bout de leur créativité !

Le site est donc une juxtaposition de mini-sites d'une page. Chacun mettant en avant un des aspects de l'artiste. Et surtout, gros avantage d'un site comme celui-ci, il est ouvert à de multiples ajouts qui pourront être faits au fur et à mesure du développement des projets de Krazy Bald Head qui ne manque pas d'envies et d'idées.

Le site est donc composé de 6 "modules" : Un module cartographique, une playlist des morceaux du dernier album, un mini-site participatif mettant en avant le premier single "Empty Boy" et le module central, une timeline représentant les étapes importantes de la vie de l'artiste. Ces modules sont arrangés les uns à côté des autres sur un site d'une seule grande page (voir le schéma ci-dessous).

Qui devient une fois designé, ceci :

Avouez que le premier mot qui vous vient à l'esprit à vous aussi c'est "patchwork" !

D'un point de vue technique, le site est donc constitué d'un "squelette" pouvant accueillir des "pages" et les plaçant sur une grille. La timeline est positionnée sur la case (0, 0) et les autres pages de la même manière : carte en (0, 1), playlist en (1, 0), la galerie emptyboy en (-1, -1), etc. Chaque page est gérée par un objet Javascript indépendant. Le squelette principal a pour rôle de gérer les mouvement de l'ensemble de la grille et d'activer et désactiver les différentes pages.

Ainsi, lorsqu'on change de page, les actions suivantes sont effectuées :

  1. Appeler la fonction deactivate sur la page courante.
  2. Appeler la fonction beforeActivate sur la page cible.
  3. Effectuer le mouvement de l'ensemble de la grille.
  4. Appeler la fonction afterDeactivate sur la page courante.
  5. Enregistrer la page cible comme page courante.
  6. Appeler la fonction activate sur la page cible (qui est devenue la page courante).

Ces multiples étapes permettent à chaque page de bien gérer le lancement de leurs différents éléments (timers, video, audio, écouteurs d'événements, ...).

Voilà le code, très simple, résumé ici :

goToPage: function(page) { 
var self = this;

 if(this.current.page != page) {
  if(this.current.page) 
       this.current.page.deactivate(); 
 page.beforeActivate();


 siteContent.slide(
     -(page.x * layout.width),        // x 
     -(page.y * layout.height),      // y    
     2000,                          // duration 
     function() {                  // callback function after page slept
         if(self.current.page)
             self.current.page.afterDeactivate();

         self.current.x = page.x;
         self.current.y = page.y;
         self.current.page = page;
         page.activate(); 
        }
    );
  }
 }

HTML5 et CSS3 sont dans le bateau...

Le plaisir de travailler sur des projets de site avec Microsoft, c'est que l'on n'a pas seulement le droit mais le devoir d'utiliser le plus possible de nouveautés d'HTML5 et des API liées. Ca n'est pas tous les jours que l'on ne nous demande pas de faire de la compatibilité notre principal cheval de bataille donc on en profite grandement sur ce genre de projets.

Ici quels sont donc les techniques utilisées ?

Et bien de nombreuses, même si elles ne se voient pas toutes de manière évidente.

Bien entendu, il y a les balises audio et video utilisées à profusion dans l'écran de playlist. Ces balises sont devenues très rapidement des classiques et on les utilise abondamment dans tous nos sites avec des fallbacks Silverlight ou Flash pour les anciens navigateurs.

Pour la fluidité du défilement des photos avec le empty boy qui danse, cours et saute par dessus, on utilise des translations CSS3 plutôt que du déplacement de position. Les derniers navigateurs le gèrent plus efficacement.

L'upload de photos pour empty boy est un peu particulier. Pour des raisons d'architecture système et d'organisation du projet nous avions besoin que la partie upload soit gérée sur un serveur différent de celui hébergeant le site (qui est lui sur une instance Windows Azure). Le formulaire d'upload est donc situé sur un autre serveur et integré au site grâce à une iframe. Mais qui dit iframe dit problème de communication entre la frame parente (le site) et le contenu de l'iframe (le formulaire). On a donc utilisé l'API de cross messaging qui permet d'envoyer des messages textes entre frames ou entre fenêtres de navigateur.

Dans la timeline, pendant le défilement des éléments, ceux-ci arrivent par la droite avec un petit mouvement de rotation. Celui-ci est réalisé avec des transformations en CSS 3D disponible maintenant sur tous les derniers navigateurs du marché.

Toujours au niveau de la timeline vous aurez peut-être remarqué 2 petits effets subtils : pendant que les développeurs avaient le dos tourné, les designers ont choisi de concevoir les éléments de la timeline dans des ronds... Les devs n'ont pas contredis l'esthétique du choix jusqu'au moment où il a fallut les animer. Par exemple, lorsque les éléments arrivent au milieu de l'écran ils se déploient alors qu'ils se rétractent lorsqu'ils quittent le centre. Nous aurions pu utiliser une transformation d'échelle CSS mais cela était rendu compliqué et assez lourd à cause des rotations 3D déjà présentes (voir ci-dessus). Nous avons donc choisi d'utiliser des canvas et d'animer à la main l'expansion et la rétractation des ronds. Autre avantage, cela nous permet d'utiliser les effets de masques de l'API de dessin du canvas afin de ne pas avoir besoin de retravailler chaque image en rond.

De la même manière l'effet de transition "à la Star Wars" dans les éléments qui représentent des galleries d'images est aussi réalisé en canvas. Cela permet de limiter le nombre d'éléments présent dans le DOM pendant le défilement de la timeline entière et donc de l'alléger pour fluidifier le mouvement.

Vous l'aurez noté, pas d'énormes nouveautés, pas d'HTML5 dans tous les coins du site. Juste l'utilisation des bonnes technologies que nous offre le HTML5 et le CSS3 aux endroits où elles s'avèrent le plus efficaces afin de servir le design du site. On n'est pas dans un exercice de démonstration des capacités du HTML5 mais plus dans son utilisation afin de servir au mieux la créativité des designers de l'équipe.

Le contrôle du temps

Mais j'ai été assez bavard jusque là ! Rentrons donc dans le vif du sujet. On ne va pas décortiqué toutes les techniques utilisées dans le site mais nous concentrer sur le principe de contrôle de la timeline.

Principia Mathematica

Le défilement de la timeline peut se faire de 4 manières différentes :

  • En cliquant sur un des points en bas de l'écran.
  • En cliquant sur le petit curseur rectangulaire tout en bas de l'écran et en le glissant horizontalement.
  • En déplaçant la souris sur le bord de la fenêtre à droite ou à gauche.
  • En "swipant" avec le doigts si vous êtes sur un écran tactile.

Pour chacun de ces mouvements, le résultat du mouvement doit être fluide. On doit d'ailleurs pouvoir les mélanger et les ordres de mouvement ne doivent pas devenir contradictoires. De même on ne doit pas avoir besoin d'attendre la fin d'un mouvement pour pouvoir en commencer un autre. Par exemple, si je clique sur le dernier élément et qu'avant la fin du mouvement, je viens déplacer la souris sur la gauche de l'écran, c'est le dernier contrôle qui doit être pris en compte et la timeline doit défiler vers la gauche (en fait vers la droite mais pour nous diriger vers les éléments de gauche). Et bien sûr, les transitions entre les différents ordres doivent s'enchaîner en un mouvement fluide.

Il y a certainement de nombreuses manières d'arriver à ce type de résultat. Celui que nous avons choisi consiste à décorrèler l'ordre et le mouvement lui-même. Ainsi, les mouvements et clics de la souris ou les actions du doigts fixent à la timeline une position cible à atteindre. Une deuxième tâche s'exécutant en boucle s'occupe, quant à elle, de gérer le mouvement de la position courante de la timeline qui tente de rejoindre cette position cible. Ce mouvement est réalisé de manière à simuler des accélérations et une inertie afin de rendre le mouvement fluide et plus proche d'un mouvement réaliste.

Pour gérer ce mouvement de manière réaliste, on peut bien entendu créer ou utiliser un moteur physique qui gèrerait les accélérations et décélérations, l'inertie, les frottements, etc. Mais nous cherchons juste à rendre une impression de mouvement réaliste, nous ne développons pas un jeu ou une simulation. L'algorithme utilisé est donc complètement simplifié afin d'accélérer au maximum les calculs du mouvement tout en donnant la bonne perception à l'utilisateur.

Le principe de cet algorithme est très simple : à chaque étape, on divise la distance entre la position actuelle et la position cible par un nombre fixe d'étapes (ce que nous appellerons le facteur de mouvement). Cela nous donne une pseudo-accélération à ajouter à la vitesse courante de la timeline. On avance alors la position courante jusqu'à la prochaine étape en fonction de la vitesse courante, puis on recommence. Si la position cible n'a pas changée, la distance a diminuée et on recommence la division pour calculer la position de la prochaine étape, si la cible a bougé, on la prend en compte pour la prochaine étape. Ainsi au fur et à mesure que l'on s'approche de la cible, la distance à parcourir va être de plus en plus petite, et la timeline va naturellement ralentir. Bien entendu, si l'on s'arrête à cela, on ne terminera jamais le mouvement, car à un moment donné, la distance à parcourir est trop petite pour être visible à l'écran et on peut diviser la distance restante à l'infini sans jamais arriver au bout. C'est le paradoxe de la dichotomie de Zénon que nous conta Aristote et qui est résolu par les mathématiciens grâce à la nature continue du mouvement. Mais en informatique, le continu n'existe pas ! Il nous faut donc jouer les maîtres du temps et couper court aux vélléités de mouvement perpétuel de notre timeline. Pour cela, nous ajoutons tout simplement une limite de distance à partir de laquelle, nous "téléportons" notre timeline directement à sa position cible. Spock à l'Enterprise : Mission accomplie !

Après quelques petits ajustements, voici le code de l'algorithme de mouvement de la timeline :

var MOVE_FACTOR = 8;
 var MOVE_LIMIT = 0.01;
 var STARTING_POSITION = 100;

 var screen = { 
            position: STARTING_POSITION,
            target: STARTING_POSITION,
            speed: 0, acceleration: 0
     };
     
 function computeMove() {
       var diff = screen.target - screen.position;
       
       screen.acceleration = diff / MOVE_FACTOR - screen.speed;
       if((screen.acceleration < MOVE_LIMIT)
                      && (screen.acceleration > -MOVE_LIMIT)) {
           screen.acceleration = 0; 
       } 
       
       screen.speed += screen.acceleration;
       if((screen.speed < MOVE_LIMIT) && (screen.speed > -MOVE_LIMIT)) {
           screen.speed = 0; 
       }
      
       screen.position += screen.speed; 
 }
 
  function animate() {
           // compute...
           computeMove();
            
          // then display (code for the example behind)
          display(); 
 } 
 
 setInterval(animate, 30);

Et voici un exemple très simple qui utilise le code précédent pour faire bouger non pas une timeline mais une simple div (le carré rouge) à la poursuite de la souris.

Pour faire fonctionner cet exemple, nous avons juste à ajouter au code précédent la fonction d'affichage du carré rouge (nous utilisons sa propriété CSS left pour simplifier le code) et à écouter les mouvements de la souris sur l'ensemble de la page.

var square = document.getElementById("square");
 
function mouseMoved(event) {
	 screen.target = event.pageX;
}

 function display() {
      square.style.left = (screen.position - 15) + "px";
} 

document.body.addEventListener("mousemove", mouseMoved, false);

Courir après la souris

Le mouvement de la timeline étant maintenant assuré, il nous reste, pour déplacer notre timeline à la souris, à écrire le code qui déplacera la position cible en fonction de la position de la souris.

Le principe utilisé est de découper l'écran en plusieurs zones qui vont réagir différemment lorsque la souris passe au-dessus :

  • Une zone centrale qui ne déclenche aucun mouvement. Cela permet aux utilisateurs d'interagir avec les éléments de la timeline lorsqu'ils sont au centre de l'écran.
  • Une zone à gauche, qui déclenche un mouvement de la timeline vers la droite (afin de découvrir les éléments de gauche). Plus on s'approche du bord de l'écran, plus ce mouvement est rapide.
  • Une zone à droite qui déclenche le mouvement inverse et est aussi progressif.

Nous avons donc besoin pour calibrer le mouvement de 2 variables : une largeur de zone centrale ainsi qu'une vitesse maximale de défilement que l'on atteindra sur les bords de l'écran. Il ne nous reste plus ensuite qu'à écouter les mouvements de la souris. Cependant, lorsque l'utilisateur ne bouge plus la souris, nous ne recevons aucun événement de souris, or nous voulons que la timeline continue à glisser régulièrement si l'utilisateur a placé sa souris sur le bord de l'écran. Il nous faut donc ajouter une étape pour notre mouvement : lorsque l'utilisateur bouge la souris, nous allons calculer la vitesse du défilement et l'enregistrer. Puis, à chaque étape d'animation, avant de calculer le mouvement de la timeline, nous calculerons la position cible de la timeline en fonction de cette vitesse.

Tout ceci mis ensemble nous donne le code suivant :

var timeline = document.getElementById("timelineContent");

var MOVE_FACTOR = 8;
var MOVE_LIMIT = 0.01;
var STARTING_POSITION = 0;
var SLIDE_CENTRAL_ZONE = 300;
var SLIDE_MAX_SPEED = 100;

var screen = {
   position: STARTING_POSITION,
   target: STARTING_POSITION,
   speed: 0, 
   acceleration: 0,
   
   slideSpeed: 0 
 };
 
  function computeMove() {
  		 // ... not modified 
 }
 
  function animate() { 
 	 computeSlideMove(); // call added
  	 computeMove();<br>
 	 display(); 
 }
 
  function computeSlideMove() {
  	 var timelineWidth, winWidth, maxDisplacement;
     if(screen.slideSpeed != 0) {
        screen.target = screen.position - screen.slideSpeed; 
        if(screen.target > 0)
            screen.target = 0;
        else { 
            timelineWidth = timelineContent.clientWidth;
            winWidth = window.innerWidth; 
            maxDisplacement = timelineWidth - winWidth;
            
            if(screen.target < -maxDisplacement) { 
                screen.target = -maxDisplacement;
            }
         }
       }
   }
   
 
  function display() {
      // no difference. 
      timeline.style.left = screen.position + "px"; 
  }
  
  function mouseMoved(event) {
      var slideSpeed = 0; 
      var ratio = 0;
      var winWidth = window.innerWidth; 
      var slideZoneWidth = (winWidth - SLIDE_CENTRAL_ZONE) / 2;
      var slideZoneRight = (winWidth + SLIDE_CENTRAL_ZONE) / 2; 
      if(event.pageX < slideZoneWidth) { 
          ratio = event.pageX / slideZoneWidth - 1;
      } 
      else if(event.pageX > slideZoneRight) {
           ratio = (event.pageX - slideZoneRight) / slideZoneWidth;
      }
      
       screen.slideSpeed = Math.round(ratio * SLIDE_MAX_SPEED);
 }
 
 document.body.addEventListener("mousemove", mouseMoved, false);

 setInterval(animate, 30);

Ce qui donne le résultat suivant :

Si vous regardez bien, il reste un petit soucis à notre code. Si vous déplacez la souris en dehors de la fenêtre, la timeline continue à défiler jusqu'à ce qu'elle soit arrivée au bout de son déplacement possible. Il nous faut donc détecter le moment où la souris sort de la zone afin de réinitialiser la vitesse de défilement à 0. On utilise dans ce cas simple les 2 événements mouseout et mouseleave qui réagissent différemment en fonction des navigateurs.

function mouseOut(event) {
   screen.slideSpeed = 0;
}

document.body.addEventListener("mouseleave", mouseOut, false);
document.body.addEventListener("mouseout", mouseOut, false);

Ce qui donne une fois corrigé, cela :

Voilà pour ce qui concerne le contrôle par la souris du défilement du site de Krazy Bald Head. Bien sûr, si vous allez jeter un coup d'oeil sur le code du site (ne vous gênez pas !), vous verrez qu'il est bien plus complexe que cela. En effet, on doit, dans notre cas, gérer aussi le défilement grâce au slider en bas de l'écran. Lorsqu'on prend et glisse ce slider, bien évidemment le navigateur envoie des événements "mousemove" auquel on ne veut pas répondre de la même manière que celle présentée dans cet article. On doit donc gérer les différents cas d'actions utilisés dans l'ensemble du site. De même, on teste la position verticale de la souris pour ne pas, par exemple, activer le défilement lorsque la souris est sur le menu, etc. Mais je laisse les curieux étudier plus avant le code original.

Et passons au deuxième moyen de contrôler cette timeline : le doigt.

Obéir au doigts...

Pour le "touch", cela devient tout de suite un peu plus complexe. En effet les navigateurs n'offrent pas les mêmes événements à écouter pour réagir au écrans tactiles. De ce côté, IE10 offre une palette plus complète de possibilités avec la détection des "gestes", etc.

Pour notre timeline, nous n'avons pas besoin de gestes compliqués, le simple mouvement d'un doigt unique nous intéresse et on va donc pouvoir créer sans trop de soucis un code compatible avec tous les navigateurs en gérant les 2 types d'événements simples.

Pour les navigateurs de type Firefox et Webkit Family, les événements sont calqués sur ceux de la souris : touchstart, touchmove, touchend et touchcancel (au cas où par exemple un appel téléphonique surviendrait en plein milieu d'un geste).

Pour IE 10, les événements corespondant sont : MSPointerDown, MSPointerMove, MSPointerUp et MSPointerCancel. Il existe des événements MSGesture... qui permettent de gérer les gestes plus complexes beaucoup plus facilement puisque IE fait tout le travail de détection pour nous. Mais au moment où nous avons développé le site, ces événements n'étaient pas encore documentés.

Bref, la timeline du site ne nécessite qu'un traitement simple prenant en compte uniquement les événements Start, Move et End. Voici une fonction permettant d'enregistrer les 3 écouteurs de ces événements tout en gérant la compatibilité des navigateurs :

function registerTouchEvents(downCallback, moveCallback, upCallback) {
  if(window.navigator.msPointerEnabled) { 
       if(downCallback)
          timeline.addEventListener("MSPointerDown", touchDown, false);
       if(moveCallback) 
          document.addEventListener("MSPointerMove", touchMove, false);
       if(upCallback)
          document.addEventListener("MSPointerUp", touchUp, false); 
  }
  else { 
      // events compatibility for simple use
      if(downCallback) { 
          timeline.addEventListener("touchstart", function(event) {
               event.preventDefault();
               event.screenX = event.changedTouches[0].screenX;
               event.screenY = event.changedTouches[0].screenY; 
               downCallback(event);
          }, false); 
      }
       
     if(moveCallback) { 
          timeline.addEventListener("touchmove", function(event) {
              event.preventDefault();
              if(event.touches.length === 1) { 
                  event.screenX = event.changedTouches[0].screenX;
                  event.screenY = event.changedTouches[0].screenY;
                  moveCallback(event); 
              }
          }, false); 
     }
     
     if(upCallback) { 
         timeline.addEventListener("touchend", function(event) { 
             event.screenX = event.changedTouches[0].screenX;
             event.screenY = event.changedTouches[0].screenY;
             upCallback(event);
         }, false); 
      }
   } 
}

Pour désactiver la détection et le déclenchement des actions par défaut des gestes, sous IE, il nous faudra aussi ajouter à notre timeline une propriété CSS particulière :

-ms-touch-action: none;

Une fois ce problème de compatibilité réglé, nous pouvons gérer de manière très basique le mouvement de notre timeline en calculant le mouvement du doigt sur l'écran et en calquant dessus la position cible de la timeline.

var touch = {
    startX: undefined, 
    baseX: undefined 
};

function touchDown(event) {
    touch.startX = event.screenX;
    touch.baseX = screen.position;
   
    screen.target = touch.baseX;
}

function touchMove(event) { 
    if(touch.baseX === undefined) {
             touch.baseX = screen.position;
    } 
    if(touch.startX === undefined) {
             touch.startX = event.screenX;
    }
   
    screen.target = touch.baseX - (event.screenX - touch.startX);
}

function touchUp(event) {
    touch.baseX = undefined;
    touch.startX = undefined; 
}

registerTouchEvents(touchDown, touchMove, touchUp);

Et on a alors un mouvement au doigt très simple. On pourrait aller plus loin et calculer grâce à la propriété event.timestamp la vélocité du mouvement afin de détecter un "swipe" et de "lancer" la timeline comme on le ferait sur une vraie mappemonde. Mais dans ce cas, il serait plus pertinent sous IE de gérer cela avec des MSGesture et de traiter le cas de manière particulière pour les autres navigateurs. Ca n'est pas le propos ici et nous en resteront donc à cet exemple simple.

Des souris et des doigts : trop d'intelligence peut nuire...

Il ne nous reste plus qu'à traiter le cas bien particulier des nouvelles tablettes sous Windows 8 (c'est vrai aussi d'un certain nombre d'ordinateurs qui sortent en cette fin d'année).

En effet elles sont les premières à nous confronter à un cas d'utilisation nouveau : on peut avoir à la fois un écran tactileET une souris !

Vous allez me dire, qu'à cela ne tienne, il suffit que l'on dépose nos 2 codes côte à côte. La décorélation du mouvement et du contrôle vont régler tout seuls le problème. Presque ! Mais c'est sans compter sur "l'intelligence" des navigateurs qui veulent permettre à tous les utilisateurs de profiter des sites web conçus soit pour le touch soit pour la souris.

Je m'explique : imaginez un site conçu uniquement pour fonctionner avec la souris (comme 99,99% des sites actuels), vous ne pourriez pas les utiliser sur une tablette uniquement tactile si les concepteurs du navigateurs n'avait pas ajouté quelques neurones au cerveau de votre machine pour lui faire simuler la souris avec le doigt. Lorsque vous posez le doigt, un événement mousedown est donc généré, de même lorsque vous bouger le doigt, c'est un événement mousemove, etc. Ainsi vous pouvez contrôler le site avec votre doigt ou avec la souris.

De même, si votre site est prévu pour réagir au touch, la souris va générer des événements touchstart, touchmove et touchend pour simuler le déplacement d'un doigt.

Habituellement cela ne pose pas de problème mais dans notre cas, nous avons décidé de traiter différemment le touch et la souris. Le contrôle n'est pas du tout le même, l'un basé sr la position de la souris dans l'écran et l'autre sur le mouvement du doigt. Et là, les neurones du navigateur s'emmèlent les synapses et déclenchent nos événements dans tous les sens en mélangeant les comportements et en rendant notre timeline épilleptique !

Il nous faut donc une solution, mais heureusement, les concepteurs de IE 10 ont prévu le coup. L'objet event passé en paramètre des écouteurs MSPointer... contient une propriété supplémentaire nous indiquant l'origine de l'événement. Cette propriété s'appelle event.pointerType et peut prendre les valeurs suivantes :

  • event.MSPOINTER_TYPE_TOUCH
  • event.MSPOINTER_TYPE_MOUSE
  • event.MSPOINTER_TYPE_PEN (pour les stylets)

Il nous suffit donc de faire 2 choses :

  • Ajouter à chaque écouteur d'événement un test pour ne l'activer que si l'événement vient du bon endroit.
  • Remplacer sous IE les évenements mouse... par des événements MSPointer... (je sais, c'est un code particulier pour un navigateur mais si on regarde bien de toutes manières, en tant que développeur web, on passe notre temps à gérer les petites différences entre chacun des navigateurs et aucun ne nous épargne !).

Et le tour est joué ! je vous laisse regarder directement le code complet dans le source de l'exemple final ci-dessous.

En conclusion

Voilà donc une revue simplifiée de la création d'un des modules de ce site. Au fur et à mesure du développement des interfaces tactiles, les API de gestion des événements et des gestes vont se compléter. Microsoft avec IE 10 a pris une bonne avance sur la définition d'une telle API. On attend avec impatience que le WHATWG et le W3C s'approprient cette API pour que tous les navigateurs nous propose un traitement standardisé.

En espérant que ce petit tutoriel vous aura éclairer sur les secrets de réalisations de ce site. Et surtout, n'hésitez pas à plonger dans le code du site pour aller y piocher des idées pour les vôtres. Et faites le nous savoir !

 

 

Par les équipes de Steaw.com & Waest.com

Visitez le site de l’artiste

Microsoft réalise une enquête en ligne pour comprendre votre opinion sur le site Web de. Si vous choisissez de participer, l’enquête en ligne vous sera présentée lorsque vous quitterez le site Web de.

Souhaitez-vous y participer ?