# Empty image links and vague “Read more” links

Source: https://easeweb.dev/learn/link-text
Topics: Buttons and links > Link text makes sense (WCAG 2.4.4)
The fix: Give every link a name that says where it goes. Either add the missing words to the links you have, as visually hidden text or with aria-labelledby, or make each heading the link and stretch its click area with a pseudo-element. Both pass; the first changes less, the second reads more cleanly.
Test with: keyboard, screen reader, mouse
References: https://www.w3.org/WAI/WCAG22/Understanding/link-purpose-in-context.html https://www.w3.org/WAI/WCAG22/Techniques/failures/F89 https://www.w3.org/WAI/WCAG22/Techniques/html/H30 https://www.w3.org/WAI/WCAG22/Understanding/label-in-name.html https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a#accessibility

This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.

## What happens

A tea shop's home page opens with a banner: a photo of autumn leaves, the headline "Autumn blends are here" and a line about the new teas. The whole banner is clickable. Pressing Tab puts focus on it, and a screen reader announces "link", or reads out the address, "collections/autumn". Below it are three journal cards, each with a heading, a sentence and a link that says "Read more". Someone who opens the screen reader's list of links hears an unnamed link and then "Read more, Read more, Read more".

## Why it fails

To make the whole banner clickable, the theme lays an empty `<a>` over it with absolute positioning. The headline and text sit in a sibling element, outside the link, so the link has no text and therefore no accessible name. The cards have the opposite problem: their links do have text, but the same two words for three different posts.

## Who is affected

Screen reader users often move through a page by its links, or open a list of every link on it. An unnamed link gives them nothing to go on, and three identical "Read more" entries make them follow each one to find out where it leads. Voice control users say a link's text to activate it; they can't say the name of a link that has none, and "click Read more" matches three links at once. People who find reading hard also benefit when a link says plainly where it goes.

## What automation and AI miss

An automated check such as axe's `link-name` reliably flags the empty banner link. It does not judge whether a name is useful, so it passes three "Read more" links, a link named "IMG_2041.jpg", or an icon whose alt is "logo". A quick AI fix often adds `aria-label="Link"`, which silences the scanner and helps nobody. It may also add an `aria-label` that drops the visible words, so voice control can no longer find the link. A name only helps when a person reads it in a list and still knows where it goes.

## Before: an empty link over the banner

```html
<div class="banner">
  <img src="/images/autumn.jpg" alt="">
  <a href="/collections/autumn" class="banner-link"></a>
  <div class="banner-text">
    <h2>Autumn blends are here</h2>
    <p>Roasted hojicha, chai and chestnut.</p>
  </div>
</div>

<article class="card">
  <h3>How to brew hojicha</h3>
  <p>Lower heat and a shorter steep bring out the roast.</p>
  <a href="/journal/brew-hojicha">Read more</a>
</article>
```

The banner link contains nothing, so assistive technology has no words to announce. The card's "Read more" only makes sense when the heading above it is read too. In a list of links, that heading is not read.

## After: add the missing words to the links you have

```html
<div class="banner">
  <img src="/images/autumn.jpg" alt="">
  <a href="/collections/autumn" class="banner-link">
    <span class="visually-hidden">Autumn blends are here</span>
  </a>
  <div class="banner-text">
    <h2>Autumn blends are here</h2>
    <p>Roasted hojicha, chai and chestnut.</p>
  </div>
</div>

<article class="card">
  <h3>How to brew hojicha</h3>
  <p>Lower heat and a shorter steep bring out the roast.</p>
  <a href="/journal/brew-hojicha">
    Read more<span class="visually-hidden"> about how to brew hojicha</span>
  </a>
</article>
```

```css
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
```

Adding the words leaves the layout as it is. The banner link is now announced as "Autumn blends are here, link", and each card link as "Read more about how to brew hojicha, link". The card names start with the visible words, so voice control can still find them. Instead of hidden text, the banner link can take its name from the headline with `aria-labelledby`, pointing at an `id` on the `h2`, so the two can't drift apart. Either way, someone reading the banner from top to bottom hears the headline twice: once as the link and once as the heading.

