web-dev-qa-db-fra.com

IFRAME et Safari sur iPad, comment l'utilisateur peut-il faire défiler le contenu?

Selon le mantra Apple iOS), il devrait être possible de faire défiler le contenu d'un IFRAME en le faisant glisser avec deux doigts. Malheureusement, avec la dernière version d'iOS sur l'iPad, je n'ai pas encore trouvé de fichier Site Web avec un IFRAME qui défile à l'aide de cette méthode - aucune barre de défilement n'apparaît non plus.

Est-ce que quelqu'un sait comment un utilisateur est supposé faire défiler le contenu d'un IFRAME avec le Safari mobile?

71
Karlth

iOS 5 a ajouté le style suivant pouvant être ajouté à la div parente afin que le défilement fonctionne.

-webkit-overflow-scrolling:touch

88
Karlth

-webkit-overflow-scrolling:touch comme mentionné dans la réponse est en fait la solution possible.

<div style="overflow:scroll !important; -webkit-overflow-scrolling:touch !important;">
     <iframe src="YOUR_PAGE_URL" width="600" height="400"></iframe>
</div>

Mais si vous ne parvenez pas à faire défiler le contenu de l’iframe comme indiqué dans l’image ci-dessous, enter image description here

vous pouvez essayer de faire défiler avec 2 doigts en diagonale comme ceci,

enter image description here

En fait, cela a fonctionné dans mon cas, alors partagez-le si vous n'avez toujours pas trouvé de solution à ce problème.

24
Dipin Krishnan

Il ne semble pas que les iframes s'affichent et défilent correctement. Vous pouvez utiliser une balise d'objet pour remplacer un iframe et le contenu sera déroulable avec 2 doigts. Voici un exemple simple:

<html>
    <head>
        <meta name="viewport" content="minimum-scale=1.0; maximum-scale=1.0; user-scalable=false; initial-scale=1.0;"/>
    </head>
    <body>
        <div>HEADER - use 2 fingers to scroll contents:</div>
        <div id="scrollee" style="height:75%;" >
            <object id="object" height="90%" width="100%" type="text/html" data="http://en.wikipedia.org/"></object>
        </div>
        <div>FOOTER</div>
    </body>
</html>
9
deCastongrene

Ce n'est pas ma réponse, mais je viens de la copier à partir de https://Gist.github.com/anonymous/2388015 simplement parce que la réponse est géniale et corrige complètement le problème. Le crédit va complètement à l'auteur anonyme.

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
    $(function(){
        if (/iPhone|iPod|iPad/.test(navigator.userAgent))
            $('iframe').wrap(function(){
                var $this = $(this);
                return $('<div />').css({
                    width: $this.attr('width'),
                    height: $this.attr('height'),
                    overflow: 'auto',
                    '-webkit-overflow-scrolling': 'touch'
                });
            });
    })
</script>
7
Foreever

Comme mentionné dans d’autres publications, la combinaison des valeurs css de débordement: auto; & -webkit-overflow-scrolling: touchez;

fonctionne lorsqu'il est appliqué à la fois à l'iframe en question ET à son div parent

Avec l'effet secondaire malheureux des doubles barres de défilement sur les navigateurs non tactiles.

La solution que j'ai utilisée consistait à ajouter ces valeurs CSS via javascript/jquery. Ce qui m'a permis d'utiliser un css de base pour tous les navigateurs

if (isSafariBrowser()){
    $('#parentDivID').css('overflow', 'auto');
    $('#parentDivID').css('-webkit-overflow-scrolling', 'touch');
    $('#iframeID').css('overflow', 'auto');
    $('#iframeID').css('-webkit-overflow-scrolling', 'touch');
}

où isSafariBrowser () est défini comme suit ...

var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
var is_safari = navigator.userAgent.indexOf("Safari") > -1;

function isSafariBrowser(){
    if (is_safari){
        if (is_chrome)  // Chrome seems to have both Chrome and Safari userAgents
            return false;
        else
            return true;
    }
    return false;
}

Cela a permis à mon application de fonctionner sur un iPad Note 1) Non testé sur d'autres systèmes ios 2) Non testé ceci sur Android navigateurs sur tablettes, des modifications supplémentaires peuvent être nécessaires

(donc cette solution peut ne pas être complète)

5
Toothless Seer

