英文:
Screen reader capturing hidden content on carousel
问题
以下是您要翻译的内容:
I have a carousel as follows. It scrolls horizontally on click.
I intent to only show 3 items at a time. Rest will be hidden via overflow hidden.
Clicking right or left will hide/reveal more tiles.
But the screen reader
is currently reading out the hidden items too since it can capture the overflow hidden content.
<br/>This is wrong. It should have read out only the 3 visible items.
Imagine I have scrolled left once so item 1 is now hidden. Yet it still reads out:
> 1 long text ..
I could overcome this by adding aria-hidden: true
for the hidden items.
<br/>Based on currentPos
, update the aria-hidden=true or false
values dynamically for each item. This works.
But this introduces a new problem.
There are 6 items. So previously the screen reader at start will read out.
> List 6 items. You are currently in a list.
But since now I am hiding items, it ends up reading only 3 items existing:
> List 3 items. You are currently in a list.
Not sure if this is acceptable by accessibility standards.
Is there a way around this.
The question is: How can I stop screen reader from reading hidden content.
<br/>But at the same time the screen should still know there are 6 items so that it can call that out as usual.
<br/>Is this even possible. Or the reducing in list size in the read out is acceptable. Not found any references on it.
P.S: Using mac's inbuilt screen reader for testing.
The component. Stylings not added here to keep it simple.
import React, { useState } from 'react';
const Carousel = () => {
const [currentPos, setCurrentPos] = useState(0);
const handleLeftClick = () => {
if (currentPos === 0) return;
setCurrentPos(currentPos - 1);
};
const handleRightClick = () => {
setCurrentPos(currentPos + 1);
};
return (
<div className="carousel">
<ul className="carousel-inner" style={{ transform: `translateX(${-currentPos * 350}px)` }}>
{/* is dynamic can have more or less than 6 items*/}
<li className="carousel-item">1 long text ..</li>
<li className="carousel-item">2 long text ..</li>
<li className="carousel-item">3 long text ..</li>
<li className="carousel-item">4 long text ..</li>
<li className="carousel-item">5 long text ..</li>
<li className="carousel-item">6 long text ..</li>
</ul>
<div className="carousel-arrow left" onClick={handleLeftClick}>&lt;<</div>
<div className="carousel-arrow right" onClick={handleRightClick}>&gt;</div>
</div>
);
};
export default Carousel;
建议的解决方案供参考。
<br/>Using mac's default screen reader.
<br/>Won't work cos the screen reader reads out:
> List My Custom List 4 items
Was expecting just:
> My Custom List
<!DOCTYPE html>
<body>
<div>
<button>Click me!</button>
<br/>
<br/>
<ul aria-label="My Custom List">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
<br/>
<br/>
</div>
<br/>
</body>
</html>
英文:
I have a carousel as follows. It scrolls horizontally on click.
I intent to only show 3 items at a time. Rest will be hidden via overflow hidden.
Clicking right or left will hide/reveal more tiles.
But the screen reader
is currently reading out the hidden items too since it can capture the overflow hidden content.
<br/>This is wrong. It should have read out only the 3 visible items.
Imagine I have scrolled left once so item 1 is now hidden. Yet it still reads out:
> 1 long text ..
I could overcome this by adding aria-hidden: true
for the hidden items.
<br/>Based on currentPos
, update the aria-hidden=true or false
values dynamically for each item. This works.
But this introduces a new problem.
There are 6 items. So previously the screen reader at start will read out.
> List 6 items. You are currently in a list.
But since now I am hiding items, it ends up reading only 3 items existing:
> List 3 items. You are currently in a list.
Not sure if this is acceptable by accessibility standards.
Is there a way around this.
The question is: How can I stop screen reader from reading hidden content.
<br/>But at the same time the screen should still know there are 6 items so that it can call that out as usual.
<br/>Is this even possible. Or the reducing in list size in the read out is acceptable. Not found any references on it.
P.S: Using mac's inbuilt screen reader for testing.
The component. Stylings not added here to keep it simple.
import React, { useState } from 'react';
const Carousel = () => {
const [currentPos, setCurrentPos] = useState(0);
const handleLeftClick = () => {
if (currentPos === 0) return;
setCurrentPos(currentPos - 1);
};
const handleRightClick = () => {
setCurrentPos(currentPos + 1);
};
return (
<div className="carousel">
<ul className="carousel-inner" style={{ transform: `translateX(${-currentPos * 350}px)` }}>
{/* is dynamic can have more or less than 6 items*/}
<li className="carousel-item">1 long text ..</li>
<li className="carousel-item">2 long text ..</li>
<li className="carousel-item">3 long text ..</li>
<li className="carousel-item">4 long text ..</li>
<li className="carousel-item">5 long text ..</li>
<li className="carousel-item">6 long text ..</li>
</ul>
<div className="carousel-arrow left" onClick={handleLeftClick}>&lt;</div>
<div className="carousel-arrow right" onClick={handleRightClick}>&gt;</div>
</div>
);
};
export default Carousel;
Suggested solution for reference.
<br/>Using mac's default screen reader.
<br/>Won't work cos the screen reader reads out:
> List My Custom List 4 items
Was expecting just:
> My Custom List
<!DOCTYPE html>
<body>
<div>
<button>Click me!</button>
<br/>
<br/>
<ul aria-label="My Custom List">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
<br/>
<br/>
</div>
<br/>
</body>
</html>
答案1
得分: 1
如果只有3个可见项目,屏幕阅读器应该说有3个项目。
你不应该欺骗它说有6个,那是错误的,会导致混淆。
从屏幕阅读器的角度来看,基本上有两种可能的方式来查看你的走马灯组件。但都不是完美的。
分页列表
让只有6个项目中的3个可见并没有问题。简而言之,这就是一个分页列表。
如果你选择这种方式,需要考虑以下几点:
- 你应该明确指示项目1到3是6个项目中可见的,或者你在第1页中独立于屏幕阅读器自动宣布的可见项目数量。
- 移动到前一页/后一页的按钮必须对屏幕阅读器可访问。
- 不要在没有用户交互的情况下切换到另一页。
- 为了更好地理解,按下前一页/后一页按钮时,应该一次移动3个项目而不是1个。
对于第3点,我在考虑定时走马灯,其中内容会定期更改而无需用户干预。当你已经阅读了项目1到3,想要回去重新阅读它们时,发现它们已经被其他内容替代,对于屏幕阅读器用户来说会很烦人。或者更糟糕的是,在阅读仍在进行时,一些内容消失了。
对于第4点,作为一个屏幕阅读器用户,如果项目1到3可见,我通常期望在按下下一页按钮后看到项目4到6,而不是项目2到4。如果你这样做,如果显示哪些项目当前可见的指示不是很清楚,我可能会得出结论,下一页按钮不起作用,如果我再次遇到我已经阅读过的项目#2和#3。
只是一个技术上的想法:为什么不使用display:none
,而不是更复杂的CSS和aria-hidden
?这样开发起来简单得多,并且保证在任何地方都能正常工作。
总是看到所有内容
正如你可以从上面解释的分页列表观点中看到的,有几个重要的要考虑的点,以使其对屏幕阅读器可访问,并不总是容易做出权衡。
事实上,让你的组件对屏幕阅读器用户始终可见并不一定是件坏事。
- 你不需要担心定时走马灯,或者下一个按钮只会滚动一个项目而不是整个页面的事情。
- 作为一个屏幕阅读器用户,连续阅读许多项目要简单得多,而不是每隔几个项目就需要换页,特别是当每页的项目数量非常低时(比如3个)。
- 你的上一页/下一页按钮不需要对屏幕阅读器可访问,实际上,由于对屏幕阅读器用户完全没有用处,你可能应该从可访问树中隐藏它们。
对于第2点,拥有许多项目并不是问题,但前提是有办法轻松地跳过项目或整个列表。
如果你有一个良好的页面结构,使用标题、地标等,那就没什么特别需要做的,但如果你没有,那么拥有许多项目可能会成为一个问题。
对于第3点,我说“可能”,因为事实上它并不像放置aria-hidden
那么容易。
按钮必须对使用语音控制的用户和不使用屏幕阅读器的键盘用户等保持可操作,等等。
这又是一个权衡……最普遍访问的方式可能是将它们保留在可访问树中,但对屏幕阅读器用户明确表示它们对他们来说完全没有用处,例如通过添加一个标签如“滚动到左边”。
然而,对于不使用屏幕阅读器的仅键盘用户来说,有一个新的问题:
如果焦点移到当前隐藏项目中的链接会发生什么?
你必须注意这一点。
只是一个想法:为什么不使用本机滚动条,而不是实际上在这种情况下只做滚动的上一页/下一页按钮呢?
总结
这两者都不完美,但可能最好选择分页列表的观点。
- 所有用户都很了解分页列表的概念,因为它们无处不在
- 你不会为正常用户和屏幕阅读器用户创建完全不同的用户体验(即始终看到所有内容与一次只看到3个项目之间的区别),这也可能为其他用户群体创建问题。
英文:
If there are only 3 visible items, the screen reader should say that there are 3 items.
You shouldn't trick into making it say that there are 6, it would be incorrect and would lead to confusion.
From a screen reader perspective, there are basically two possible ways to view your carousel component. None is perfect.
Paginated list
There is no problem to make it so that only 3 items are visible among a list of 6. Simply put, that's a paginated list.
Some points to consider if you go that way:
- You should indicate somewhere explicitly that items 1 to 3 are visible out of a total of 6, or that you are on page 1 of 2, independently from the automatic number of visible items announced by the screen reader
- Buttons to move to previous / next page must be screen reader accessible
- Don't move to another page without user interaction
- For a better understanding, pressing the previous / next button should move 3 items at a time rather than just 1.
For point 3, I'm thinking about timed carousels where the content periodically change without user intervention. It's very annoying for a screen reader user when you have read items 1 to 3, want to go back to read them again, and notice that they have been replaced by something else.
Or worse, when some content disappears while reading is still in progress.
For point 4, as a screen reader user, if items 1 to 3 are visible, I normally expect to see items 4 to 6 after having pressed the next button, rather than items 2 to 4.
If you do so and if the indication of which items are currently visible isn't very clear, I might conclude that the next button doesn't work if I encounter again items #2 and #3 that I already have read.
Just a technical thought: why don't you use display:none, rather than more complicated CSS and aria-hidden ?
It's much simpler to develop, and is guaranteed to work absolutely everywhere.
Always see everything
As you can read on the paginated list point of view explained above, there are several important points to consider in order to make it accessible, and this isn't always easy to make tradeoffs.
In fact, making your component so that everything is always visible for screen readers isn't necessarily a bad thing.
- You don't need to care about timed carousels, or the fact that the next button will only scroll one item rather than an entire page
- As a screen reader user, it's much simpler to have many items read in a row, rather than having the need to change page every few items, especially when the number of items per page is very low (such as 3)
- Your previous / next buttons don't need to be screen reader accessible, and in fact, since they are completely useless to screen reader users, you should maybe hide them from accessibility tree
For point 2, having a lot of items isn't a problem at all, but under the important condition that there are ways to skip items or the entire list easily.
If you have a good page structure, are using headings, landmarks and such, there's nothing special more to do, but if you don't, then having a lot of items would be a problem.
For point 3, I say maybe, because in fact it isn't easy as putting aria-hidden.
The buttons must stay actionnable for users of voice control, as well as keyboard only users who don't use a screen reader, among others.
So this is another tradeoff....
The most universally accessible would probably be to keep them in the accessibility tree as normal, but making clear for screen reader users that they are totally useless for them, for example by putting a label like "scroll to the left".
There's, however, a new issue for keyboard-only users who don't use a screen reader:
what happens if the focus goes to a link present in a currently hidden item ?
You must take care of that.
Just a thought: instead of previous/next buttons that in fact just do scrolling in this case, why don't you use native scrollbars ?
Wrapping up
None of the two are perfect, but probably that you'd better to go for a paginated list point of view.
- All users well now the concept of paginated list, because they are everywhere
- You don't create a completely different user experience for normal users than screen reader users (i.e. see always everything vs. see only 3 items at a time), which may by the way also create problems for other groups of users
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论