## After: make the heading the link

```html
<div class="banner">
  <img src="/images/autumn.jpg" alt="">
  <div class="banner-text">
    <h2><a href="/collections/autumn" class="banner-link">Autumn blends are here</a></h2>
    <p>Roasted hojicha, chai and chestnut.</p>
  </div>
</div>

<article class="card">
  <h3><a href="/journal/brew-hojicha" class="card-link">How to brew hojicha</a></h3>
  <p>Lower heat and a shorter steep bring out the roast.</p>
</article>
```

```css
.banner, .card { position: relative; }
/* The link's click area covers the whole banner or card. */
.banner-link::after, .card-link::after {
  content: "";
  position: absolute;
  inset: 0;
}
.banner-link:focus-visible { outline: none; }
.banner-link:focus-visible::after {
  outline: 3px solid var(--focus-ring);
  outline-offset: -3px;
}
```

Here the headline is the link's name, and the pseudo-element still makes the whole banner and card clickable. Each banner and card has one link, and nothing is read twice: screen readers announce "Autumn blends are here, link" and "How to brew hojicha, link". The "Read more" text goes.

## Which option to use

Both options give every link a name and meet 2.4.4. Adding the words is the smaller change: no layout or CSS changes, so it suits a theme or third-party slideshow you can't restructure, or a design that must keep "Read more". Making the heading the link is cleaner: one link per banner or card, read once, named by the heading people already see. Choose it when you can change the template. You can mix them, for example heading links on cards you own and a named overlay link on a slideshow you don't.

## Implementation decisions

**The stretched link covers other controls.** Any other button or link inside the card, such as a "Save" button or a tag link, needs `position: relative` and a `z-index` above the pseudo-element, or it can't be clicked. The overlay also stops people selecting the card's text. If the card has several controls, consider making only the heading and image clickable.

**Wrapping the whole card in one `<a>`.** This is valid HTML and makes the card clickable, but the link's name becomes everything inside the card, so the screen reader reads a long paragraph. The card also can't contain another link or button. A link on the heading avoids both problems.

**Hidden text versus `aria-label`.** Use a clip-based `.visually-hidden` class, not `display: none`, which removes the text from the accessible name too. Prefer hidden text to `aria-label`: `aria-label` replaces the link's content, some browser translation tools skip it, and it can drift from the visible text. If you do use it, start it with the visible words.

**Image and icon links.** When the image is the only content of a link, its `alt` names the destination ("Leaf & Kettle home", "Instagram"), not the picture. When the image sits next to text in the same link, give it `alt=""` so the name is not read twice. For an SVG icon, hide the SVG with `aria-hidden="true"` and put visually hidden text in the link.

**Editable content.** In a theme or CMS, the banner's headline is often an optional field. If it is left empty, the stretched link has no name again. Require a link label when a link is set, or don't render the link when the label is empty. Several banners that each say "Shop now" have the same problem as "Read more".

**Strictly, context can be enough.** WCAG 2.4.4 accepts link text read together with its programmatically determined context, such as the sentence, list item or table cell it sits in. A "Read more" inside a well-structured card may therefore conform, but the list of links is still unclear, and level AAA 2.4.9 asks for links that make sense on their own. An empty link fails in every case.

## Verify the fix

1. Tab through every link on the page and check, in the browser's accessibility tree, that each one has a name.
2. Open the screen reader's list of links (the rotor in VoiceOver, Insert+F7 in NVDA and JAWS). Each entry must say where it goes and be distinct from the others.
3. Check every image-only and icon-only link: the name describes the destination, not the picture or a file name.
4. Click across the banner and each card, including at 200% zoom and on a touch screen, and check that other controls inside the card can still be pressed.
5. With voice control, say the visible text of a link and confirm that it activates that link.

Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the shared card, banner or slideshow component changes.

## Limits

This is a starting pattern, not a guarantee for every application. Paths and class names in the snippets are placeholders. Content editors can still write a vague link later, so keep link text in your publishing review. Test the complete journey with your target assistive technology.