C'est ce que j'ai fait pour que le défilement iframe fonctionne sur iPad. Notez que cette solution ne fonctionne que si vous contrôlez le code HTML affiché dans l'iframe.

En fait, il désactive le défilement par iframe par défaut et fait défiler la balise body à l'intérieur de l'iframe.

main.html:

<!DOCTYPE html>
<html>
<head>
<style type="text/css">
#container {
    position: absolute;
    top: 50px;
    left: 50px;
    width: 400px;
    height: 300px;
    overflow: hidden;
}
#iframe {
    width: 400px;
    height: 300px;
}
</style>
</head>
<body>

    <div id="container">
        <iframe src="test.html" id="iframe" scrolling="no"></iframe>
    </div>

</body>
</html>

test.html:

<!DOCTYPE html>
<html>
<head>
<style type="text/css">
html { 
    overflow: auto; 
    -webkit-overflow-scrolling: touch; 
}
body {
    height: 100%;
    overflow: auto; 
    -webkit-overflow-scrolling: touch;
    margin: 0;
    padding: 8px;
}
</style>
</head>
<body>
…
</body>
</html>

La même chose pourrait probablement être accomplie avec jQuery si vous préférez:

$("#iframe").contents().find("body").css({
    "height": "100%",
    "overflow": "auto", 
    "-webkit-overflow-scrolling": "touch"
});

J'ai utilisé cette solution pour que TinyMCE (wordpress editor) défile correctement sur l'iPad.

2
ccallendar

