如何在图形元素之外指定标题

How to specify a caption outside of figure element

我有一种情况需要将标题与相关图形物理分开,例如这种标记:

<figure>
  <img src="…" alt="…"/>
</figure>

…later in the code…

<figcaption>
  Caption text
<figcaption>

这在语义上不正确 (),并且会产生验证错误。鉴于此,我想知道表示这一点的适当方式是什么(考虑标记和可访问性)。

理想情况下,会有某种属性(例如 label 元素 for 属性)可以让您将 figcaptionfigure 相关联。目前我正在使用 aria-describedby 属性(见下文),但我也不确定这是否准确。

<figure aria-describedby="caption">
  <img src="…" alt="…"/>
</figure>

…later in the code…

<div id="caption">
  Caption text
<div>

有几种方法可以解决这个问题,可以通过添加角色并使用 aria-labelledby,也可以使用 JavaScript。

方法 1 - HTML 仅

aria-labelledby 属性只能在表单控件(例如按钮、输入框、复选框等)或分配了 role 属性的元素上识别。如果没有这些条件中的任何一个,将不会在元素上计算 accessible name computation

<figure role="region" aria-labelledby="caption-text">
    <img src="/images/logo.png" alt="your image alt text" />
</figure>

<p>…later in the code…</p>

<div id="caption-text">Caption text</div>

在我对 NVDA/Chrome 的测试中,只要图像上的 alt 属性不为空,它就可以工作。我强烈建议在部署到生产环境之前使用不同的浏览器和屏幕阅读器对此进行测试,因为它本质上是非交互式元素上的 label

方法 2 - JavaScript 和 CSS

这个方法更符合你原来的问题。它生成一个不可见的 figcaption 元素作为 figure 元素的子元素。

<style>
    .sr-only {
        clip: rect(1px, 1px, 1px, 1px);
        clip-path: inset(50%);
        height: 1px;
        width: 1px;
        margin: -1px;
        overflow: hidden;
        padding: 0;
        position: absolute;
    }
</style>

<figure id="fig">
    <img src="/images/logo.png" alt="your image alt text" />
</figure>

<p>…later in the code…</p>

<div id="caption-text" aria-hidden="true">Caption text</div>

<script>
    document.addEventListener("DOMContentLoaded", () => {
        
        // create a figcaption element
        const caption = document.createElement("figcaption")
        
        // get innerText from div#caption-text and add to new figcaption element
        caption.innerText = document.getElementById("caption-text").innerText
        
        // assign a class to visually hide
        caption.className = "sr-only"

        // append figcaption to the figure element
        document.getElementById("fig").appendChild(caption)
    });
</script>