可访问 CSS-only 选项卡视图

Accessible CSS-only tab view

我在一个网站上工作,该网站需要 (a) 在没有 JavaScript 的情况下工作并且 (b) 可以通过键盘访问。

我已经使用标签目标技巧来构建选项卡视图 (https://css-tricks.com/functional-css-tabs-revisited/),但我注意到它依赖于被点击的标签。我不知道如何让它与键盘一起工作。这可能吗?

.tabs {
  background-color: #eee;
  min-height: 400px;
}

.tabs__list {
  border-bottom: 1px solid black;
  display: flex;
  flex-direction: row;
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}

.tabs__tab {
  padding: 0.5rem;
}

.tabs__content {
  display: none;
  left: 0;
  padding: 0.5rem;
  position: absolute;
  top: 100%;
}

.tabs__input {
  display: none;
}

.tabs__input+label {
  cursor: pointer;
}

.tabs__input:focus,
.tabs__input:hover {
  color: red;
}

.tabs__input:checked+label {
  color: red;
}

.tabs__input:checked~.tabs__content {
  display: block;
}
<div class="tabs">
  <ul class="tabs__list">
    <li class="tabs__tab">
      <input class="tabs__input" type="radio" id="tab-0" name="tab-group" checked>
      <label for="tab-0" class="tabs__label" tabindex="0" role="button">Tab 0</label>
      <div class="tabs__content">
        Tab 0 content
      </div>
    </li>
    <li class="tabs__tab">
      <input class="tabs__input" type="radio" id="tab-1" name="tab-group">
      <label for="tab-1" class="tabs__label" tabindex="0" role="button">Tab 1</label>
      <div class="tabs__content">
        Tab 1 content
      </div>
    </li>
  </ul>
</div>

它只是单选按钮...键盘可用于使用制表符和 space 栏来浏览它们。

我会使用 :focus 突出显示所选的选项卡,并使用 tabindex 属性 使其按我想要的方式工作。

如果您遇到与之相关的特定问题,请提供更多部门,并在此处提供基本代码示例,无链接。

由于无法通过键盘选择隐藏的输入,因此将其设为可见...

.tabs {
  background-color: #eee;
  min-height: 400px;
}

.tabs__list {
  border-bottom: 1px solid black;
  display: flex;
  flex-direction: row;
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}

.tabs__tab {
  padding: 0.5rem;
}

.tabs__content {
  display: none;
  left: 0;
  padding: 0.5rem;
  position: absolute;
  top: 100%;
}

.tabs__input {
  position: fixed;
  top:-100px;
}

.tabs__input+label {
  cursor: pointer;
}

.tabs__input:focus
.tabs__input:hover {
  color: red;
}

.tabs__input:checked+label {
  color: red;
}

.tabs__input:checked~.tabs__content {
  display: block;
}
<div class="tabs">
  <ul class="tabs__list">
    <li class="tabs__tab">
      <input class="tabs__input" type="radio" id="tab-0" name="tab-group" checked>
      <label for="tab-0" class="tabs__label" tabindex="0" role="button">Tab 0</label>
      <div class="tabs__content">
        Tab 0 content
      </div>
    </li>
    <li class="tabs__tab">
      <input class="tabs__input" type="radio" id="tab-1" name="tab-group">
      <label for="tab-1" class="tabs__label" tabindex="0" role="button">Tab 1</label>
      <div class="tabs__content">
        Tab 1 content
      </div>
    </li>
  </ul>
</div>

已接受的答案不是可访问的解决方案。

我在这里做了一些更正和一些观察。如果您将来偶然发现这个问题,请不要在生产中使用已接受的答案。使用键盘是一种糟糕的体验。

下面的答案修复了一些 CSS 问题,使其更易于访问。

但是 我建议您重新考虑没有 JavaScript 的要求。

我可以理解有一个很好的回退(我在下面给出的修复示例是)但是你无法制作一组完全可访问的 CSS 选项卡。

首先,您应该使用 WAI-ARIA 来补充您的 HTML 以使屏幕 reader 的内容更加清晰。请参阅 tabs examples on W3C 以了解您应该使用哪些 WAI-ARIA 角色。如果没有 JavaScript 这是不可能的,因为状态需要改变(例如 aria-hidden 应该改变)。

其次,您应该能够使用某些快捷键。例如,按 home 键以 return 到第一个选项卡,您只能借助一点 JS 帮助才能做到这一点。

话虽这么说,但我在接受的答案中修正了一些问题,至少可以为您提供一个良好的起点,作为您的 'no JavaScript fallback'。

问题 1 - tabindex 在标签上。

通过添加它,您将创建一个无法通过键盘激活的可聚焦元素(您不能按 spaceEnter 在标签上更改选择,除非您使用 JavaScript).

为了解决这个问题,我只是从标签中删除了 tabindex

问题 2 - 通过键盘导航时没有焦点指示器。

在示例中,选项卡仅在您关注单选按钮(隐藏)时才起作用。但是,此时没有焦点指示器,因为样式是在复选框获得焦点时将样式应用于复选框,而不是应用于其标签。

为了解决这个问题,我调整了 CSS

/*make it so when the checkbox is focused we add a focus indicator to the label.*/
.tabs__input:focus + label {
  outline: 2px solid #333;
}

问题 3 - :hover:focus 状态使用相同的状态。

这是另一个需要改掉的坏习惯,始终以不同的方式显示悬停和焦点状态。一些屏幕 reader 和屏幕放大镜用户会使用他们的鼠标来检查他们是否聚焦了正确的项目并在页面上定位自己。如果没有单独的悬停状态,则很难检查您是否悬停在焦点项目上。

/*use a different colour background on hover, you should not use the same styling for hover and focus states*/
.tabs__label:hover{
   background-color: #ccc;
}

例子

在示例中,我在顶部添加了一个超链接,这样您就可以在使用键盘时看到焦点指示器的位置。

当您的焦点指示器位于两个选项卡之一上时,您可以按箭头键更改选项卡(这是预期的行为)并且焦点指示器将相应地调整以明确选择了哪个选项卡。

.tabs {
  background-color: #eee;
  min-height: 400px;
}

.tabs__list {
  border-bottom: 1px solid black;
  display: flex;
  flex-direction: row;
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}

.tabs__tab {
  padding: 0.5rem;
}

.tabs__content {
  display: none;
  left: 0;
  padding: 0.5rem;
  position: absolute;
  top: 100%;
}

.tabs__input {
  position: fixed;
  top:-100px;
}

.tabs__input+label {
  cursor: pointer;
}


.tabs__label:hover{
   background-color: #ccc;
}

.tabs__input:focus + label {
  outline: 2px solid #333;
}

.tabs__input:checked+label {
  color: red;
}

.tabs__input:checked~.tabs__content {
  display: block;
}
<a href="#">A link so you can see where your focus indicator is</a>
<div class="tabs">
  <ul class="tabs__list">
    <li class="tabs__tab">
      <input class="tabs__input" type="radio" id="tab-0" name="tab-group" checked>
      <label for="tab-0" class="tabs__label" role="button">Tab 0</label>
      <div class="tabs__content">
        Tab 0 content
      </div>
    </li>
    <li class="tabs__tab">
      <input class="tabs__input" type="radio" id="tab-1" name="tab-group">
      <label for="tab-1" class="tabs__label" role="button">Tab 1</label>
      <div class="tabs__content">
        Tab 1 content
      </div>
    </li>
  </ul>
</div>