How to create website thumbnail cards with clickable links in HTML
Build accessible, responsive thumbnail cards with semantic HTML and CSS Grid. Learn how to make images clickable, choose useful alt text, and prevent layout shifts.
To make a website thumbnail card clickable, put its image and descriptive title inside an <a> element with a real href. Use CSS Grid for the responsive layout, set image dimensions to reserve space while thumbnails load, and choose object-fit based on whether cropping is acceptable.
1. Build a semantic card grid
This complete HTML and CSS example creates cards that navigate to real destinations. Each card has one link, a visible heading, supporting text, and an image with known intrinsic dimensions.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Garden guides</title>
<style>
* { box-sizing: border-box; }
body {
margin: 0;
padding: 2rem;
font-family: system-ui, sans-serif;
color: #17202a;
}
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
gap: 1rem;
max-width: 1100px;
margin-inline: auto;
}
.card {
overflow: hidden;
border: 1px solid #cbd2d9;
border-radius: 0.5rem;
background: #fff;
}
.card__link {
display: block;
color: inherit;
text-decoration: none;
}
.card__link:focus-visible {
outline: 3px solid #155eef;
outline-offset: 3px;
}
.card__link img {
display: block;
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
.card h2,
.card p {
margin: 0;
padding: 0.75rem;
}
.card__link:hover h2 { text-decoration: underline; }
</style>
</head>
<body>
<main>
<h1>Garden guides</h1>
<div class="cards">
<article class="card">
<a class="card__link" href="/guides/gardening">
<img
src="/images/gardening-thumb.jpg"
alt="A raised garden bed with leafy vegetables"
width="640"
height="360"
>
<h2>How to start a garden</h2>
</a>
<p>A beginner guide to planning and planting a garden.</p>
</article>
<article class="card">
<a class="card__link" href="/guides/composting">
<img
src="/images/compost-thumb.jpg"
alt=""
width="640"
height="360"
>
<h2>How to make compost</h2>
</a>
<p>Learn the basics of building and maintaining a compost pile.</p>
</article>
</div>
</main>
</body>
</html>
The first thumbnail describes information that adds to its link, so it has descriptive alternative text. The second is decorative because its visible heading already names the destination, so it uses alt="". Choose based on the actual image and surrounding text.
2. Make the image and destination accessible
An anchor’s href provides the destination. Nest the image and title in the same anchor when they lead to the same page; the title gives the link a useful name even when the image is not visible. A link labeled “Read more” gives less context than one whose content identifies the destination. See MDN’s references for the anchor element and image element.
- Use a real URL in
href, such as/guides/gardening. A placeholder like#does not take the visitor to the intended destination. - For a linked image, write alt text that works as link text: describe the destination or the meaningful information the image contributes.
- If the visible title already names the destination and the image adds no distinct information, use an empty alt value:
alt="". This avoids repeating the title for assistive technology. - Use an
<article>for a self-contained card when that matches your content. Semantic elements describe the content; CSS controls appearance. - Keep the visible keyboard focus clear. The
:focus-visiblerule in the example outlines a link when it receives keyboard focus.
3. Choose thumbnail sizing and cropping
The width and height attributes tell the browser the image’s intrinsic dimensions so it can reserve space before loading. The CSS aspect-ratio gives thumbnails a consistent display box. This helps avoid layout shifts as images load.
| Setting | What it does | Use it when |
|---|---|---|
object-fit: cover |
Fills the thumbnail box and crops overflow. | A uniform grid matters and the subject remains visible after cropping. |
object-fit: contain |
Shows the full image inside the box, potentially leaving empty space. | The whole image, such as a diagram, must remain visible. |
object-position: center |
Sets which part of the image stays visible when cropped. | The default centered crop cuts off an important subject. |
For example, to keep a subject near the top in a cropped thumbnail, add object-position: center top; to the image rule. Adjust the position for the actual image; cover can crop different amounts at different card widths.
4. Adapt the grid for different layouts
The example uses repeat(auto-fill, minmax(230px, 1fr)): the browser fits as many columns of at least 230 pixels as the container allows, then distributes remaining space. Change the minimum width and gap to match your design. If you need a fixed number of columns at known breakpoints, use media queries instead:
.cards {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
}
@media (min-width: 600px) {
.cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 900px) {
.cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
For a reusable recipe and more layout context, see MDN’s card layout recipe.
5. Decide whether the whole card or separate actions link
If a card has one destination, a single anchor around its image and title makes that content one clear link target. The supporting description can remain outside the anchor. If the card has multiple actions, such as an article link and a separate author link, create separate anchors with their own meaningful content. Never nest an anchor inside another anchor.
Do not use a clickable <div> as a substitute for a link. An anchor provides navigation behavior and keyboard activation. If you add buttons for actions that do not navigate, keep them distinct from the destination link.
6. Source and prepare thumbnail images
- Use an HTML
<img>for meaningful imagery so it can have a text alternative. A CSS background image is better suited to decoration. - Use images you have permission to publish. Avoid hotlinking another site’s image: it can disappear or change without your control.
- Provide the correct intrinsic
widthandheightfor each source image, and check the crop at the narrowest card size. - Use descriptive filenames and maintain an image format and size appropriate for your site’s delivery setup. The correct optimization depends on the image pipeline and hosting environment.
If you need a preview image of a live page for a card, you can capture one with ScreenshotNeo, a website screenshot API and MCP server for developers. The response can be a PNG, JPEG, WebP, or PDF; for a card thumbnail, request an image format and use the resulting image URL or file in your site.
7. Or skip the browser setup
Instead of setting up a browser and capture script, make one API request. See the ScreenshotNeo API documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://stripe.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.
Sign up for 1,000 free screenshots a month with no card.
8. Troubleshooting
| Problem | Likely cause | Fix |
|---|---|---|
| The image is not clickable. | The image is not inside the anchor, or the anchor has no destination. | Put the image and title within <a href="..."> and check that the URL is valid. |
| The card link says only “Read more.” | The link content does not identify its destination. | Include the article title in the anchor or use another descriptive link name. |
| The screen reader announces the title twice. | The image alt repeats the adjacent linked title. | When the image adds no distinct information, use alt="". |
| Thumbnails have different heights or cause content to jump. | There is no consistent display ratio, or dimensions are not provided. | Set image width and height, then use a consistent CSS aspect-ratio. |
| The subject is cut off. | object-fit: cover crops the source to fill the box. |
Adjust object-position, or use contain if the full image must show. |
| Keyboard users cannot tell which card is active. | The focus indicator is missing or too subtle. | Add a visible :focus-visible outline and ensure surrounding styles do not clip it. |
| A remote thumbnail stops appearing. | The remote owner removed or changed the image, or does not permit hotlinking. | Publish an image you have permission to use from infrastructure you control. |
9. Performance, reliability, and cost considerations
A static card grid needs no JavaScript to make links work. CSS Grid and intrinsic image dimensions let the browser lay out cards without waiting for script or image downloads to discover the basic geometry. Keep source images available and use dimensions that match the source ratio; cropping with CSS does not reduce the downloaded file size.
For reliability, use stable image URLs you control and verify that every card destination and image path resolves. If thumbnails are generated from live pages, capture them as part of your content workflow and store or serve the resulting files through your chosen image hosting setup. ScreenshotNeo’s stated pricing is Free for 1,000 shots per month with no card, Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; yearly billing gives two months free. Every feature is on every plan. Only clean shots are billed; bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, with response headers indicating the page verdict and billing status.
FAQ
Can I put a heading inside an anchor?
Yes. In this single-destination card pattern, the heading is part of the linked content and identifies the destination.
Should every thumbnail have alt text?
Every image needs an appropriate alternative text value. Use descriptive text when the image contributes meaning; use an empty value for an image that is decorative or redundant beside the visible link title.
Does CSS Grid make cards clickable?
No. Grid arranges the cards. The anchor and its href provide navigation.
When should I choose contain over cover?
Choose contain when cropping would hide information that must remain visible. Choose cover when a filled, uniform thumbnail box is more useful and the crop preserves the subject.


