web-dev-qa-db-fra.com

Solution aux bogues iframe d'iOS 11 WebKit

Description du bogue iframe iOS WebKit

iOS WebKit redimensionne les iframes à la pleine taille de leur contenu (voir photo ci-dessous). C'est un bug connu depuis 2016 et toujours pas résolu dans iOS 11: https://bugs.webkit.org/show_bug.cgi?id=155198

iOS 11

Mes découvertes actuelles

1. Pour le contenu iframe fixe (par exemple vidéo)

Il suffit d'appliquer le CSS ci-dessous, mais cela empêche le défilement du contenu iframe.

.fixed iframe {
    width: 0;
    height: 0;

    min-width: 100%;
    min-height: 100%;    
}

2. Pour le contenu iframe défilable (par exemple, les pages)

  1. Nous avons besoin de deux conteneurs iframe: un comme limite (taille fixe) et le second comme zone de défilement.
  2. Pour ajuster le contenu iframe, son conteneur div doit avoir w/h défini en pixels. Toutes les mesures relatives (comme%, vw/vh) ne fonctionnent pas.
  3. Certaines pages RWD (disons avec "RWD incomplète") connaissent un débordement d'iframe (iframe ne rentre pas dans le conteneur iframe). Malheureusement, nous ne pouvons pas résoudre ce problème depuis l'iframe à l'extérieur et pour résoudre ce problème, le document à l'intérieur d'iframe nécessite au moins:

    body {
        max-width: 100vw !important;
    }
    

    Facultativement, nous pouvons mettre à l'échelle le contenu iframe en dernier recours.

  4. En raison de 2, pour conserver la proportion de conteneurs, nous devons utiliser au moins des requêtes de médias CSS ou JS pour ajuster sa hauteur.

Quelques solutions incomplètes :

Ma solution de contournement est publiée en réponse.

7
Krzysztof Przygoda

C'est ce que je suis venu jusqu'ici. Toute contribution très appréciée. Version la plus récente sur Github Gist .

/* 1. Beautifiers (optional) */

iframe {
    border: none;
    width: 100%;
    height: 100%;
}

.simple-container {
    width: 50vw;
    height: 50vh;
    padding: 1em;
}

/* 2. Resolving iOS iframe rendering issue */

/* 2.1. Sizing reorganization (obligatory) */

.popover {
    /* To control popover size by .popover-body instead of .popover */
    max-width: 100% !important;
}

.popover-body {
    box-sizing: border-box;
    max-width: 100%;
    max-height: 100%;
}

.iframe-container,
.iframe-container iframe {
    width: 100%;
    height: 100%;
    
    margin: 0 !important;
    padding: 0 !important;
    box-sizing: border-box;
}

.fixed iframe {
    /* This only fits iframe inside iframe-container but prevents scrolling */
    width: 0;
    height: 0;
    
    min-width: 100%;
    min-height: 100%;
}

.popover-body {
    width: 640px; height: 360px;
}

/* 2.2. RWD Resizings (optional) */

@media only screen and (max-width: 568px)
{
    .rwd .popover-body {
        width: 320px; height: 180px;
    }    
}

@media only screen and (min-width: 569px) and (max-width: 965px)
{
    .rwd .popover-body {
        width: 480px; height: 270px;
    }    
}

@media only screen and (min-width: 968px) and (max-width: 1023px)
{
    .rwd .popover-body {
        width: 640px; height: 360px;
    }    
}

/* 2.3. Resolving iOS iframe scrolling issue (obligatory) */

/*
    Due to iOS WebKit bug an iframe content cannot be scrolled, because WebKit renders entire iframe content:
    https://bugs.webkit.org/show_bug.cgi?id=155198
    (still not resolved on iOS11)
    The workaround is to scroll an div container content with full iframe rendered inside.
*/

.scroll {
    overflow: scroll !important;
    -webkit-overflow-scrolling: touch !important;
}

/* 2.4. Resolving iframe and container double scrollbars on desktop browsers (rather obligatory) */

.no-scrollbar {
    position: relative;
}

.no-scrollbar iframe {
    position: absolute;
    top: 0;
    left: 0;
}

.no-scrollbar {
    /* Hide scrollbars in IE Edge */
    /* Autohiding is needed inside iframe document */
    /*-ms-overflow-style: -ms-autohiding-scrollbar;*/
    /* In the parent iframe container we don't want any scrollbars */
    -ms-overflow-style: none;
}

