Twitter YouTube SoundCloud LinkedIn

Tiennot blog

Portrait ou paysage ?

Vendredi 13 juillet 2012, 22:04 (par guilhem)

L'arrivée de nouveaux terminaux mobiles s'accompagne de nouvelles résolutions d'affichage, ce qui est d'autant plus perturbant que certains écrans peuvent basculer, comme sur les tablettes. Certes, il est possible de rendre son design adaptatif grâce à des dimensionnements relatifs ou des media queries, mais il peut être parfois intéressant d'optimiser l'espace avec du javascript, ou tout simplement ajouter des effets lors du basculement.

Travaillant actuellement sur une mission de développement web où j'ai à me soucier de ces problématiques, je me suis essayé à la tâche ardue de détecter le basculement et l'orientation du terminal en javascript - en l'occurrence, une tablette. Et la solution n'est pas aussi simple qu'il n'y paraît...

Pour les impatients, le script fonctionnel se trouve à la fin du billet.

window.orientation, c'est pas encore ça...

Pour déclencher une fonction à chaque basculement, il suffit de l'attacher à l'évènement window.onorientationchange. La variable window.orientation nous donne alors l'orientation du terminal par rapport à sa position de référence : 0°, 90°, -90° ou 180°.

/* Ce code ne donne pas le résultat attendu... */

window.onorientationchange = function() {
  var orientation = window.orientation;

  if (orientation == -90 || orientation == 90)
    alert('mode paysage');
  else
    alert('mode portrait.');
}

Mais cela ne marche pas. Pour comprendre pourquoi, prenez un iPad dans une main, une Galaxy Tab dans l'autre. Si vous les placez dans leurs positions normales (bouton en bas pour le premier, logo Samsung en bas pour la seconde), vous remarquerez que l'un est en mode portrait, l'autre en mode paysage. Ainsi, le 0° peut correspondre indifféremment à l'un ou l'autre mode suivant le terminal, et idem pour les autres valeurs !

On y est presque !

Pour s'en sortir, l'idée serait de comparer la largeur et la hauteur de l'écran pour savoir si on est en portrait ou en paysage à 0°. Ainsi, on peut en déduire l'orientation pour les autres valeurs.

/* Ce code ne fonctionne toujours pas... */

/* Appelé quand le device passe en mode portrait. */
function mode_portrait() {
  alert('mode portrait.');
}

/* Appelé quand le device passe en mode paysage. */
function mode_paysage() {
  alert('mode paysage.');
}

window.onorientationchange = function() {
  var orientation = window.orientation;

  if (screen.width > screen.height)
  {
    if (orientation == -90 || orientation == 90)
      mode_portrait();
    else
      mode_paysage();
  }
  else
  {
    if (orientation == 90 || orientation == -90)
      mode_paysage();
    else
      mode_portrait();
  }
}

Ce code fonctionne très bien pour iPad, par exemple. Mais sur la Galaxy Tab, le message affiché sera toujours le même. Pourquoi ? Parce que les valeurs mêmes de screen.width et screen.height changent avec l'orientation sur cette tablette, ce qui n'est pas le cas sur l'iPad. Nous nous retrouvons donc face à un beau casse-tête !

La solution

Voici la solution que je vous propose. Tout d'abord, les hauteur et largeur de l'écran sont relevées au lancement du script. Puis, lors d'un basculement, on compare les valeurs de screen.width et screen.height avec celles enregistrées. Si celles-ci ont changées, on se fie à cette donnée pour déterminer l'orientation. En revanche, si elles restent inchangées, on utilise le script présenté juste avant.

/* La solution !
 * Licence : GNU/GPL 2.
 */

var width = screen.width;
var height = screen.height;

/* Appelé quand le device passe en mode portrait. */
function mode_portrait() {
  alert('mode portrait.');
}


/* Appelé quand le device passe en mode paysage. */
function mode_paysage() {
  alert('mode paysage.');
}

window.onorientationchange = function() {
  var orientation = window.orientation;

  /* Trois cas de figure possible :
   *  - le device a un écran plus large que haut.
   *  - le device a un écran plus haut que large.
   *  - le device trouve intelligent de modifier la largeur
   *    et la hauteur de l'écran en fonction de son orientation...
   * 
   * Du coup, soit la largeur/hauteur de l'écran change, et
   * on en déduit à partir de là l'orientation, sinon il faut
   * se fier à la variable window.orientation, et en déduire
   * d'après le ratio de l'écran l'orientation...
   */

  if (screen.width != width || screen.height != height)
  {
    width = screen.width;
    height = screen.height;

    if (screen.width > screen.height)
      mode_paysage();
    else
      mode_portrait();
  }
  else if (screen.width > screen.height)
  {
    if (orientation == -90 || orientation == 90)
      mode_portrait();
    else
      mode_paysage();
  }
  else
  {
    if (orientation == 90 || orientation == -90)
      mode_paysage();
    else
      mode_portrait();
  }
}

Cette solution n'est peut-être pas la plus élégante (si vous avez mieux, je suis intéressé), mais elle a le mérite de fonctionner correctement.

Ce qu'en dit la norme

La notion d'orientation a été vraisemblablement introduite par Apple avec l'iPhone et l'iPod. À l'époque, seuls ces deux terminaux prenaient en charge l'évènement window.onorientationchange et la variable window.orientation. Actuellement, elle est en passe d'être normalisée par le w3c, ce qui explique pourquoi la plupart des périphériques tactiles la prennent en charge. Cependant, la norme est encore à l'état de brouillon.

Malgré tout, l'orientation n'est pas restreinte aux seuls modes portraits ou paysage, comme on pourrait s'y attendre. Ainsi, le fabricant a toute la liberté de choisir la position de référence qu'il souhaite.

Concernant la largeur et la hauteur de l'écran, je n'ai pas vu qu'il était imposé qu'elles soient fixées. Ce détail est laissé à l'appréciation du constructeur, ce qui explique le comportement de la Galaxy Tab.

Comme vous pouvez le constater, la norme reste encore floue aujourd'hui, d'où des comportements différents suivant les terminaux. On ne peut qu'espérer qu'à l'avenir, tout ceci se clarifie un peu.

Commentaires