如何修复手风琴拼贴菜单的Tab键顺序?

时间:2018-05-03 19:20:41

标签: javascript jquery html css accessibility

我正在创建一个tile / accordion实用程序。 点击图块后,我将通过在最近的第三个li元素下面附加div内容来显示与该图块相关的内容,并将手动将焦点设置到该div内容部分。

我现在可以在JS和CSS的帮助下实现此功能:

enter image description here

但是,可访问性/标签顺序功能搞砸了。如果我点击Tile 1并显示内容(div将附加在第三个li元素下面),使用键盘进行Tab键,在链接后焦点应该转到Tile 2,但它会转到Tile 4(因为DOM中元素的顺序是按顺序排列的,并且我以不同的顺序对元素进行了相对定位以便显示。

如果我删除了元素的相对位置,那么外观就会搞砸了。

我认为可以解决的可能解决方案:

  1. 删除元素的相对位置以及每次点击图块,计算顶部,左侧位置值并相对重新对齐图块的位置。

  2. 使用键盘事件,按所需顺序强制对焦。

  3. 有没有人有任何建议可以轻松解决此问题?

    更正标签顺序:

    1. 如果单击了Tile 1,

      • 第一个标签 - 专注于div内的链接。
      • 第二个标签 - 焦点应转移到平铺2。
      • 第三个标签 - 焦点应移至平铺3。
      • 第四个标签 - 焦点应移至平铺4。
    2. 如果单击了Tile 2,

      • 第一个标签 - 专注于div内的链接。
      • 第二个标签 - 焦点应移至平铺。
      • 第三个标签 - 焦点应移至平铺。
      • 第四个标签 - 焦点应移至Tile
    3. 
      
      $(document).ready(function() {
      
          $("#tiles > li").click(function() {
              var idVal = $(this).find("a").attr("rel");
      
              dynamicContainerClass = "";
      
              var indexVal = parseInt($(this).attr("rel"));
              $(".dynamicContainer").remove();
      
              var id = parseInt($(this).attr("rel"));
              var $positionObj = $("#contentDiv").html();
      
              //$('<div class=dynamicContainer aria-live="assertive" tabindex="-1"><div id=' + id + " class=" + dynamicContainerClass + ">" + $positionObj + "</div></div>").insertAfter($(this))
      
              if (indexVal % 3 == 1) {
                  var next = $(this).next();
                  var nextCtr = 1;
                  while (next.hasClass("active") == false) {
                      next = next.next();
                      nextCtr++;
                      if (nextCtr > 12) {
                          break
                      }
                  }
                  var afterNext = next.next();
                  var afterNextCtr = 1;
                  while (afterNext.hasClass("active") == false) {
                      afterNext = afterNext.next();
                      afterNextCtr++;
                      if (afterNextCtr > 12) {
                          break
                      }
                  }
                  if (afterNext.size() > 0) {
                      $('<div class=dynamicContainer aria-live="assertive" tabindex="-1"><div id=' + id + " class=" + dynamicContainerClass + ">" + $positionObj + "</div></div>").insertAfter(afterNext)
                  } else {
                      if (next.size() > 0) {
                          $('<div class=dynamicContainer aria-live="assertive" tabindex="-1"><div id=' + id + " class=" + dynamicContainerClass + ">" + $positionObj + "</div></div>").insertAfter(next)
                      } else {
                          $('<div class=dynamicContainer aria-live="assertive" tabindex="-1"><div id=' + id + " class=" + dynamicContainerClass + ">" + $positionObj + "</div></div>").insertAfter($(this))
                      }
                  }
              } else {
                  if (indexVal % 3 == 2) {
                      var nextCtr = 1;
                      var next = $(this).next();
                      while (next.hasClass("active") == false) {
                          next = next.next();
                          nextCtr++;
                          if (nextCtr > 12) {
                              break
                          }
                      }
                      if (next.size() > 0) {
                          $('<div class=dynamicContainer aria-live="assertive" tabindex="-1"><div id=' + id + " class=" + dynamicContainerClass + ">" + $positionObj + "</div></div>").insertAfter(next)
                      } else {
                          $('<div class=dynamicContainer aria-live="assertive" tabindex="-1"><div id=' + id + " class=" + dynamicContainerClass + ">" + $positionObj + "</div></div>").insertAfter($(this))
                      }
                  } else {
                      if (indexVal % 3 == 0) {
                          $('<div class=dynamicContainer aria-live="assertive" tabindex="-1"><div id=' + id + " class=" + dynamicContainerClass + ">" + $positionObj + "</div></div>").insertAfter($(this))
                      }
                  }
              }
      
              $(".dynamicContainer #" + id).addClass("container-text").attr("tabindex", "-1").focus();
      
          });
      
      });
      &#13;
      .tiles-module {
          font-size: 12px;
          font-family: Arial;
          display: block;
          width: 292px;
          background-color: #e5e2da;
          margin: 0 10px;
          min-height: 1px;
      }
      
      .tiles-module .tiles-header {
          font-family: Arial;
          font-size: 18px;
          margin: 0 0 1px 16px;
          color: #6b5e51;
          padding-top: 3px;
      }
      
      .tiles-module #tiles>li {
          float: left;
          width: 95px;
          height: 89px;
          padding: 0;
          margin: 0 1px 1px 0;
      }
      
      .tiles-module img {
          cursor: pointer;
      }
      
      .tiles-module .tab-container li a {
          background-color: #fff;
          border: medium none;
          color: #605952;
          cursor: pointer;
          display: inline-block;
          height: 85px;
          outline: medium none;
          text-decoration: none !important;
          width: 91px;
          border-right: 2px solid #b6b5b2;
          border-bottom: 2px solid #b6b5b2;
      }
      
      .tiles-module .tab-container {
          margin-left: 4px;
      }
      
      ul {
          margin: 0;
          padding: 0;
      }
      
      li {
          list-style: none;
      }
      
      .tiles-module .dynamicContainer {
          position: relative;
          top: -3px;
      }
      
      .tiles-module .tab-container .container-text {
          width: 284px;
          float: left;
          margin-bottom: 1px;
          margin-top: 3px;
      }
      
      .tiles-module .container-text {
          display: inline-block;
          position: relative;
          background-color: #FFF;
          width: 268px;
      }
      
      .container-text {
          height: 100px;
          text-align: center;
      }
      
      .tiles-module .tab-container li a:focus, .tiles-module .tab-container li a:active {
          background-color: #B0E9FD;
      }
      &#13;
      <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
      
      <body>
          <div class="tiles-module">
              <div class="tiles-tab">
                  <div class="tab-container">
                      <div class="tiles-header">
                          <h3>Tiles Section</h3>
                      </div>
                      <ul id="tiles">
                          <li class="active" rel="1">
                              <a href="javascript:void(0);" >
                                  <p>Tile 1</p>
                              </a>
                          </li>
                          <li class="active" rel="2">
                              <a href="javascript:void(0);" >
                                  <p>Tile 2</p>
                              </a>
                          </li>
                          <li class="active" rel="3">
                              <a href="javascript:void(0);">
                                  <p>Tile 3</p></a>
                          </li>
                          <li class="active" rel="4">
                              <a href="javascript:void(0);">
                                  <p>Tile 4</p>
                              </a>
                          </li>
                          <li class="active" rel="5">
                              <a href="javascript:void(0);">
                                  <p>Tile 5</p>
                              </a>
                          </li>
                          <li class="active" rel="6">
                              <a href="javascript:void(0);">
                                  <p>Tile 6 </p>
                              </a>
                          </li>
                          <li class="active" rel="7">
                              <a href="javascript:void(0);">
                                  <p>Tile 7 </p>
                              </a>
                          </li>
      
                          <li class="active" rel="8">
                              <a href="javascript:void(0);">
                                  <p>Tile 8</p>
                              </a>
                          </li>
      
                      </ul>
                  </div>
                  <div class="ClearAll" style="clear:both;"></div>
              </div>
              <div id="contentDiv" style="display:none;">This is the tile content <a href="javascript:void(0);">This is link focusable element inside tile content</a></div>
          </div>
      </body>
      &#13;
      &#13;
      &#13;

      代码 - https://jsbin.com/rezehepuju/edit?html,css,js,output

