I have a situation where I need physically separate a caption from the associated figure, e.g. this sort of markup:
<figure>
<img src="…" alt="…"/>
</figure>
…later in the code…
<figcaption>
Caption text
<figcaption>
This isn't semantically correct (there are existing SO questions addressing it), and it produces a validation error. Given that, I'm wondering what the appropriate way to represent this would be (considering markup and accessibility).
Ideally, there would be some sort of attribute (like the label
elements for
attribute) that would let you associate a figcaption
with a figure
. Currently I am using an aria-describedby
attribute (see below), but I'm not sure if this is accurate either.
<figure aria-describedby="caption">
<img src="…" alt="…"/>
</figure>
…later in the code…
<div id="caption">
Caption text
<div>
There are a couple of ways you could approach this, either by adding a role and using aria-labelledby
, or with JavaScript.
Method 1 - HTML Only
The aria-labelledby
attribute is only recognized on form controls (e.g. buttons, inputs, checkboxes, etc.) or on elements that have a role
attribute assigned. Without either of these conditions, the accessible name computation will not be calculated on the element.
<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>
In my testing on NVDA/Chrome this works as long as the alt
attribute on the image is not empty. I would strongly recommend testing this using different browsers and screen-readers before deploying to a production environment for the reason that it's essentially a label
on a non-interactive element.
Method 2 - JavaScript and CSS
This method is more inline with your original question. It produces a non-visual figcaption
element as a child of the figure
element.
<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>