无法通过编程方式在Chrome浏览器的iframe中设置浏览器或屏幕阅读器焦点

时间:2019-07-17 21:21:38

标签: javascript google-chrome accessibility

在做一些最近的可访问性工作时,我遇到了一个场景,即在iframe中将焦点设置为标头(设置了tabindex)对用户来说是不一致的结果,但是在Chrome隐身模式下却始终失败。

经过大量测试,我缩小了范围,提出了以下测试方案。这些需要在本地HTML文件中运行,因为测试用例在iframe中运行(例如,在Codepen上)的工作方式有所不同:

<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>"Fun" with focus!</title>
</head>
<body translate="no">
  <h1>"Fun" with focus!</h1>
  <ol>
    <li>Test the following *6* cases in Chrome incognito</li>
    <li>Enable VoiceOver on Mac by hitting Cmd + fingerprint sensor 3 times, or Cmd + F5</li>
    <li>Keyboard navigate through the sections below using tab, and activate them using space or enter.</li>
    <li>Look inside the console to make sure all 6 focus calls were made ("focusing on iframe-# header")</li>
  </ol>

  <h2>On-page IFrame</h2>
  <p>Clicking this
    <button id="btn-1">button</button>
    should work result in the IFrame header being focused on and read out
  </p>
  <div id="iframe-1-container">
    <iframe id="iframe-1"></iframe>
  </div>

  <h2>Sandboxed On-page IFrame</h2>
  <p>Clicking this
    <button id="btn-2">button</button>
    should work result in the IFrame header being focused on and read out
  </p>
  <div id="iframe-2-container">
    <iframe id="iframe-2" sandbox="allow-forms allow-modals allow-popups allow-same-origin allow-scripts"></iframe>
  </div>

  <script>
    // Render iframe-1
    document.querySelector('#btn-1').addEventListener('click', function () {
      const doc = document.querySelector('#iframe-1').contentWindow.document;
      doc.write(
        '<h1 id="header" tabindex="-1">I should be focused and read out</h1>' +
        '<button>Ignore me I am an useless button</button>' +
        '<scr' + "ipt>console.log('focusing on iframe-1 header'); document.querySelector('#header').focus();</scr" + 'ipt>');
      doc.close();
    });

    // Render iframe-2
    document.querySelector('#btn-2').addEventListener('click', function () {
      const doc = document.querySelector('#iframe-2').contentWindow.document;
      doc.write(
        '<h1 id="header" tabindex="-1">I should be focused and read out</h1>' +
        '<button>Ignore me I am an useless button</button>' +
        '<scr' + "ipt>console.log('focusing on iframe-2 header'); document.querySelector('#header').focus();</scr" + 'ipt>');
      doc.close();
    });
  </script>

  <h2>Dynamically Inserted IFrame Outside an Event Handler</h2>
  <p>Clicking this
    <button id="btn-3">button</button>
    should also result in the IFrame header being focused on and read out
  </p>
  <div id="iframe-3-container"></div>

  <h2>Dynamically Inserted Sandboxed IFrame Outside an Event Handler</h2>
  <p>Clicking this
    <button id="btn-4">button</button>
    should also result in the IFrame header being focused on and read out
  </p>
  <div id="iframe-4-container"></div>

  <script>
    // Render iframe-3
    let div = document.createElement('div');
    div.innerHTML = '<iframe id="iframe-3"></iframe>';
    document.querySelector('#iframe-3-container').appendChild(div);

    document.querySelector('#btn-3').addEventListener('click', function () {
      const doc = document.querySelector('#iframe-3').contentWindow.document;
      doc.write(
        '<h1 id="header" tabindex="-1">I should also be focused and read out</h1>' +
        '<button>Ignore me I am an useless button</button>' +
        '<scr' + "ipt>console.log('focusing on iframe-3 header'); document.querySelector('#header').focus();</scr" + 'ipt>');
      doc.close();
    });

    // Render iframe-4
    div = document.createElement('div');
    div.innerHTML = '<iframe id="iframe-4" sandbox="allow-forms allow-modals allow-popups allow-same-origin allow-scripts"></iframe>';
    document.querySelector('#iframe-4-container').appendChild(div);

    document.querySelector('#btn-4').addEventListener('click', function () {
      const doc = document.querySelector('#iframe-4').contentWindow.document;
      doc.write(
        '<h1 id="header" tabindex="-1">I should also be focused and read out</h1>' +
        '<button>Ignore me I am an useless button</button>' +
        '<scr' + "ipt>console.log('focusing on iframe-4 header'); document.querySelector('#header').focus();</scr" + 'ipt>');
      doc.close();
    });
  </script>

  <h2>Dynamically Inserted IFrame Inside an Event Handler</h2>
  <p>Clicking this
    <button id="btn-5">button</button>
    should also result in the IFrame header being focused on and read out
  </p>
  <div id="iframe-5-container"></div>

  <h2>Dynamically Inserted Sandbox IFrame Inside an Event Handler</h2>
  <p>Clicking this
    <button id="btn-6">button</button>
    probably won't result in the IFrame header being focused or read out (focus will likely stay here)
  </p>
  <div id="iframe-6-container"></div>

  <script>
  // Render iframe-5
  document.querySelector('#btn-5').addEventListener('click', function () {
    div = document.createElement('div');
    div.innerHTML = '<iframe id="iframe-5"></iframe>';
    document.querySelector('#iframe-5-container').appendChild(div);

    const doc = document.querySelector('#iframe-5').contentWindow.document;
    doc.write(
      '<h1 id="header" tabindex="-1">I should also be focused and read out</h1>' +
      '<button>Ignore me I am an useless button</button>' +
      '<scr' + "ipt>console.log('focusing on iframe-5 header'); document.querySelector('#header').focus();</scr" + 'ipt>');

    doc.close();
  });

  // Render iframe-6
  document.querySelector('#btn-6').addEventListener('click', function () {
    div = document.createElement('div');
    div.innerHTML = '<iframe id="iframe-6" sandbox="allow-forms allow-modals allow-popups allow-same-origin allow-scripts"></iframe>';
    document.querySelector('#iframe-6-container').appendChild(div);

    const doc = document.querySelector('#iframe-6').contentWindow.document;
    doc.write(
      '<h1 id="header" tabindex="-1">I will neither be focused nor read out</h1>' +
      '<button>Ignore me I am an useless button</button>' +
      '<scr' + "ipt>console.log('focusing on iframe-6 header'); document.querySelector('#header').focus();</scr" + 'ipt>');

    doc.close();
  });
  </script>
</body>
</html>

请注意,前五种情况均会导致焦点设置正确,而第六种情况则不会。具体来说,将iframe动态插入事件处理程序中并对其设置沙箱权限时,将无法正确设置内部焦点。为什么会这样?

Safari可以处理所有这些情况,Firefox也可以处理所有情况(尽管VoiceOver无法读取),但是Chrome始终无法解决这最后一种情况。

0 个答案:

没有答案