Вызов element.focus() в iframe прокручивает родительскую страницу в случайную позицию в Safari iOS10

Safari на iOS 10.1.1, похоже, имеет ошибку при настройке фокуса на элемент внутри iframe.

Когда мы вызываем element.focus() в элементе внутри iframe, Safari будет немедленно прокручивать родительскую страницу вниз и перемещать фокусный элемент вне экрана (вместо прокрутки фокусного элемента в виде). ​​

Однако это происходит только в том случае, если элемент находится в iframe, который выше высоты экрана устройства (более короткие iframe в порядке).

Итак, если есть два элемента: один в верхней части iframe и еще один ниже страницы, первый будет фокусироваться отлично, а второй будет выходить за пределы экрана, когда мы устанавливаем фокус.

Мне кажется, что Safari пытается прокручивать элемент в представлении, но математика ошибочна, и они заканчивают прокрутку в случайную позицию дальше по странице. Все работает нормально в iOS9, поэтому я думаю, что это новая ошибка в iOS10.

Есть ли способ предотвратить прокрутку родительской страницы или какой-либо другой способ избежать этой ошибки?

Я собрал одностраничный текст, который реплицирует проблему на устройствах iOS 10 или симуляторе.

Вот URL, который вы действительно можете использовать на телефоне: goo.gl/QYi7OE

Здесь плункер, чтобы вы могли проверять поведение на рабочем столе: https://embed.plnkr.co/d61KtGlzbVtVYdZ4AMqb/

И главная версия этого plunker: https://gist.github.com/Coridyn/86b0c335a3e5bf72e88589953566b358

Здесь runnable версия gist (укороченный URL выше пунктов здесь): https://rawgit.com/Coridyn/86b0c335a3e5bf72e88589953566b358/raw/62a792bfec69b2c8fb02b3e99ff712abda8efecf/ios-iframe-bug.html

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="apple-mobile-web-app-capable" content="yes" />

    <script>
    document.addEventListener('DOMContentLoaded', function(){
        document.querySelector('#frame').srcdoc = document.querySelector('#frameContent').innerHTML;
    });
    </script>
</head>
<body>
    <iframe id="frame" frameborder="1"
        style="width: 100%; height: 1200px;"
        width="100%" height="1200">
    </iframe>

    <!--
    To keep this a one-page example, the content below will be inserted into the iframe using the `srcdoc` attribute.

    The problem occurs in iOS10 regardless of using `srcdoc` or `src` (and regardless of same-domain or cross-domain content).
    -->
    <script id="frameContent" type="text/template">
<div>
    <style>
        .spacer {
            padding-top: 400px;
            padding-bottom: 400px;
        }
        .green-block {
            width: 20px;
            height: 20px;
            background-color: green;
        }
        .red-block {
            width: 20px;
            height: 20px;
            background-color: red;
        }
    </style>

    <div class="green-block" tabindex="0"></div>

    <p>Scroll down and press the 'Focus Green' or 'Focus Red' button.</p>

    <h2>'Focus Green'</h2>
    <p><b>Expected:</b> should set focus on '.green-block' and scroll to the top of the page.</p>
    <p><b>Actual:</b> sets focus but does not scroll page.</p>

    <h2>'Focus Red'</h2>
    <p><b>Expected:</b> should set focus on '.red-block' and not scroll page (because element is already on-screen).</p>
    <p><b>Actual:</b> sets focus and scrolls down to the bottom of the host page.</p>

    <hr/>

    <p class="spacer">1 Filler content to force some visible scrolling 1</p>

    <div class="red-block" tabindex="0"></div>

    <div>
        <button type="button" onclick="document.querySelector('.green-block').focus();">Focus Green</button>
        <p>'Focus Green' should go to top of page, but on iOS10 the view doesn't move.</p>
    </div>
    <div>
        <button type="button" onclick="document.querySelector('.red-block').focus();">Focus Red</button>
        <p>'Focus Red' should stay here, but on iOS10 the view scrolls to the bottom of the page</p>
    </div>

    <p class="spacer">20 Filler content to force some visible scrolling 20</p>
    <p>Bottom of iframe</p>

</div>
    </script>

</body>
</html>

Что мы нашли:

  • Проблема происходит в iOS 10+ как в Safari, так и в Chrome
  • Проблема не выполняется в Safari iOS 9.3.2 (поведение соответствует браузеру рабочего стола, как и ожидалось)
  • Проблема возникает только при фокусировке на элементах без ввода HTML, например. DIVs, SPANs, метки привязки и т.д.; настройка фокуса на элементах INPUT работает правильно
  • Desktop Safari отлично работает
  • Это родительская страница, которая прокручивается, а не iframe (iframe имеет размер до 100% его содержимого, чтобы избежать прокрутки внутри фрейма).
  • Мы попытались вызвать preventDefault на родительской странице с помощью window.onscroll = (event) => event.preventDefault();, но это не работает, потому что событие scroll не отменяется
  • Событие scroll, поднятое на родительской странице, похоже, поступает из самого Safari/Webkit, потому что в стоп-кадре нет других функций (при проверке с помощью DevTools и Error.stack)

Ответы

Ответ 1

У меня была аналогичная проблема с прокруткой на iOS. Это происходило на всех версиях iOS для меня, 8, 9 и 10.

Тестирование вашего плунжера на реальном устройстве iOS 10 не вызывало проблемы для меня. Я не уверен, правильно ли я тестировал.

Можете ли вы попробовать эту версию вашего плункера на iOS? https://embed.plnkr.co/NuTgqW/

Мое обходное решение для моей проблемы состояло в том, чтобы убедиться, что тег body и html в содержимом iframe имеет определенную высоту и ширину 100% и прокрутку переполнения. Это позволило принудительно измерить размер iframe. Это предотвратило скачок прокрутки.

Сообщите мне, если это поможет.