【问题标题】:Handle tabbing focus with cross-origin iFrame inside modal trap在模态陷阱中使用跨域 iFrame 处理选项卡焦点
【发布时间】:2021-10-09 02:36:49
【问题描述】:

当存在跨域 <iframe> 时,我正在尝试解决模态框内的选项卡问题。

我注意到了什么:

  1. 如果 iFrame 不是模态框的第一个或最后一个可聚焦元素,则无需使用 javascript 设置 .focus()
  2. 如果 iFrame 是模式中的第一个或最后一个可聚焦元素,我需要使用 javascript 设置 .focus() 以保持键盘可访问性。

.focus() 在此用途中受到限制。而且由于我无法设置焦点,所以模态键盘选项卡陷阱被打破了。

有人在这方面取得成功吗?

HTML 示例

有效(我不需要在 iframe 上使用 javascript 设置焦点)

<input type="text" />
<iframe />
<input type="text" />

如果 iframe 是第一个或最后一个可聚焦元素,我将需要使用 javascript 设置焦点以保持模态键盘陷阱

<input type="text" />
<iframe />

<iframe />
<input type="text" />

javascript

var KEY = {
    TAB: 9,
  },
  allowedFocusableElements =
  'a[href], area[href], input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]';

function openDialog(e) {

  // Get focusable elements.
  dialogFocusableElements = dialog.querySelectorAll(allowedFocusableElements);
  dialogFirstElement = dialogFocusableElements[0];
  dialogLastElement = dialogFocusableElements[dialogFocusableElements.length - 1];

  document.addEventListener("keydown", processKeys);
}

function processKeys(event) {
  if (event.keyCode === KEY.TAB && !event.shiftKey) {
    if (document.activeElement === dialogLastElement) {
      event.preventDefault();
      dialogFirstElement.focus();
    }
  } else if (event.keyCode === KEY.TAB && event.shiftKey) {
    if (document.activeElement === dialogFirstElement) {
      event.preventDefault();
      dialogLastElement.focus();
    }
  }
}

【问题讨论】:

    标签: javascript html iframe


    【解决方案1】:

    这一切都归结为尝试在跨域 iFrame 上使用 .focus()。由于似乎没有任何办法解决这个问题(考虑标签顺序控制和使用 javascript 的焦点),我已经(不太理想)在 iFrame 之前或之后实现了一些额外的标签元素,具体取决于它在模式中的位置。

    如果 iFrame 是第一个可聚焦元素,我们在它之前放置一个“伪”可选项卡元素,同样,如果它是最后一个可聚焦元素,我们在它之后放置一个可选项卡元素。

    这是特定的 sn-p 代码:

    var KEY = {
        TAB: 9,
      },
      allowedFocusableElements =
      'a[href], area[href], input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]';
    
    function openDialog(e) {
    
      // Get focusable elements.
      dialogFocusableElements = dialog.querySelectorAll(allowedFocusableElements);
      dialogFirstElement = dialogFocusableElements[0];
      dialogLastElement = dialogFocusableElements[dialogFocusableElements.length - 1];
    
      // Tab helpers for iFrames.
      if (dialogFirstElement.tagName && dialogFirstElement.tagName === "IFRAME") {
        iframeTabHelper = document.createElement("div");
        iframeTabHelper.setAttribute("tabindex", "0");
        iframeTabHelper.classList.add("iframe-helper-button");
        dialogFirstElement.parentNode.insertBefore(iframeTabHelper, dialogFirstElement);
    
        // Re-get focusable elements.
        dialogFocusableElements = dialog.querySelectorAll(
          allowedFocusableElements
        );
        dialogFirstElement = dialogFocusableElements[0];
      }
    
      if (dialogLastElement.tagName && dialogLastElement.tagName === "IFRAME") {
        iframeTabHelper = document.createElement("div");
        iframeTabHelper.setAttribute("tabindex", "0");
        iframeTabHelper.classList.add("iframe-helper-button");
        dialogLastElement.parentNode.insertBefore(iframeTabHelper, dialogLastElement.nextSibling);
    
        // Re-get focusable elements.
        dialogFocusableElements = dialog.querySelectorAll(
          allowedFocusableElements
        );
        dialogLastElement = dialogFocusableElements[dialogFocusableElements.length - 1];
      }
    
      document.addEventListener("keydown", processKeys);
    }
    
    function processKeys(event) {
      if (event.keyCode === KEY.TAB && !event.shiftKey) {
        if (document.activeElement === dialogLastElement) {
          event.preventDefault();
          dialogFirstElement.focus();
        }
      } else if (event.keyCode === KEY.TAB && event.shiftKey) {
        if (document.activeElement === dialogFirstElement) {
          event.preventDefault();
          dialogLastElement.focus();
        }
      }
    }
    

    不完美,但可以保持键盘跳格和陷阱功能。

    可能会添加一些检查来验证 iFrame 是否确实是跨域的,或者甚至更好的是,重写以检查是否有 any 元素会限制应用.focus(),而不仅仅是 iFrames。

    【讨论】:

      猜你喜欢
      • 2020-03-11
      • 1970-01-01
      • 2012-02-22
      • 2012-09-25
      • 2015-09-18
      • 2021-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多