2 个答案:

答案 0 :(得分:0)

如果可能的话,尝试使用tabindex 避免。如果瓷砖是您页面上唯一的东西,那么弄乱tabindex可能没问题。但是,一旦设置了一个对象的tabindex,就必须为所有对象设置它。也就是说,您必须完全控制页面上所有内容的Tab键顺序。它变得非常混乱。

Tab键的DOM顺序通常是最佳顺序,所以如果你必须更改Tab键顺序,通常最好更改你的DOM。

但是,请记住,低视力用户,尤其是那些使用放大镜(如ZoomText)的人,可能会对您的标签顺序感到困惑,因为它不一致。放大镜将滚动页面以使焦点保持在视图中。

如果图块1已打开,则订单为:

  1. tile 1
  2. 链接
  3. tile 2
  4. tile 3
  5. 如果图块2已打开,则订单为:

    1. tile 1
    2. tile 2
    3. 链接
    4. tile 3
    5. 如果图块3已打开,则订单为:

      1. tile 1
      2. tile 2
      3. tile 3
      4. 链接
      5. 屏幕放大镜将以“看似”随机的方式不断地来回移动。在跳到开放区域之前,用户不知道焦点是否会在瓷砖上移动。

        这不能回答你原来的问题(虽然tabindex是一种答案),但希望从可访问性的角度提供一些思考的食物。

