How to Add Images in HTML Code
Learn the correct img syntax, alt text, responsive sources, lazy loading, troubleshooting, and a ScreenshotNeo shortcut for rendered pages.
Use an <img> element: <img src='images/photo.jpg' alt='A description of the photo'>. The src points to an image URL or file path, and alt describes the image for people who cannot see it or when the file fails to load. <img> is a void element, so it has no closing tag.
This guide shows the complete markup for reliable, accessible, responsive images, then explains loading, formats, layout stability, and common failures.
1. Add one image
Create an HTML file and place the image element in the document body:
<!doctype html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<title>Image example</title>
</head>
<body>
<img src='images/photo.jpg' alt='A grapefruit slice on a plate' width='800' height='600'>
</body>
</html>
src can be a relative path such as images/photo.jpg, a root-relative path such as /images/photo.jpg, or an absolute HTTPS URL. The browser resolves a relative path from the page URL, so spelling, capitalization, and directory location must match exactly.
Use numeric width and height values for the image’s intrinsic dimensions. They let the browser reserve the correct aspect ratio before the file arrives, reducing layout shifts. CSS controls the displayed size.
2. Write useful alt text
Describe the information the image adds, not every visible detail. A product photo might use alt='Black backpack with two front pockets'. If an image is purely decorative and nearby text already conveys its meaning, use an empty value: alt=''. Always include the attribute; omitting it makes the image harder to interpret with assistive technology.
The alt value is replacement text: it can be read aloud or shown when the resource cannot load. Do not put filenames, “image of,” or keyword lists in it unless those words are genuinely useful.
3. Make images responsive
Prevent an image from overflowing a narrow screen with CSS:
img {
display: block;
max-width: 100%;
height: auto;
}
max-width: 100% lets the image shrink to its container while height: auto preserves its aspect ratio. Keep the HTML dimensions even when CSS scales the image.
4. Serve different resolutions with srcset and sizes
When the same image is available at several widths, provide candidates. Width descriptors (w) must be paired with sizes; do not mix width and density descriptors in one srcset.
<img
src='photo-800.jpg'
srcset='photo-480.jpg 480w, photo-800.jpg 800w, photo-1600.jpg 1600w'
sizes='(max-width: 600px) 100vw, 800px'
alt='A person standing beside a lake'
width='1600'
height='1067'>
sizes tells the browser how wide the image will render in each layout condition. The browser then considers the slot width and display density when choosing a candidate. Keep src as a fallback for browsers that do not use srcset.
Density descriptors
If you have variants for a fixed CSS size, use density descriptors instead:
<img
src='logo.png'
srcset='logo.png 1x, logo@2x.png 2x'
alt='Acme logo'
width='200'
height='80'>
Choose either density descriptors or width descriptors for a given srcset, never both.
5. Use picture for art direction and formats
Use <picture> when a narrow screen needs a different crop, or when you want to offer a modern format with a fallback. The nested <img> is required and acts as the default:
<picture>
<source srcset='portrait-crop.webp' media='(max-width: 600px)' type='image/webp'>
<source srcset='wide-image.webp' type='image/webp'>
<img src='wide-image.jpg' alt='A person standing beside a lake' width='1200' height='800'>
</picture>
The browser tests <source> elements in order and uses the first compatible match. Keep the fallback image valid because older browsers or unsupported formats use it.
6. Control loading
Images load eagerly by default. For content well below the initial viewport, loading='lazy' defers fetching until the image is near view:
<img src='gallery/photo.jpg' alt='A red bicycle leaning on a brick wall'
width='1200' height='800' loading='lazy'>
Retain explicit dimensions on lazy images. Without them, an unloaded image can occupy zero space and cause reflow when it appears. Do not lazy-load a hero or other image needed immediately when the page opens.
7. Complete gallery example
<style>
.gallery { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 1rem; }
.gallery img { display: block; width: 100%; height: auto; }
</style>
<div class='gallery'>
<img src='lake-480.jpg'
srcset='lake-480.jpg 480w, lake-960.jpg 960w'
sizes='(max-width: 700px) 100vw, 50vw'
alt='Mountain reflected in a lake' width='960' height='640'>
<img src='bike.jpg' alt='Red bicycle beside a brick wall'
width='1200' height='800' loading='lazy'>
</div>
8. Paths, URLs, and deployment checks
- Confirm the file is inside the directory served by your web server.
- Use forward slashes in URLs, including on Windows hosts.
- Match filename case; many production servers are case-sensitive.
- Encode spaces and special characters in URLs, or rename files to simple names.
- Use HTTPS for remote images on an HTTPS page to avoid mixed-content blocking.
- Check the browser Network panel for the exact requested URL and HTTP status.
9. Accessibility checklist
- Every image has an intentional
altvalue. - Informative images describe their purpose or data.
- Decorative images use
alt=''and are not repeated in nearby text. - Text inside an image is avoided when equivalent HTML text is possible.
- Intrinsic dimensions are present to preserve layout.
10. Performance and reliability
Offer appropriately sized files instead of making every visitor download the largest source. Use srcset/sizes for variable slots, modern formats through <picture> when useful, and lazy loading for below-the-fold content. Keep critical images eager and include dimensions for every image, including lazy ones.
When an image is remote, its server, cache headers, redirects, authentication, and availability affect your page. A local or reliably hosted asset avoids a third-party outage. If you change a file while a CDN caches it, use a new filename or cache-busting URL.
11. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Broken-image icon | Wrong path, filename, case, or server status | Copy the requested URL from DevTools, open it directly, and correct the path or deployment. |
| Image works locally but not online | Asset was not copied, or the production path differs | Inspect the deployed directory and use a path relative to the deployed page. |
| Image is stretched | Both CSS width and height are forced independently | Set height: auto, or preserve the source aspect ratio. |
| Page jumps while loading | No intrinsic dimensions | Add accurate width and height attributes. |
| Wrong responsive candidate | sizes does not describe the rendered slot |
Update media conditions and slot widths; keep descriptors in w. |
| WebP is not displayed | No compatible fallback | Put a normal JPEG/PNG <img> inside <picture>. |
| Remote image blocked | Mixed content, hotlink protection, authentication, or CORS policy | Use HTTPS, permit the requesting origin, authenticate correctly, or host the asset yourself. |
| Lazy image appears late | It is far from the viewport or network is slow | Keep critical images eager and reserve lazy loading for noncritical content. |
12. Or skip the browser setup
If you need an image of a rendered webpage rather than an image asset inside your own HTML, ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one GET request. Its cleanup steps accept cookie banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing result.
See the ScreenshotNeo API docs for all options.
cURL
curl -G 'https://api.screenshotneo.com/v1/shot' -d access_key=YOUR_API_KEY --data-urlencode 'url=https://stripe.com' -o shot.webp
Python
import requests
r = requests.get('https://api.screenshotneo.com/v1/shot', params={'access_key': 'YOUR_API_KEY', 'url': 'https://stripe.com'}, timeout=90)
r.raise_for_status()
open('shot.webp', 'wb').write(r.content)
Node.js
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(`HTTP ${res.status}`);
require('node:fs').writeFileSync('shot.webp', Buffer.from(await res.arrayBuffer()));
ScreenshotNeo also supports full-page capture with lazy images loaded, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, custom CSS and JavaScript, clicks, waits, blocking rules, headers/cookies/user agents, timezone and geolocation, transparent backgrounds, resizing, chosen-TTL caching, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. An MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
The Free plan includes 1,000 shots per month with no card. Starter is $5 for 3,000 shots; yearly billing gives two months free, and every feature is available on every plan. Create a free ScreenshotNeo account.
13. FAQ
Can I omit width and height?
The image can still render, but dimensions let the browser reserve its aspect ratio and reduce layout shifts, so include them when known.
Should every image be lazy-loaded?
No. Lazy-load images below the initial viewport; keep immediately visible, critical images eager.
When do I need picture instead of srcset?
Use srcset for alternate resolutions of the same image. Use <picture> for art direction or format-specific sources with a fallback.
Does alt text affect the image request?
No. It supplies replacement text and accessibility information; src and responsive attributes determine what is fetched.


