1

Scroll auto sur iPhone, iPod et iPad

6 avril 2010
par ARNO*

Avertissement : cette astuce n’est pas réservée à SPIP. Elle concerne n’importe quelle page HTML destinée à l’affichage sur iPhone ou iPad. (Mais personnellement, je développe jamais que du HTML avec SPIP...)

Sur Safari versions iPhone, iPad et iPad, il est très difficile d’utiliser le scroll automatique pour des éléments de hauteur fixée dotée du style :

  1. overflow: auto;

Le comportement existe, mais est généralement inconnu des usagers : le scroll s’obtient en caressant l’engin avec deux doigts. Le scroll avec un doigt est réservé au scroll général de la page.

Si votre page est conçue comme une « application Web », ce comportement est très pénible. Je n’ai pas trouvé de solution satisfaisante pour rétablir le comportement « habituel » sur ces machines, aussi j’ai développé un petit javascript (utilisant jQuery).

Je vous le livre donc ci-dessous, tel quel.

Outre le retour du scroll à un doigt sur les éléments à overflow, le script simule l’apparition et la disparition d’une scrollbar à la façon de Safari.

Pour l’utiliser, il faut ajouter la classe scroll_auto aux éléments concernés (les éléments qui sont conçus pour la classe overflow). Par exemple :

  1. <div id="cadredemo" class="scroll_auto">
  2.         Ceci est mon texte.
  3.         [...]
  4.         Ce contenu est suffisamment long pour déclencher le système de scroll.
  5. </div>

Télécharger

Pour être cohérent, il faut évidemment que le cadre doté du scroll_auto soit de hauteur fixe et doté d’un overflow, par exemple :

  1. #cadredemo {
  2.         height: 400px;
  3.         overflow: auto;
  4. }

Télécharger

Il suffit ensuite d’appeler le fichier Javascript dans votre header, il déclenchera tout seul tout le comportement nécessaire.