/* 3. Scale non-RWD iframe content (optional) */

/* Warning! iOS 11 Safari crashes on two-fingers zoom of a page with scaled iframe */

.scale {   
    -ms-transform-Origin: 0 0;
    -moz-transform-Origin: 0 0;
    -o-transform-Origin: 0 0;
    -webkit-transform-Origin: 0 0;
    transform-Origin: 0 0;    
}

.scale.x2 {
    width: 200% !important;
    height: 200% !important;
    
    -ms-transform: scale(0.5);
    -moz-transform: scale(0.5);
    -o-transform: scale(0.5);
    -webkit-transform: scale(0.5);
    transform: scale(0.5);
}

.scale.x4 {
    width: 400% !important;
    height: 400% !important;
    
    -ms-transform: scale(0.25);
    -moz-transform: scale(0.25);
    -o-transform: scale(0.25);
    -webkit-transform: scale(0.25);
    transform: scale(0.25);
}

/* DEBUG */

/* To receive click events on iOS */
/*
* {
    cursor: pointer;    
}
*/
.popover-body {
    border: 1px green dotted;
}

.simple-container,
.iframe-container {
    border: 1px blue dotted;
}

iframe {
    border: 1px red dotted;
}
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>iOS iframes</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta http-equiv="cache-control" content="no-cache" />

        <!-- Solution -->
        <link rel="stylesheet" href="iframe.css" />
        
        <!-- Bootstrap with Popover -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" />
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.bundle.min.js"></script>    
        <script>
            jQuery(function ($) {
                $('a.popover-me').on('click', function(e) {
                    e.preventDefault();
                    if (!$(this).data('bs.popover')) $(this).popover({
                        container: 'body',
                        boundary: 'window',
                        placement: 'auto',
                        trigger: 'manual',
                        html: true,
                        title: $(this).text(),
                        content: '<div class="iframe-container scroll no-scrollbar"><iframe src="' + this.href + '"></iframe></div>'
                    });
                    $(this).popover('toggle');
                });
            });
        </script>
    </head>
    <body class="rwd" style="padding: 2em;">
        <h2>Embracing iOS WebKit weirdness with iframes</h2>
        <div class="alert alert-primary" role="alert">
            Ready for Bootstrap v4.0.0 <a class="popover-me" href="https://en.wikipedia.org/wiki/WebKit">Popover</a>.
        </div>
        <div class="alert alert-danger" role="alert">
            Display this page on iOS device.
        </div>        
        <h3>1. Workaround for scrollable iframe</h3>
        
        <p>
            <div class="popover-body">
                <div class="iframe-container scroll no-scrollbar">
                    <iframe src="https://en.wikipedia.org/wiki/WebKit"></iframe>
                </div>
            </div>
        </p>
        
        <div class="alert alert-warning" role="alert">
            <strong>Hint: </strong>
            <em>
                Some RWD pages (let's say with "incomplete RWD") are experiencing iframe overflow (iframe does not fit into the iframe-container).
                Unfortunately, we can't fix that from the iframe outside and to solve this issue, document inside iframe requires at least:
            </em>
            <br /><br />
<pre>
body {
    /* Resolves iOS overflow rendering bug */
    max-width: 100vw !important;
}
</pre>
            <em>
                Optionally, you can scale iframe document as below.
            </em>
        </div>
        
        <h3>2. Workaround for non-RWD scrollable iframe</h3>
        
        <em>
            Page inside iframe is zoomed out to 50%.
        </em>
        
        <p>
            <div class="popover-body">
                <div class="iframe-container scroll no-scrollbar scale x2">
                    <iframe src="https://en.wikipedia.org/wiki/WebKit"></iframe>
                </div>
            </div>
        </p>
        
        <h3>3. Workaround for fixed iframe</h3>
        
        <em>
            iframe fits in iframe-container.
        </em>
        
        <p>
            <div class="popover-body">
                <div class="iframe-container fixed scroll no-scrollbar">
                    <iframe src="https://en.wikipedia.org/wiki/WebKit"></iframe>
                </div>
            </div>
        </p>
        
        <h3>4. [BUG] Plain iframe inside simple container</h3>
        
        <em>
            iframe should fit into simple container.
        </em>

        <p>
            <div class="simple-container">
                <iframe src="https://en.wikipedia.org/wiki/WebKit"></iframe>
            </div>
        </p>
    </body>
</html>
14
Krzysztof Przygoda