卡片式组件常用于文章列表等场景。外观看似简单,但从无障碍角度考虑,其设计挑战却出人意料地复杂。
以典型卡片为例,从上到下依次为
- 图片
- 文章标题
- 文章摘要
- 详情链接
,让我们来探讨一下纵向排列布局下的实现模式。
设计时的主要考量要点
1. 视觉顺序与 HTML 结构
屏幕阅读器基本上会按照 HTML 的书写顺序进行朗读。在 WCAG 2.0 的成功准则 1.3.2(有意义的顺序,A 级)中,基本原则是使视觉顺序与 HTML 顺序保持一致。
但是,仅通过 CSS 改变顺序本身并不会违反 WCAG。即使视觉顺序与 HTML 顺序不同,只要内容能够被理解,就没有问题。根据具体情况灵活判断非常重要。
2. 图片的处理方式
文章卡片中的图片大多属于装饰性内容。只要有文章标题,内容就已充分传达,因此几乎没有朗读图片说明的必要。
作为装饰性图片处理时,仅使用 alt="" 即可。
<img src="thumbnail.jpg" alt="">
3. 详情链接的标签
“查看详情”之类的通用文本应当避免使用,原因如下。
视觉上的问题
如果没有周边上下文,就无法判断这是什么链接。
屏幕阅读器的问题
通过链接列表功能列出时,所有链接都显示为“查看详情”,无法区分。
语音识别的问题
当存在多个相同文本时,需要通过编号进行选择,操作变得繁琐。
理想情况下,应使用类似“查看○○的详情”这样,仅凭链接本身就能明确其目的的文本。但本文将讨论在需要原样还原“查看详情”设计时的实现方法。
4. 卡片的可点击区域
为了提升 UX,常常需要让整个卡片都可以点击。实现方法有多种,但各自对无障碍访问的影响不同。
5. 卡片应使用 article 还是 div
取决于内容的性质。
<article>适用于以下情况:
- 卡片内容能够作为独立内容成立
以下情况下可以使用<div>:
- 仅作为一组链接发挥作用
- 卡片本身不具有语义上的独立性
在普通的博客文章列表或商品列表卡片中,<article>是合适的。但是,如果使用多个<article>,建议考虑屏幕阅读器的地标导航,并通过aria-labelledby或aria-label来标识每篇文章(WCAG 2.4.6,AA 级)。
使用aria-labelledby时,请注意确保ID为唯一值。
关于视觉顺序与HTML结构
模式1:使视觉顺序与HTML顺序保持一致
<article class="article-card" aria-labelledby="article-title">
<img src="thumbnail.jpg" alt="">
<h3 id="article-title"><a href="#" class="card-link">記事タイトル</a></h3>
<p>記事の概要...</p>
<a href="#" class="card-detail-link">
<span class="visually-hidden">記事タイトル:</span>詳細を見る
</a>
</article>
由于HTML的书写顺序与视觉顺序完全一致,因此结构简单且直观。
注:<article>作为首个元素使用标题通常更为推荐,但这并非绝对要求。如果优先考虑与视觉顺序保持一致,则此模式没有问题。
补充:
语音识别软件(Dragon、Voice Control等)是基于屏幕上显示的文本进行操作的。使用 visually-hidden (sr-only) 可以保留视觉文本,从而支持通过语音识别进行操作。此外,以下是链接标签处理的合格与不合格实现示例。
<!-- 以下は可視テキストがアクセシブルな名前に含まれているのでOK -->
<a href="#" id="link-text" class="card-detail-link" aria-labelledby="link-text article-title">
詳細を見る
</a>
<a href="#" aria-label="詳細を見る:記事タイトル">
詳細を見る
</a>
<!-- 以下は可視テキストがアクセシブルな名前に含まれていないのでNG -->
<a href="#" class="card-detail-link" aria-labelledby="article-title">
詳細を見る
</a>
<a href="#" class="card-detail-link" aria-label="記事タイトル">
詳細を見る
</a>
模式2:使用 CSS order 调整视觉顺序
<article class="article-card" aria-labelledby="article-title">
<h3 id="article-title"><a href="#">記事タイトル</a></h3>
<p>記事の概要...</p>
<a href="#" class="card-detail-link">
<span class="visually-hidden">記事タイトル:</span>詳細を見る
</a>
<img src="thumbnail.jpg" alt="">
</article>
.article-card {
display: flex;
flex-direction: column;
}
.article-card img {
order: -1;
}
由于<article>第一个元素为标题,因此从语义结构上看更为理想。
对于装饰性图片(alt=""),由于图片会被跳过,因此不会影响朗读顺序。
注意:
- 如果图片具有含义并设置了 alt 属性,由于视觉顺序与朗读顺序会发生变化,因此不适合采用此结构。
- 键盘的 Tab 顺序遵循 HTML 的排列顺序,因此如果卡片内存在多个可获得焦点的元素,请确认焦点顺序不会破坏逻辑流程。
如果希望将卡片的可点击区域设置为整体
模式 3:通过伪元素使整张卡片可点击
该方法利用标题链接的伪元素覆盖整张卡片,“查看详情”则作为纯视觉装饰<span>处理。
即使将“查看详情”保持为<a>原样,并添加tabindex="-1"或aria-hidden="true",它仍会在屏幕阅读器的链接列表和元素导航模式中造成干扰,因此我认为<span>更为合适。
<article class="article-card" aria-labelledby="article-title">
<img src="thumbnail.jpg" alt="">
<h3 id="article-title"><a href="#" class="card-link">記事タイトル</a></h3>
<p>記事の概要...</p>
<span class="card-detail-link">詳細を見る</span>
</article>
.article-card {
position: relative;
}
.card-link::after {
content: '';
position: absolute;
inset: 0;
z-index: 1;
}
.card-link:focus-visible {
outline: none;
}
.card-link:focus-visible::after {
outline: 2px solid currentColor;
outline-offset: 2px;
}
/* カード内に複数のリンクがある場合の例 */
.article-card a:not(.card-link) {
position: relative;
z-index: 2;
}
优点:
- 能够保持语义化结构
- 屏幕阅读器可以自然地朗读内容
- 卡片内可以放置多个链接(如分类、标签、作者链接等)
缺点:
- 需要管理
z-index(但只要设置一次即可,不会有问题)
模式 4:用<a>包裹整张卡片
采用此方法时,由于整个卡片是一个链接,“查看详情”会自然地成为<span>链接文本。
<article class="article-card" aria-labelledby="article-title">
<a href="#" class="card-link">
<img src="thumbnail.jpg" alt="">
<h3 id="article-title">記事タイトル</h3>
<p>記事の概要...</p>
<span class="card-detail-link">詳細を見る</span>
</a>
</article>
优点:
- 实现简单
- 便于调整 CSS
缺点:
- 部分屏幕阅读器可能会将所有文本连在一起朗读(尤其是 VoiceOver,会读作“文章标题 文章摘要... 查看详情,链接”)
- 无法在卡片内放置多个链接
各模式示例
总结
实现无障碍的卡片式组件有多种方法。重要的是,并不存在“唯一正确”的实现模式,最佳方案会因情况而异。
在实现时,重点关注以下几点。
- 选择实际使用者不会感到困扰的实现方式
- 考虑图片的含义、卡片的用途以及网站的整体结构
- 优先采用实用且易于维护的实现方式
从 DTP 进入 Web 领域,不知不觉间,标记、前端、项目指导、无障碍样样精通的“技术仙人”。自 Liberogic 创业初期起就身兼多职,如今已是公司内的活字典般的存在。最近沉迷于用提示词提升效率的探索:“无障碍支持,能不能更多地依靠 AI 呢?”技术与思考仍在不断进化中。
二俣 歩
IAAP认证网页无障碍专家(WAS) / 标记工程师 / 前端工程师 / 网页总监