Le code ci-dessous fonctionne pour moi (merci à Christopher Zimmermann pour son message de blog http://dev.magnolia-cms.com/blog/2012/05/strategies-for-the-iframe-on-the-ipad) -problem / ). Les problèmes sont:

  1. Aucune barre de défilement ne permet à l'utilisateur de savoir qu'il peut faire défiler
  2. Les utilisateurs doivent utiliser le défilement à deux doigts
  3. Les fichiers PDF ne sont pas centrés (travaillent toujours dessus)

    <!DOCTYPE HTML>
    <html>
    <head>
      <title>Testing iFrames on iPad</title>
      <style>
      div {
        border: solid 1px green;
        height:100px;
      }
    
    .scroller{
        border:solid 1px #66AA66;
        height: 400px;
        width: 400px;
        overflow: auto;
        text-align:center;
    
    }
    </style>
    
    <table>
      <tr>
        <td><div class="scroller">
        <iframe width="400" height="400" src="http://www.supremecourt.gov/opinions/11pdf/11-393c3a2.pdf" ></iframe>
    </div>
        </td>
        <td><div class="scroller">
        <iframe width="400" height="400" src="http://www.supremecourt.gov/opinions/11pdf/11-393c3a2.pdf" ></iframe>
    </div>
        </td>
      </tr>
      <tr>
      <td><div class="scroller">
        <iframe width="400" height="400" src="http://www.supremecourt.gov/opinions/11pdf/11-393c3a2.pdf" ></iframe>
    </div>
        </td>
        <td><div class="scroller">
        <iframe width="400" height="400" src="http://www.supremecourt.gov/opinions/11pdf/11-393c3a2.pdf" ></iframe>
    </div>
        </td>
      </tr>
    </table>
    <div> Here are some additional contents.</div>
    
2
WhatsInAName

Basé sur cet article , j'ai rassemblé l'extrait de code suivant qui fournit des fonctionnalités très basiques:

<div id = "container"></div>
<script>
function setPDFHeight(){ 
        $("#pdfObject")[0].height = $("#pdfObject")[0].offsetHeight;   
}   
$('#container').append('<div align="center" style="width: 100%; height:100%; overflow: auto !important; -webkit-overflow-scrolling: touch !important;">\
      <object id="pdfObject" width="100%" height="1000000000000" align="center" data="content/lessons/12/t.pdf" type="application/pdf" onload="setPDFHeight()">You have no plugin installed</object></div>');  
</script>

Évidemment, il est loin d’être parfait (étant donné que cela augmente pratiquement la hauteur de votre page à l’infini), mais c’est la seule solution de contournement viable que j’ai trouvée jusqu’à présent.

0
periklis

Le problème

Je contribue à la maintenance d'un ancien site complexe, complexe et désordonné, dans lequel tout (littéralement) est imbriqué dans plusieurs niveaux d'iframes - dont beaucoup sont créés de manière dynamique et/ou ont un src dynamique. Cela crée les défis suivants:

  1. Toute modification de la structure HTML risque de briser les scripts et les feuilles de style qui n'ont pas été touchés depuis des années.
  2. La recherche et la correction manuelle de tous les iframes et documents src prendraient beaucoup trop de temps et d’efforts.

Parmi les solutions publiées jusqu’à présent, this est la seule que j’ai vu qui surmonte le défi 1. Malheureusement, cela ne semble pas fonctionner sur certains iframes, et lorsque cela se produit, le défilement est très complexe. glitchy (ce qui semble causer d’autres bogues sur la page, tels que des liens qui ne répondent pas et des contrôles de formulaire).

La solution

Si les remarques ci-dessus ressemblent à votre situation, vous pouvez essayer le script suivant. Il abandonne le défilement natif et rend tous les iframes déplaçables dans les limites de leur fenêtre. Vous devez seulement l'ajouter au document contenant les iframes de niveau supérieur. il appliquera le correctif en fonction de leurs besoins et de ceux de leurs descendants.

Voici un travail violon *, et voici le code:

(function() {
  var mouse = false //Set mouse=true to enable mouse support
    , iOS = /iPad|iPhone|iPod/.test(navigator.platform);
  if(mouse || iOS) {
    (function() {
      var currentFrame
        , startEvent, moveEvent, endEvent
        , screenY, translateY, minY, maxY
        , matrixPrefix, matrixSuffix
        , matrixRegex = /(.*([\.\d-]+, ?){5,13})([\.\d-]+)(.*)/
        , min = Math.min, max = Math.max
        , topWin = window;
      if(!iOS) {
        startEvent = 'mousedown';
        moveEvent = 'mousemove';
        endEvent = 'mouseup';
      }
      else {
        startEvent = 'touchstart';
        moveEvent = 'touchmove';
        endEvent = 'touchend';
      }
      setInterval(scrollFix, 500);
      function scrollFix() {fixSubframes(topWin.frames);}
      function fixSubframes(wins) {for(var i = wins.length; i; addListeners(wins[--i]));}
      function addListeners(win) {
        try {
          var doc = win.document;
          if(!doc.draggableframe) {
            win.addEventListener('unload', resetFrame);
            doc.draggableframe = true;
            doc.addEventListener(startEvent, touchStart);
            doc.addEventListener(moveEvent, touchMove);
            doc.addEventListener(endEvent, touchEnd);
          }
          fixSubframes(win.frames);
        }
        catch(e) {}
      }
      function resetFrame(e) {
        var doc = e.target
          , win = doc.defaultView
          , iframe = win.frameElement
          , style = getComputedStyle(iframe).transform;
        if(iframe===currentFrame) currentFrame = null;
        win.removeEventListener('unload', resetFrame);
        doc.removeEventListener(startEvent, touchStart);
        doc.removeEventListener(moveEvent, touchMove);
        doc.removeEventListener(endEvent, touchEnd);
        if(style !== 'none') {
          style = style.replace(matrixRegex, '$1|$3|$4').split('|');
          iframe.style.transform = style[0] + 0 + style[2];
        }
        else iframe.style.transform = null;
        iframe.style.WebkitClipPath = null;
        iframe.style.clipPath = null;
        delete doc.draggableiframe;
      }
      function touchStart(e) {
        var iframe, style, offset, coords
          , touch = e.touches ? e.touches[0] : e
          , elem = touch.target
          , tag = elem.tagName;
        currentFrame = null;
        if(tag==='TEXTAREA' || tag==='SELECT' || tag==='HTML') return;
        for(;elem.parentElement; elem = elem.parentElement) {
          if(elem.scrollHeight > elem.clientHeight) {
            style = getComputedStyle(elem).overflowY;
            if(style==='auto' || style==='scroll') return;
          }
        }
        elem = elem.ownerDocument.body;
        iframe = elem.ownerDocument.defaultView.frameElement;
        coords = getComputedViewportY(elem.clientHeight < iframe.clientHeight ? elem : iframe);
        if(coords.elemTop >= coords.top && coords.elemBottom <= coords.bottom) return;
        style = getComputedStyle(iframe).transform;
        if(style !== 'none') {
          style = style.replace(matrixRegex, '$1|$3|$4').split('|');
          matrixPrefix = style[0];
          matrixSuffix = style[2];
          offset = parseFloat(style[1]);
        }
        else {
          matrixPrefix = 'matrix(1, 0, 0, 1, 0, ';
          matrixSuffix = ')';
          offset = 0;
        }
        translateY = offset;
        minY = min(0, offset - (coords.elemBottom - coords.bottom));
        maxY = max(0, offset + (coords.top - coords.elemTop));
        screenY = touch.screenY;
        currentFrame = iframe;
      }
      function touchMove(e) {
        var touch, style;
        if(currentFrame) {
          touch = e.touches ? e.touches[0] : e;
          style = min(maxY, max(minY, translateY + (touch.screenY - screenY)));
          if(style===translateY) return;
          e.preventDefault();
          currentFrame.contentWindow.getSelection().removeAllRanges();
          translateY = style;
          currentFrame.style.transform = matrixPrefix + style + matrixSuffix;
          style = 'inset(' + (-style) + 'px 0px ' + style + 'px 0px)';
          currentFrame.style.WebkitClipPath = style;
          currentFrame.style.clipPath = style;
          screenY = touch.screenY;
        }
      }
      function touchEnd() {currentFrame = null;}
      function getComputedViewportY(elem) {
        var style, offset
          , doc = elem.ownerDocument
          , bod = doc.body
          , elemTop = elem.getBoundingClientRect().top + elem.clientTop
          , elemBottom = elem.clientHeight
          , viewportTop = elemTop
          , viewportBottom = elemBottom + elemTop
          , position = getComputedStyle(elem).position;
        try {
          while(true) {
            if(elem === bod || position === 'fixed') {
              if(doc.defaultView.frameElement) {
                elem = doc.defaultView.frameElement;
                position = getComputedStyle(elem).position;
                offset = elem.getBoundingClientRect().top + elem.clientTop;
                viewportTop += offset;
                viewportBottom = min(viewportBottom + offset, elem.clientHeight + offset);
                elemTop += offset;
                doc = elem.ownerDocument;
                bod = doc.body;
                continue;
              }
              else break;
            }
            else {
              if(position === 'absolute') {
                elem = elem.offsetParent;
                style = getComputedStyle(elem);
                position = style.position;
                if(position === 'static') continue;
              }
              else {
                elem = elem.parentElement;
                style = getComputedStyle(elem);
                position = style.position;
              }
              if(style.overflowY !== 'visible') {
                offset = elem.getBoundingClientRect().top + elem.clientTop;
                viewportTop = max(viewportTop, offset);
                viewportBottom = min(viewportBottom, elem.clientHeight + offset);
              }
            }
          }
        }
        catch(e) {}
        return {
          top: max(viewportTop, 0)
          ,bottom: min(viewportBottom, doc.defaultView.innerHeight)
          ,elemTop: elemTop
          ,elemBottom: elemBottom + elemTop
        };
      }
    })();
  }
})();

* La prise en charge de la souris du jsfiddle est activée à des fins de test. Sur un site de production, vous souhaitez définir mouse = false.

0
DoctorDestructo

Aucune des solutions jusqu’à présent ne fonctionnait complètement pour moi lorsque j’essayais (parfois, qu’un buggy sur les charges secondaires), mais comme solution de contournement, utilisez un élément object comme décrit ici, puis encapsulez un div à défilement, puis définissez l’objet de manière très haute hauteur (5000px) a fait le travail pour moi. C'est une solution de contournement importante et qui ne fonctionne pas incroyablement bien (pour commencer, les pages de plus de 5000 pixels causeraient des problèmes - 10000 pixels pour le tout complètement cassé pour moi), mais il semble que le travail soit fait dans certains de mes cas de test:

var style = 'left: ...px; top: ...px; ' +
        'width: ...px; height: ...px; border: ...';

if (isIOs) {
    style += '; overflow: scroll !important; -webkit-overflow-scrolling: touch !important;';
    html = '<div style="' + style + '">' +
           '<object type="text/html" data="http://example.com" ' +
           'style="width: 100%; height: 5000px;"></object>' +
           '</div>';
}
else {
    style += '; overflow: auto;';
    html = '<iframe src="http://example.com" ' +
           'style="' + style + '"></iframe>';
}

En espérant Apple résoudra les problèmes de Safari iFrame.

0
Philipp Lenssen