答案 1 :(得分:0)

使用此解决方案能够实现预期的标签顺序。使用绝对,顶部,左侧属性重新定位切片。它奏效了。

&#13;
&#13;
$(document).ready(function() {

    $("#tiles > li").click(function() {
        var idVal = $(this).find("a").attr("rel");

        dynamicContainerClass = "";

        var indexVal = parseInt($(this).attr("rel"));
        $(".dynamicContainer").remove();

        var id = parseInt($(this).attr("rel"));
        var $positionObj = $("#contentDiv").html();

        var listItems = $("#tiles li");
        listItems.each(function(idx, li) {
	     $(li).css({'position':'','top':'','left':''});
        });

        //$('<div class=dynamicContainer aria-live="assertive" tabindex="-1"><div id=' + id + " class=" + dynamicContainerClass + ">" + $positionObj + "</div></div>").insertAfter($(this))

        if (indexVal % 3 == 1) {
            var next = $(this).next();
            var positionOne = next.position();
            var nextCtr = 1;
            while (next.hasClass("active") == false) {
                next = next.next();
                nextCtr++;
                if (nextCtr > 12) {
                    break
                }
            }
            var afterNext = next.next();
            var positionTwo = afterNext.position();
            var afterNextCtr = 1;
            while (afterNext.hasClass("active") == false) {
                afterNext = afterNext.next();
                afterNextCtr++;
                if (afterNextCtr > 12) {
                    break
                }
            }
            if (afterNext.size() > 0) {
                $('<div class=dynamicContainer aria-live="assertive" tabindex="-1"><div id=' + id + " class=" + dynamicContainerClass + ">" + $positionObj + "</div></div>").insertAfter($(this));
               afterNext.css('position','absolute');
		       afterNext.css('left',positionTwo.left);
		       afterNext.css('top',positionTwo.top);
		       next.css('position','absolute');
		       next.css('left',positionOne.left);
		       next.css('top',positionOne.top);
            } else {
                if (next.size() > 0) {
                    $('<div class=dynamicContainer aria-live="assertive" tabindex="-1"><div id=' + id + " class=" + dynamicContainerClass + ">" + $positionObj + "</div></div>").insertAfter($(this));
                    next.css('position','absolute');
		            next.css('left',positionOne.left);
		            next.css('top',positionOne.top);
                } else {
                    $('<div class=dynamicContainer aria-live="assertive" tabindex="-1"><div id=' + id + " class=" + dynamicContainerClass + ">" + $positionObj + "</div></div>").insertAfter($(this))
                }
            }
        } else {
            if (indexVal % 3 == 2) {
                var nextCtr = 1;
                var next = $(this).next();
                var positionOne = next.position();
                while (next.hasClass("active") == false) {
                    next = next.next();
                    nextCtr++;
                    if (nextCtr > 12) {
                        break
                    }
                }
                if (next.size() > 0) {
                    $('<div class=dynamicContainer aria-live="assertive" tabindex="-1"><div id=' + id + " class=" + dynamicContainerClass + ">" + $positionObj + "</div></div>").insertAfter($(this));
                    next.css('position','absolute');
		            next.css('left',positionOne.left);
		            next.css('top',positionOne.top);
                } else {
                    $('<div class=dynamicContainer aria-live="assertive" tabindex="-1"><div id=' + id + " class=" + dynamicContainerClass + ">" + $positionObj + "</div></div>").insertAfter($(this))
                }
            } else {
                if (indexVal % 3 == 0) {
                    $('<div class=dynamicContainer aria-live="assertive" tabindex="-1"><div id=' + id + " class=" + dynamicContainerClass + ">" + $positionObj + "</div></div>").insertAfter($(this))
                }
            }
        }

        $(".dynamicContainer #" + id).addClass("container-text").attr("tabindex", "-1").focus();

    });

});
&#13;
.tiles-module {
    font-size: 12px;
    font-family: Arial;
    display: block;
    width: 292px;
    background-color: #e5e2da;
    margin: 0 10px;
    min-height: 1px;
}

