“[aria-hidden="true"] 元素包含可聚焦的后代”;解决这个问题的最佳方法?
"[aria-hidden="true"] elements contain focusable descendents"; best way to fix that?
我有一个简单的手风琴:
<div>
<button aria-expanded='false' aria-controls='content'>
Open accordion
</button>
<div id='content' aria-hidden='true'>
This the accordion's hidden content.
</div>
</div>
我使用 Javascript 到 open/close 手风琴并设置 aria-*
标签。
一切正常,但是当我在内容中添加链接时:
<div>
<button aria-expanded='false' aria-controls='content'>
Open accordion
</button>
<div id='content' aria-hidden='true'>
This is the accordion's hidden content.
<a href='https://www.google.com'>Go to Google</a>
</div>
</div>
灯塔给我这个:
[aria-hidden="true"] elements contain focusable descendents
在我看来,将 tabindex='-1'
添加到 a
标签可以解决问题:
<a tabindex='-1' href='https://www.google.com'>Go to Google</a>
然而,这使得元素“不可制表”,不利于可访问性。
我可以使用 Javascript 手动查询手风琴内容中的所有 a
标签,但我什至不确定这是否真的解决了“问题”或者是一个肮脏的解决方法?有没有更好的选择?
谢谢。
简单的解决方案,使用 CSS display:none
属性 将元素从焦点中删除:
#content[aria-hidden=true] {
display:none;
}
这不仅有用而且非常必要,因为我们不希望屏幕阅读器宣布不可见的东西。
为什么会收到此警告?
此警告显示尽管您使用 aria-hidden="true"
如果子项可以获得焦点(以解决开发人员的错误),大多数屏幕 reader 将忽略父项上的 aria-hidden="true"
, JavaScript 加载不正确等)。
如何解决?
我假设您使用的是向上滑动动画或类似的东西,这就是为什么您不简单地在内容上使用 display: none
的原因。
如果您不使用动画,那么当您应用 aria-hidden="true"
时,只需 display: none
内容(@Adam 在他的回答中向您展示了执行此操作的完美方法)。
更好的是你可以直接在 div 上使用 display: none
因为这会隐藏屏幕上的所有内容 reader 所以你不需要使用 WAI -那里有咏叹调!
我正在使用动画/过渡,所以不能只隐藏所有内容。
如果您正在使用动画、不透明度变化等,这会阻止您简单地隐藏整个内容,那么您可以做的是将可聚焦的内容隐藏在内容中 <div>
。
我们可以在您应用 aria-hidden="true"
时使用 CSS 来执行此操作,然后在您更改或删除 aria-hidden="true"
.
时取消隐藏可聚焦元素
另外,为了在我们再次取消隐藏元素时避免“布局卡顿”,我建议使用 visibility: hidden
而不是 display: none
,因为这样会为隐藏的项目分配 space,并且仍然从屏幕 readers 等中隐藏它们
#content[aria-hidden=true] a[href],
#content[aria-hidden=true] area[href],
#content[aria-hidden=true] input:not([disabled]),
#content[aria-hidden=true] select:not([disabled]),
#content[aria-hidden=true] textarea:not([disabled]),
#content[aria-hidden=true] button:not([disabled]),
#content[aria-hidden=true] [tabindex]:not([disabled]),
#content[aria-hidden=true] [contenteditable=true]:not([disabled]){
visibility: hidden;
}
快速演示
了解我的意思的最简单方法是通过快速演示,按“切换 aria-hidden on”按钮,它将隐藏 #content <div>
中的所有可聚焦元素。
var btn = document.querySelector('#toggle-aria');
var contentDiv = document.querySelector('#content');
btn.addEventListener('click', function(){
var self = this;
if(contentDiv.getAttribute('aria-hidden') == "false"){
self.innerHTML = "Toggle aria-hidden off";
contentDiv.setAttribute('aria-hidden', "true");
}else{
self.innerHTML = "Toggle aria-hidden on";
contentDiv.setAttribute('aria-hidden', "false");
}
});
#content{
padding: 20px;
border: 1px solid #333;
}
#content[aria-hidden=true] a[href],
#content[aria-hidden=true] area[href],
#content[aria-hidden=true] input:not([disabled]),
#content[aria-hidden=true] select:not([disabled]),
#content[aria-hidden=true] textarea:not([disabled]),
#content[aria-hidden=true] button:not([disabled]),
#content[aria-hidden=true] [tabindex]:not([disabled]),
#content[aria-hidden=true] [contenteditable=true]:not([disabled]){
visibility: hidden;
}
<br/><br/><button id="toggle-aria">Toggle aria-hidden on</button>
<p>When aria-hidden is set to true on the below div all focusable elements should disappear.</p>
<hr/>
<div id="content" aria-hidden="false">
<a href="https://google.com">To Google</a><br/><br/>
<label>An input
<input />
</label><br/><br/>
<label>A Select
<select>
<option>option 1</option>
<option>option 2</option>
<option>option 3</option>
</select>
</label><br/><br/>
<label>A textarea
<textarea></textarea>
</label><br/><br/>
<button>A button</button><br/><br/>
<div tabindex="0">A fake button with tabindex</div><br/><br/>
<div contenteditable="true">A div that is cotnent editable</div><br/><br/>
<p>Only the labels and this paragraph should be the only things left showing when you toggle the aria-hidden to true</p>
</div>
<br/><br/>
<button>I am a button purely so you can see there is nothing focusable within the #content div if you "Tab"</button>
重要说明: 第二次按下“打开手风琴”按钮时,您应该删除 aria-hidden
before 任何动画等. 这是因为 screen reader 用户随后会尝试通过 Tab(或通过 screen reader 快捷方式导航)进入内容。如果您删除 aria-hidden="true"
太迟,他们可能会跳过所有内容!
我有一个简单的手风琴:
<div>
<button aria-expanded='false' aria-controls='content'>
Open accordion
</button>
<div id='content' aria-hidden='true'>
This the accordion's hidden content.
</div>
</div>
我使用 Javascript 到 open/close 手风琴并设置 aria-*
标签。
一切正常,但是当我在内容中添加链接时:
<div>
<button aria-expanded='false' aria-controls='content'>
Open accordion
</button>
<div id='content' aria-hidden='true'>
This is the accordion's hidden content.
<a href='https://www.google.com'>Go to Google</a>
</div>
</div>
灯塔给我这个:
[aria-hidden="true"] elements contain focusable descendents
在我看来,将 tabindex='-1'
添加到 a
标签可以解决问题:
<a tabindex='-1' href='https://www.google.com'>Go to Google</a>
然而,这使得元素“不可制表”,不利于可访问性。
我可以使用 Javascript 手动查询手风琴内容中的所有 a
标签,但我什至不确定这是否真的解决了“问题”或者是一个肮脏的解决方法?有没有更好的选择?
谢谢。
简单的解决方案,使用 CSS display:none
属性 将元素从焦点中删除:
#content[aria-hidden=true] {
display:none;
}
这不仅有用而且非常必要,因为我们不希望屏幕阅读器宣布不可见的东西。
为什么会收到此警告?
此警告显示尽管您使用 aria-hidden="true"
如果子项可以获得焦点(以解决开发人员的错误),大多数屏幕 reader 将忽略父项上的 aria-hidden="true"
, JavaScript 加载不正确等)。
如何解决?
我假设您使用的是向上滑动动画或类似的东西,这就是为什么您不简单地在内容上使用 display: none
的原因。
如果您不使用动画,那么当您应用 aria-hidden="true"
时,只需 display: none
内容(@Adam 在他的回答中向您展示了执行此操作的完美方法)。
更好的是你可以直接在 div 上使用 display: none
因为这会隐藏屏幕上的所有内容 reader 所以你不需要使用 WAI -那里有咏叹调!
我正在使用动画/过渡,所以不能只隐藏所有内容。
如果您正在使用动画、不透明度变化等,这会阻止您简单地隐藏整个内容,那么您可以做的是将可聚焦的内容隐藏在内容中 <div>
。
我们可以在您应用 aria-hidden="true"
时使用 CSS 来执行此操作,然后在您更改或删除 aria-hidden="true"
.
另外,为了在我们再次取消隐藏元素时避免“布局卡顿”,我建议使用 visibility: hidden
而不是 display: none
,因为这样会为隐藏的项目分配 space,并且仍然从屏幕 readers 等中隐藏它们
#content[aria-hidden=true] a[href],
#content[aria-hidden=true] area[href],
#content[aria-hidden=true] input:not([disabled]),
#content[aria-hidden=true] select:not([disabled]),
#content[aria-hidden=true] textarea:not([disabled]),
#content[aria-hidden=true] button:not([disabled]),
#content[aria-hidden=true] [tabindex]:not([disabled]),
#content[aria-hidden=true] [contenteditable=true]:not([disabled]){
visibility: hidden;
}
快速演示
了解我的意思的最简单方法是通过快速演示,按“切换 aria-hidden on”按钮,它将隐藏 #content <div>
中的所有可聚焦元素。
var btn = document.querySelector('#toggle-aria');
var contentDiv = document.querySelector('#content');
btn.addEventListener('click', function(){
var self = this;
if(contentDiv.getAttribute('aria-hidden') == "false"){
self.innerHTML = "Toggle aria-hidden off";
contentDiv.setAttribute('aria-hidden', "true");
}else{
self.innerHTML = "Toggle aria-hidden on";
contentDiv.setAttribute('aria-hidden', "false");
}
});
#content{
padding: 20px;
border: 1px solid #333;
}
#content[aria-hidden=true] a[href],
#content[aria-hidden=true] area[href],
#content[aria-hidden=true] input:not([disabled]),
#content[aria-hidden=true] select:not([disabled]),
#content[aria-hidden=true] textarea:not([disabled]),
#content[aria-hidden=true] button:not([disabled]),
#content[aria-hidden=true] [tabindex]:not([disabled]),
#content[aria-hidden=true] [contenteditable=true]:not([disabled]){
visibility: hidden;
}
<br/><br/><button id="toggle-aria">Toggle aria-hidden on</button>
<p>When aria-hidden is set to true on the below div all focusable elements should disappear.</p>
<hr/>
<div id="content" aria-hidden="false">
<a href="https://google.com">To Google</a><br/><br/>
<label>An input
<input />
</label><br/><br/>
<label>A Select
<select>
<option>option 1</option>
<option>option 2</option>
<option>option 3</option>
</select>
</label><br/><br/>
<label>A textarea
<textarea></textarea>
</label><br/><br/>
<button>A button</button><br/><br/>
<div tabindex="0">A fake button with tabindex</div><br/><br/>
<div contenteditable="true">A div that is cotnent editable</div><br/><br/>
<p>Only the labels and this paragraph should be the only things left showing when you toggle the aria-hidden to true</p>
</div>
<br/><br/>
<button>I am a button purely so you can see there is nothing focusable within the #content div if you "Tab"</button>
重要说明: 第二次按下“打开手风琴”按钮时,您应该删除 aria-hidden
before 任何动画等. 这是因为 screen reader 用户随后会尝试通过 Tab(或通过 screen reader 快捷方式导航)进入内容。如果您删除 aria-hidden="true"
太迟,他们可能会跳过所有内容!