Notez bien : si vous testez votre page Safari sous Mac (ou sous Windows) en modifiant son indication d’agent utilisateur, le comportement ne fonctionnera pas : les événements touchstart, touchmove et touchend ne sont intégrés qu’aux versions iPhone, iPod et iPad.

  1. var debut_scroll_Y = false;
  2. var debut_marginTop = 0;
  3. var hauteur_scrollbar_auto = 100;
  4.  
  5. function fix_scroll_auto() {
  6.         if(
  7.                 (navigator.userAgent.match(/iPhone|iPod|iPad/i))
  8.         ) {
  9.                 $(".scroll_auto").each(function() {
  10.                         var contenu = $(this).html();
  11.                         var start_time = 0;
  12.                         var last_decal = 0;
  13.                         var rapport = 1;
  14.                         var hauteur_max = 100;
  15.                         var hauteur_boite = 100;
  16.                        
  17.                         if ($(this).children(".wrapper").width() > 0) {
  18.                         } else {
  19.                                 $(this)
  20.                                         .html( "<div class='scrollbar_auto' style='position: absolute; top: 0px; right: 3px; -webkit-box-shadow: 0px 0px 2px rgba(255,255,255, 0.3); width: 5px; height: 100px; -webkit-border-radius: 3px; background-color: rgba(0,0,0,0.5); z-index: 100; display: none; '></div>"
  21.                                                                 + "<div class='wrapper' style='height: auto; -webkit-transition-property: margin-top; -webkit-transition-duration: 0.2s; -webkit-transition-timing-function: ease-out;'>"
  22.                                                                 + contenu + "<div style='clear: both;'></div></div>"
  23.                                                                 + "<div class='bidon' style='position: absolute; opacity: 0;'></div>"
  24.                                                         )
  25.                                         .css("position", "relative")
  26.                                         .css("overflow", "hidden");
  27.                                        
  28.                         }
  29.        
  30.                         this.ontouchstart = function(evt) {
  31.                                 debut_scroll_Y = evt.touches[0].pageY;
  32.  
  33.                                 var now = new Date().getTime();
  34.                             start_time = parseInt(now, 10);
  35.                                 last_decal = 0;
  36.  
  37.                                 debut_marginTop = parseInt($(this).children(".wrapper").css("marginTop"));
  38.                                
  39.                                 rapport = $(this).outerHeight() / $(this).children(".wrapper").outerHeight();
  40.                                
  41.                                 if (rapport < 1) {
  42.                                         $(this).children(".scrollbar_auto").fadeIn();
  43.                                         hauteur_scrollbar_auto = Math.floor(rapport * $(this).outerHeight());
  44.                                         $(this).children(".scrollbar_auto").height(hauteur_scrollbar_auto);
  45.                                 }
  46.                                 hauteur_max = $(this).children(".wrapper").outerHeight() - $(this).outerHeight();
  47.                                 hauteur_max = -1 * hauteur_max;
  48.                                 hauteur_boite = $(this).outerHeight();
  49.                                
  50.                         };
  51.                        
  52.                         this.ontouchmove = function(event) {
  53.                                 if (rapport > 1) return false;
  54.                                
  55.                                 var y = event.touches[0].pageY;
  56.                                
  57.                                 var decal = y - debut_scroll_Y;
  58.                                 last_decal = decal;
  59.                                 decal = decal + debut_marginTop;
  60.                                
  61.                                
  62.                                 if (decal > 0) decal = 0;
  63.                                 if (decal < hauteur_max) decal = hauteur_max;
  64.  
  65.                                 $(this).children(".wrapper").css("marginTop", decal);
  66.                                 // Hack bizarre: dans certains cas, il faut ecrire quelque chose quelquepart pour que le scroll fonctionne en direct
  67.                                 $(this).children(".bidon").html("bidon");
  68.                                
  69.                                 var rapport_pos = (decal / hauteur_max);
  70.  
  71.                                 var vide = Math.round( rapport_pos * (hauteur_boite - hauteur_scrollbar_auto));
  72.                                
  73.                                 $(this).children(".scrollbar_auto").css("marginTop", vide);
  74.                                
  75.                                
  76.                                 return false;
  77.                                                                        
  78.                         };
  79.                        
  80.                         this.ontouchend = function(event) {
  81.                                 var now_end = new Date().getTime();
  82.                             var end_time = parseInt(now_end, 10);
  83.                            
  84.                             var duree = end_time - start_time;
  85.                        
  86.                                 var decal = Math.round(last_decal * ( 1 + 200/duree));
  87.                                 decal = decal + debut_marginTop;
  88.                                
  89.                                
  90.                                 if (hauteur_max < 0) {
  91.                                        
  92.                                         if (decal > 0) decal = 0;
  93.                                         if (decal < hauteur_max) decal = hauteur_max;
  94.                                        
  95.                                         $(this).children(".wrapper").css("marginTop", decal);
  96.                                         // Hack bizarre: dans certains cas, il faut ecrire quelque chose quelquepart pour que le scroll fonctionne en direct
  97.                                         $(this).children(".bidon").html("bidon");
  98.                                 }
  99.                         }
  100.                 });
  101.         }
  102. }
  103.  
  104. $(document).ready(function() {
  105.         fix_scroll_auto();
  106.        
  107. });
  108.  
  109. $(document).bind("touchend touchcancel", function(){
  110.         $(".scrollbar_auto").fadeOut();
  111. });

Télécharger

Version 0.2.

  • Amélioration du rendu visuel de la scrollbar.
  • Effet de transition du scroll : à la fin du scroll, si on a effectué un mouvement vertical rapide (« swipe »), le scroll continue un peu plus loin.

Version 0.3 Les clicks (pas de scroll) à l’intérieur du scroll provoquaient un décalage après un premier scroll (à noter : dans un simple « click », il n’y a semble-t-il pas de ontouchmove du tout).

Version 0.4 Optimiser le code, augmenter la vitesse d’exécution.

Qui êtes-vous ?
Votre message

Ce formulaire accepte les raccourcis SPIP [->url] {{gras}} {italique} <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.