.tiles-module .tiles-header {
    font-family: Arial;
    font-size: 18px;
    margin: 0 0 1px 16px;
    color: #6b5e51;
    padding-top: 3px;
}

.tiles-module #tiles>li {
    float: left;
    width: 95px;
    height: 89px;
    padding: 0;
    margin: 0 1px 1px 0;
}

.tiles-module img {
    cursor: pointer;
}

.tiles-module .tab-container li a {
    background-color: #fff;
    border: medium none;
    color: #605952;
    cursor: pointer;
    display: inline-block;
    height: 85px;
    outline: medium none;
    text-decoration: none !important;
    width: 91px;
    border-right: 2px solid #b6b5b2;
    border-bottom: 2px solid #b6b5b2;
}

.tiles-module .tab-container {
    margin-left: 4px;
}

ul {
    margin: 0;
    padding: 0;
}

li {
    list-style: none;
}

.tiles-module .dynamicContainer {
    position: relative;
    top: -3px;
}

.tiles-module .tab-container .container-text {
    width: 284px;
    float: left;
    margin-bottom: 1px;
    margin-top: 3px;
}

.tiles-module .container-text {
    display: inline-block;
    position: relative;
    background-color: #FFF;
    width: 268px;
}

.container-text {
    height: 100px;
    text-align: center;
}

.tiles-module .tab-container li a:focus, .tiles-module .tab-container li a:active {
    background-color: #B0E9FD;
}
&#13;
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>

<body>
    <div class="tiles-module">
        <div class="tiles-tab">
            <div class="tab-container">
                <div class="tiles-header">
                    <h3>Tiles Section</h3>
                </div>
                <ul id="tiles">
                    <li class="active" rel="1">
                        <a href="javascript:void(0);" >
                            <p>Tile 1</p>
                        </a>
                    </li>
                    <li class="active" rel="2">
                        <a href="javascript:void(0);" >
                            <p>Tile 2</p>
                        </a>
                    </li>
                    <li class="active" rel="3">
                        <a href="javascript:void(0);">
                            <p>Tile 3</p></a>
                    </li>
                    <li class="active" rel="4">
                        <a href="javascript:void(0);">
                            <p>Tile 4</p>
                        </a>
                    </li>
                    <li class="active" rel="5">
                        <a href="javascript:void(0);">
                            <p>Tile 5</p>
                        </a>
                    </li>
                    <li class="active" rel="6">
                        <a href="javascript:void(0);">
                            <p>Tile 6 </p>
                        </a>
                    </li>
                    <li class="active" rel="7">
                        <a href="javascript:void(0);">
                            <p>Tile 7 </p>
                        </a>
                    </li>

                    <li class="active" rel="8">
                        <a href="javascript:void(0);">
                            <p>Tile 8</p>
                        </a>
                    </li>

                </ul>
            </div>
            <div class="ClearAll" style="clear:both;"></div>
        </div>
        <div id="contentDiv" style="display:none;">This is the tile content <a href="javascript:void(0);">This is link focusable element inside tile content</a></div>
    </div>
</body>
&#13;
&#13;
&#13;