RizTech Academy logo
RizTech Academy
HTML FoundationsLesson 5 of 925 min

Links, images and alt text

Two elements, and between them most of the mistakes on the average small business site. Links that say "click here" and images with no alt are the two things an accessibility audit finds first, every time.

<a href="prices.html">Our prices</a>

href is the destination. Everything else is detail.

Relative and absolute paths

This is the part that causes broken links, so it is worth being precise. Say your folder looks like this:

site/
  index.html
  about.html
  images/
    shop.jpg
  prices/
    index.html

From index.html:

<a href="about.html">About</a>          <!-- same folder -->
<a href="prices/">Prices</a>            <!-- folder; serves prices/index.html -->
<img src="images/shop.jpg" alt="…">     <!-- down into a folder -->

From prices/index.html:

<a href="../about.html">About</a>       <!-- ../ means up one folder -->
<img src="../images/shop.jpg" alt="…">

And the two that behave differently:

<a href="/about.html">About</a>         <!-- root-relative: from the site root -->
<a href="https://example.com">Example</a>  <!-- absolute: another site -->

A leading / means "from the root of the site", not "from this folder". This is the one that trips people up, because on file:// a leading slash means the root of your entire hard disk, so root-relative links appear broken locally and work once deployed. If your links break the moment you open a page from a subfolder, you have used relative paths where you wanted root-relative ones.

Prefer root-relative (/about.html) for a site you will deploy. Then the same link works from any depth, and moving a page does not break its links.

Screen reader users can pull up a list of all links on a page, out of context. So:

<!-- useless in a list: "click here, click here, read more, read more" -->
<p>For our prices, <a href="/prices/">click here</a>.</p>
<a href="/atta.html">Read more</a>

<!-- makes sense alone -->
<p>See <a href="/prices/">our current prices</a>.</p>
<a href="/atta.html">More about our atta</a>

The test: does the link text make sense read on its own? "Click here" fails. "Read more" fails. "Download" fails — download what?

Also: never put the URL itself as the text for a long URL. A screen reader reads it character by character, which takes twenty seconds.

<a href="/menu.pdf" download>Download our price list (PDF, 240 KB)</a>

<a href="https://gst.gov.in" target="_blank" rel="noopener noreferrer">
  GST portal (opens in a new tab)
</a>

<a href="tel:+919876543210">Call us</a>
<a href="mailto:hello@sharmakirana.com">Email us</a>
<a href="https://wa.me/919876543210">WhatsApp us</a>

Say the file type and size for a download. Somebody on a metered connection deserves to know before they tap.

target="_blank" needs rel="noopener", which stops the new page getting a handle on yours. Modern browsers imply it, but older ones do not and the attribute costs nothing. And tell the person it opens a new tab — an unannounced new tab is disorienting, and the Back button appears broken.

tel: and wa.me links are worth real money on an Indian small business site, because most visitors are on a phone and one tap is the difference between a call and a bounce.

<h2 id="delivery">Delivery</h2>
…
<a href="#delivery">Jump to delivery</a>

An id must be unique on the page. href="#top" with no matching id goes to the top of the page; href="#" also does, and is usually a placeholder somebody forgot.

Images

<img src="images/shop.jpg" alt="The shopfront of Sharma Kirana on Karve Road">

src and alt are both required. alt being required is not a style guide — the HTML specification says so.

What alt is actually for

Not "a description of the image". A replacement for the image: what you would write if the picture could not be shown.

It is used by a screen reader, shown when the image fails to load, read by search engines, and used by anybody browsing with images off to save data — which on a metered Indian mobile plan is a real choice people make.

<img src="atta.jpg" alt="">                                  <!-- decorative: correct -->
<img src="atta.jpg" alt="atta">                              <!-- too vague -->
<img src="atta.jpg" alt="image of atta">                     <!-- "image of" is noise -->
<img src="atta.jpg" alt="atta.jpg">                          <!-- worse than nothing -->
<img src="atta.jpg" alt="A 10kg bag of Sharma Kirana atta">  <!-- good -->

Three rules that cover nearly everything:

Never start with "image of" or "picture of". A screen reader already announces "image". You are making it say "image, image of atta".

alt="" — empty, but present — is correct for a decorative image. A background flourish, a divider, an icon next to text that already says the same thing. Empty alt tells a screen reader to skip it. Leaving alt off entirely is different and worse: with no alt at all, many screen readers read out the filename, so your user hears "i-m-g underscore 2 0 2 6 0 9 dot j-p-g".

