iOS 11 WebKit iframe bug的解决方法

9

iOS WebKit iframe bug说明

iOS WebKit会将iframe调整为其内容的全尺寸(见下图)。这是自2016年以来已知的错误,在iOS 11中仍未解决:https://bugs.webkit.org/show_bug.cgi?id=155198

iOS 11

我的当前发现

1. 对于固定的iframe内容(例如视频)

只需应用以下CSS即可,但它会防止iframe内容滚动。

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

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

2. 对于可滚动的iframe内容(例如页面)

  1. We need two iframe containers: one as a boundary (fixed size) and second one as a scrolling area.
  2. To fit iframe contents, its div container must have w/h defined in pixels. Any relative measures (like %, vw/vh) doesn't work.
  3. 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:

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

    Optionally, we can scale iframe content as a last resort.

  4. Because of 2, to keep container proportion we need to use at least CSS media queries or JS to adjust its height.

一些不完整的解决方案:

我的解决方法已经发布在答案中。

1个回答

14

这是我目前的成果。非常感谢任何贡献。最新版本在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>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接