If the image is inside a link, the alt describes the destination, not the picture, because that image is the link:

<a href="/"><img src="logo.svg" alt="Sharma Kirana home"></a>

And if an image carries information — a price list as a picture, a chart — the alt must carry that information, or the information is not on your page. A photo of a price board with alt="price board" has hidden your prices from a portion of your customers. Better: put the prices in a table and use the photo as decoration.

Always set width and height

<img src="shop.jpg" alt="…" width="1200" height="800">

Not to size it — CSS does that. These are the intrinsic dimensions, and giving them lets the browser reserve the right space before the image arrives.

Without them, the page renders, then the image loads, then everything below it jumps down. That jump is called layout shift, it is measured by Lighthouse as CLS, and it is why you sometimes tap a link and hit the wrong thing because the page moved under your thumb. Two attributes fix it.

Then in CSS, always:

img {
  max-width: 100%;
  height: auto;
}

Otherwise a 2000-pixel-wide image overflows a 360-pixel phone screen and gives you a horizontal scrollbar on every page.

Which format

Format Use for
SVG Logos, icons, anything drawn. Infinitely sharp, usually tiny
WebP Photographs. Roughly 30% smaller than JPEG at the same quality
JPEG Photographs, when you need maximum compatibility
PNG Screenshots, or anything needing real transparency
AVIF Photographs, smallest of all, now safe in current browsers

Never a PNG of a photograph — it can be five times the size of the JPEG for no visible benefit. And never a 4000-pixel-wide phone photo dropped straight into a page: resize it to roughly twice its display width and no more.

Lazy loading

<img src="shop.jpg" alt="…" width="1200" height="800" loading="lazy">

loading="lazy" tells the browser not to fetch the image until it is near the viewport. Use it for everything below the fold; do not use it for the image at the top of the page, because you are delaying the one image the visitor is waiting for.

Figures and captions

<figure>
  <img src="shop.jpg" alt="The shopfront on Karve Road" width="1200" height="800">
  <figcaption>Our shop in Kothrud, open since 1998.</figcaption>
</figure>

<figcaption> is a caption everybody sees. alt is a replacement for people who cannot see the image. They are different jobs — do not write the same words twice, and do not skip the alt because there is a caption.

Check your work

What a leading / means. From the site root, not the current folder — and on file:// it means your hard disk's root.

Why prefer root-relative links. The same link works from any folder depth.

The link text test. Does it make sense read on its own, in a list? "Click here" and "Read more" fail.

Why rel="noopener" with target="_blank". It stops the new page getting a handle on yours — and announce the new tab.

What alt really is. A replacement for the image, not a description of it.

Why not "image of". The screen reader already says "image".

alt="" versus no alt. Empty means skip this decoration; missing means many screen readers read the filename aloud.

Alt for an image inside a link. Describe the destination.

What width and height prevent. Layout shift — the page jumping as images arrive.

What max-width: 100% prevents. A wide image forcing horizontal scroll on a phone.

When not to use loading="lazy". On the image at the top of the page.

alt versus <figcaption>. A replacement versus a caption for everybody.

Practice

  1. Build the folder structure from this lesson and make every link work from both index.html and prices/index.html.
  2. Change one link to root-relative and open the page from file://. Explain what happens.
  3. List the links on any real site using a screen reader's links list, or read the link texts aloud in isolation. Count how many are meaningless.
  4. Rewrite three "click here" links properly.
  5. Add a tel: and a wa.me link and tap both on a real phone.
  6. Add a PDF download link stating the type and size.
  7. Put an image on a page with no alt and listen to it with a screen reader. Then alt="". Then a real alt. Note all three.
  8. Break an image's src deliberately and look at the page. That broken-image text is your alt doing its job.
  9. Load a page with a large image and no width/height on a throttled connection. Watch the jump. Add them and watch it stop.
  10. Photograph something, drop the full-size file into a page, and check its size in the Network tab. Resize it to 1200px wide and compare.
  11. Save the same photo as PNG, JPEG and WebP. Compare the three file sizes.
  12. Add loading="lazy" to images below the fold and confirm in the Network tab that they are not fetched until you scroll.

Official documentation

Next: lists and tables, and the one thing tables must never be used for.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship