|$ curl https://forge-ai.dev/api/markdown?path=docs/html/images
$cat docs/html-images-&-figures.md
updated This week·35 min read·published

HTML Images & Figures

HTMLImagesIntermediateIntermediate
Introduction

Images are a fundamental part of the web. HTML provides the <img> element for embedding images, along with a rich set of attributes for responsive behavior, performance optimization, and accessibility. Modern image formats like WebP and AVIF offer superior compression compared to legacy JPEG and PNG.

Images account for roughly 50% of the average page weight. Optimizing image delivery — through format selection, responsive resolution switching, lazy loading, and CDN delivery — is often the single highest-impact performance improvement for any website.

The img Element

The <img> element is a void element that embeds an image into the document. The src attribute points to the image URL, and alt provides alternative text for accessibility. The width and height attributes define the intrinsic dimensions, which the browser uses to reserve space before the image loads — preventing Cumulative Layout Shift (CLS).

AttributeRequiredDescription
srcYesImage URL or path
altYesAlternative text for screen readers and broken images
widthNoIntrinsic width in pixels (prevents CLS)
heightNoIntrinsic height in pixels (prevents CLS)
srcsetNoList of candidate images with width descriptors
sizesNoDisplay size conditions for srcset selection
loadingNoLazy or eager loading behavior
decodingNoHint for synchronous or asynchronous decode
fetchpriorityNoRelative fetch priority hint
img-element.html
HTML
1<!-- Minimum viable image -->
2<img src="photo.jpg" alt="Description" />
3
4<!-- Image with dimensions to prevent CLS -->
5<img
6 src="photo.jpg"
7 alt="Golden Gate Bridge at sunset"
8 width="1920"
9 height="1080"
10/>
11
12<!-- Image with all performance attributes -->
13<img
14 src="photo.jpg"
15 alt="Mountain lake reflection"
16 width="1920"
17 height="1080"
18 loading="lazy"
19 decoding="async"
20 fetchpriority="low"
21/>
22
23<!-- Hero image — eager loading, high priority -->
24<img
25 src="hero.jpg"
26 alt="Welcome banner featuring our product"
27 width="1440"
28 height="600"
29 loading="eager"
30 decoding="async"
31 fetchpriority="high"
32/>
33
34<!-- Decorative image — empty alt -->
35<img
36 src="divider.svg"
37 alt=""
38 role="presentation"
39 width="100"
40 height="20"
41/>
Image Formats

Choosing the right image format balances quality against file size. Modern formats like WebP and AVIF offer 25-50% size reductions over JPEG at equivalent visual quality. SVG is ideal for logos, icons, and illustrations that need to scale to any resolution.

FormatCompressionTransparencyAnimationBest For
AVIFBest (AV1 intra-frame)YesYesPhotos, complex images — best quality/size ratio
WebPExcellent (VP8/VP9)YesYesPhotos, graphics — broad browser support
JPEGGood (lossy DCT)NoNoPhotographs with smooth gradients
PNGLossless (deflate)YesNoScreenshots, graphics with text, transparency
GIFPoor (LZW, 256 colors)Yes (binary)YesSimple animations (use video or WebP instead)
SVGVector — scales infinitelyYesYes (SMIL)Logos, icons, illustrations, charts
image-formats.html
HTML
1<!-- Format selection with picture element -->
2<picture>
3 <!-- AVIF: best compression -->
4 <source
5 srcset="photo.avif"
6 type="image/avif"
7 />
8 <!-- WebP: broad support -->
9 <source
10 srcset="photo.webp"
11 type="image/webp"
12 />
13 <!-- JPEG fallback for legacy browsers -->
14 <img
15 src="photo.jpg"
16 alt="Landscape photograph"
17 width="1920"
18 height="1080"
19 loading="lazy"
20 decoding="async"
21 />
22</picture>
23
24<!-- SVG embedded inline -->
25<svg viewBox="0 0 100 100" width="50" height="50">
26 <circle cx="50" cy="50" r="40" fill="#00FF41" />
27</svg>
28
29<!-- SVG via img element -->
30<img src="logo.svg" alt="Company logo" width="200" height="50" />
🔥

pro tip

Use the <picture> element with multiple type attributes to serve AVIF and WebP with a JPEG or PNG fallback. The browser selects the first supported format and downloads nothing else. Always include width and height on the fallback <img>.
Responsive Images

Responsive images serve different image files based on the viewport size and device pixel density. The srcset attribute lists candidate images with width descriptors (640w, 1024w), and the sizes attribute tells the browser how wide the image will display at different breakpoints. The <picture> element provides art direction — different crops or compositions per viewport.

TechniqueHTMLUse Case
Resolution switchingsrcset with w descriptors + sizesSame image, different pixel densities
Art direction<picture> + <source media>Different crop per breakpoint
Format selection<picture> + <source type>AVIF/WebP with fallback
Pixel densitysrcset with x descriptors (1x, 2x, 3x)Retina displays, fixed-width images
responsive-images.html
HTML
1<!-- Resolution switching with srcset and sizes -->
2<img
3 src="photo-640.jpg"
4 srcset="
5 photo-320.jpg 320w,
6 photo-640.jpg 640w,
7 photo-960.jpg 960w,
8 photo-1280.jpg 1280w,
9 photo-1920.jpg 1920w
10 "
11 sizes="
12 (max-width: 480px) 100vw,
13 (max-width: 768px) 80vw,
14 (max-width: 1200px) 60vw,
15 1200px
16 "
17 alt="Mountain landscape at dawn"
18 width="1920"
19 height="1080"
20 loading="lazy"
21 decoding="async"
22/>
23
24<!-- Pixel density for fixed-width images -->
25<img
26 src="logo-1x.png"
27 srcset="
28 logo-1x.png 1x,
29 logo-2x.png 2x,
30 logo-3x.png 3x
31 "
32 alt="Company logo"
33 width="200"
34 height="50"
35/>
36
37<!-- Art direction: different crop for mobile -->
38<picture>
39 <source
40 srcset="hero-mobile.jpg"
41 media="(max-width: 640px)"
42 />
43 <source
44 srcset="hero-tablet.jpg"
45 media="(max-width: 1024px)"
46 />
47 <img
48 src="hero-desktop.jpg"
49 alt="Hero banner"
50 width="1920"
51 height="800"
52 loading="eager"
53 fetchpriority="high"
54 />
55</picture>
56
57<!-- Format + resolution combined -->
58<picture>
59 <source
60 srcset="photo-640.avif 640w, photo-1280.avif 1280w"
61 type="image/avif"
62 sizes="(max-width: 768px) 100vw, 80vw"
63 />
64 <source
65 srcset="photo-640.webp 640w, photo-1280.webp 1280w"
66 type="image/webp"
67 sizes="(max-width: 768px) 100vw, 80vw"
68 />
69 <img
70 src="photo-640.jpg"
71 srcset="photo-640.jpg 640w, photo-1280.jpg 1280w"
72 sizes="(max-width: 768px) 100vw, 80vw"
73 alt="City skyline"
74 width="1280"
75 height="720"
76 loading="lazy"
77 decoding="async"
78 />
79</picture>

best practice

Always provide the sizes attribute when using srcset with width descriptors. Without sizes, the browser assumes 100vw (the image fills the full viewport width), which may cause it to download an image larger than necessary.
Figure & Figcaption

The <figure> element represents self-contained content, such as images, diagrams, code snippets, or quotes. The <figcaption> provides a caption or legend. This semantic pairing improves accessibility by associating the caption with the content and helps search engines understand the content structure.

figure-figcaption.html
HTML
1<!-- Figure with image and caption -->
2<figure>
3 <img
4 src="architecture-diagram.svg"
5 alt="System architecture showing client, API gateway, microservices, and database layers"
6 width="800"
7 height="500"
8 loading="lazy"
9 />
10 <figcaption>
11 Figure 1: System architecture — clients connect through an API gateway
12 to microservices backed by a distributed PostgreSQL cluster.
13 </figcaption>
14</figure>
15
16<!-- Figure with multiple images -->
17<figure>
18 <img src="before.jpg" alt="UI before redesign" width="400" height="300" loading="lazy" />
19 <img src="after.jpg" alt="UI after redesign" width="400" height="300" loading="lazy" />
20 <figcaption>
21 Before and after: dashboard redesign improved readability
22 and reduced cognitive load by 40%.
23 </figcaption>
24</figure>
25
26<!-- Figure with code block -->
27<figure>
28 <figcaption>Example: Fibonacci in JavaScript</figcaption>
29 <pre><code>function fib(n) {
30 if (n <= 1) return n;
31 return fib(n - 1) + fib(n - 2);
32}</code></pre>
33</figure>
34
35<!-- Nested figure for image + video -->
36<figure>
37 <figure>
38 <img src="screenshot.jpg" alt="App screenshot" width="600" height="400" loading="lazy" />
39 <figcaption>The main dashboard view</figcaption>
40 </figure>
41 <figcaption>Figure 2: Application walkthrough</figcaption>
42</figure>

Live preview of a figure with styled caption:

preview
Image Loading

The loading attribute controls whether an image loads immediately (eager) or waits until it is near the viewport (lazy). The decoding attribute hints whether the browser should decode the image synchronously or asynchronously. These attributes, combined with fetchpriority, give fine-grained control over image loading behavior.

AttributeValuesEffect
loadinglazy | eagerLazy defers loading until image is near the viewport; eager loads immediately
decodingasync | sync | autoAsync decodes off the main thread; sync blocks rendering until decode finishes
fetchpriorityhigh | low | autoHint for relative fetch priority; high prioritizes the image fetch
image-loading.html
HTML
1<!-- Lazy loading — defer off-screen images -->
2<img
3 src="gallery-photo.jpg"
4 alt="Gallery image"
5 width="800"
6 height="600"
7 loading="lazy"
8 decoding="async"
9 fetchpriority="low"
10/>
11
12<!-- Eager loading — critical above-the-fold image -->
13<img
14 src="hero.jpg"
15 alt="Hero banner"
16 width="1440"
17 height="600"
18 loading="eager"
19 decoding="sync"
20 fetchpriority="high"
21/>
22
23<!-- Preload the LCP image in <head> -->
24<link
25 rel="preload"
26 href="hero-1920.jpg"
27 as="image"
28 imagesrcset="hero-640.jpg 640w, hero-1024.jpg 1024w, hero-1920.jpg 1920w"
29 imagesizes="100vw"
30/>
31
32<!-- Lazy loaded gallery with a loading placeholder -->
33<div class="gallery">
34 <img
35 src="photo1.jpg"
36 alt="Gallery photo 1"
37 width="400"
38 height="300"
39 loading="lazy"
40 decoding="async"
41 />
42 <img
43 src="photo2.jpg"
44 alt="Gallery photo 2"
45 width="400"
46 height="300"
47 loading="lazy"
48 decoding="async"
49 />
50 <img
51 src="photo3.jpg"
52 alt="Gallery photo 3"
53 width="400"
54 height="300"
55 loading="lazy"
56 decoding="async"
57 />
58</div>

warning

Lazy loading improves performance for below-the-fold images but can harm the Largest Contentful Paint (LCP) score if applied to hero images. Always use loading="eager" with fetchpriority="high" on the LCP image. Consider using rel="preload" in the <head> for critical hero images to prioritize the fetch before the browser discovers the image in the HTML.
Image CDN & Optimization

Image CDNs (Content Delivery Networks) provide on-the-fly image transformation — resizing, format conversion, quality adjustment, and cropping — through URL parameters. This eliminates the need to manually generate multiple image variants. Services like Cloudinary, Imgix, and Cloudflare Images handle WebP/AVIF negotiation automatically.

image-cdn.html
HTML
1<!-- CDN URL pattern with transformation parameters -->
2
3<!-- Cloudinary-style: resize to 640px width, auto format -->
4<img
5 src="https://cdn.example.com/image.jpg?w=640&f=auto&q=80"
6 alt="CDN optimized image"
7 width="640"
8 height="480"
9 loading="lazy"
10/>
11
12<!-- Responsive images via CDN with srcset -->
13<img
14 src="https://cdn.example.com/image.jpg?w=640&f=auto&q=80"
15 srcset="
16 https://cdn.example.com/image.jpg?w=320&f=auto&q=80 320w,
17 https://cdn.example.com/image.jpg?w=640&f=auto&q=80 640w,
18 https://cdn.example.com/image.jpg?w=960&f=auto&q=80 960w,
19 https://cdn.example.com/image.jpg?w=1280&f=auto&q=80 1280w
20 "
21 sizes="
22 (max-width: 480px) 100vw,
23 (max-width: 768px) 80vw,
24 1200px
25 "
26 alt="CDN responsive image"
27 width="1280"
28 height="960"
29 loading="lazy"
30 decoding="async"
31/>
32
33<!-- CDN with format selection via picture -->
34<picture>
35 <source
36 srcset="https://cdn.example.com/image.jpg?w=640&f=avif&q=75"
37 type="image/avif"
38 />
39 <source
40 srcset="https://cdn.example.com/image.jpg?w=640&f=webp&q=80"
41 type="image/webp"
42 />
43 <img
44 src="https://cdn.example.com/image.jpg?w=640&f=jpeg&q=85"
45 alt="CDN format optimized"
46 width="640"
47 height="480"
48 loading="lazy"
49 />
50</picture>
51
52<!-- CDN with focal point cropping -->
53<img
54 src="https://cdn.example.com/image.jpg?w=400&h=400&fit=crop&crop=focal&fp-x=0.5&fp-y=0.3"
55 alt="Smart cropped image"
56 width="400"
57 height="400"
58 loading="lazy"
59/>
🔥

pro tip

When using an image CDN, always include the f=auto or equivalent format negotiation parameter. This lets the CDN serve AVIF to supporting browsers, WebP to Chrome/Firefox, and JPEG to legacy browsers — all from a single src URL. No <picture> element needed for format selection alone.
Background Images vs img

Deciding between CSS background-image and the HTML <img> element depends on the image's role. If the image is content (adds meaning), use <img> with descriptive alt text. If the image is decorative (pure visual styling), use CSS background-image.

CriterionUse <img>Use CSS background-image
Semantic roleContent — image adds informationDecorative — image is visual styling
AccessibilityNeeds alt text for screen readersHidden from screen readers (no alt needed)
Responsive behaviorsrcset/sizes for resolution switchingbackground-size with media queries
Lazy loadingNative loading="lazy" attributeRequires JavaScript Intersection Observer
PrintingPrinted by defaultUsually not printed (print stylesheet needed)
SEOIndexed by search enginesNot indexed
background-vs-img.html
HTML
1<!-- Content image — use <img> with alt -->
2<article>
3 <h2>Product Launch Event</h2>
4 <img
5 src="launch-event.jpg"
6 alt="CEO presenting the new product on stage at the 2026 launch event"
7 width="1200"
8 height="800"
9 loading="lazy"
10 />
11 <p>The event drew over 500 attendees...</p>
12</article>
13
14<!-- Decorative background — use CSS -->
15<style>
16 .hero-section {
17 background-image: url('texture.svg');
18 background-size: cover;
19 background-position: center;
20 /* Ensure background does not convey meaning */
21 }
22</style>
23<div class="hero-section" role="presentation">
24 <h1>Welcome</h1>
25</div>
26
27<!-- Hero with both — content heading + decorative bg -->
28<style>
29 .hero-banner {
30 position: relative;
31 width: 100%;
32 height: 60vh;
33 background-image: url('bg-texture.webp');
34 background-size: cover;
35 overflow: hidden;
36 }
37</style>
38<div class="hero-banner">
39 <!-- Content image for accessibility + SEO -->
40 <img
41 src="hero-content.jpg"
42 alt="Team collaborating in the new office space"
43 class="hero-content-img"
44 width="1920"
45 height="1080"
46 loading="eager"
47 fetchpriority="high"
48 />
49 <div class="hero-overlay">
50 <h1>Our Mission</h1>
51 <p>Building the future of web technology</p>
52 </div>
53</div>

best practice

A content image without alt text is inaccessible. If the image is purely decorative, use alt="" with role="presentation" or use CSS background-image. Never omit the alt attribute entirely — a missing alt attribute causes screen readers to read the image file name aloud.

Live preview comparing content image with decorative background:

preview
Accessibility

Accessible images ensure users with visual impairments can understand the content. The alt attribute is the primary mechanism — screen readers announce it in place of the image. The <figure> and <figcaption> pair provides additional context. Complex images like charts need extended descriptions.

Image Typealt Text GuidelineExample
InformativeBriefly describe the contentalt="Golden Gate Bridge at sunset"
Functional (link/button)Describe the destination or actionalt="View product details"
DecorativeEmpty alt — screen readers ignorealt="" role="presentation"
Complex (chart/diagram)Brief summary + link to long descriptionalt="Bar chart showing Q1-Q4 revenue" + adjacent data table
LogoCompany name (linked to homepage)alt="Acme Corp homepage"
Icon (with text nearby)Empty alt (text already conveys meaning)alt="" aria-hidden="true"
image-accessibility.html
HTML
1<!-- Informative image — describe the content -->
2<img
3 src="chart.png"
4 alt="Line chart showing user growth from 10K in January to 85K in December 2026"
5 width="800"
6 height="500"
7 loading="lazy"
8/>
9
10<!-- Functional image as a link -->
11<a href="/products/laptop">
12 <img
13 src="laptop-thumb.jpg"
14 alt="View product details for the UltraBook Pro"
15 width="300"
16 height="300"
17 loading="lazy"
18 />
19</a>
20
21<!-- Decorative image — empty alt with presentation role -->
22<img
23 src="divider-line.svg"
24 alt=""
25 role="presentation"
26 width="100%"
27 height="2"
28/>
29
30<!-- Complex image with data table fallback -->
31<figure>
32 <img
33 src="revenue-chart.png"
34 alt="Bar chart: revenue grew from $2.1M in Q1 to $3.8M in Q4"
35 width="800"
36 height="500"
37 loading="lazy"
38 />
39 <figcaption>Figure 4: Quarterly Revenue 2026</figcaption>
40</figure>
41<!-- Data table for screen readers and users who cannot see the chart -->
42<table aria-label="Revenue data behind the chart">
43 <caption>Revenue by quarter</caption>
44 <thead>
45 <tr><th>Quarter</th><th>Revenue</th></tr>
46 </thead>
47 <tbody>
48 <tr><td>Q1</td><td>$2.1M</td></tr>
49 <tr><td>Q2</td><td>$2.7M</td></tr>
50 <tr><td>Q3</td><td>$3.2M</td></tr>
51 <tr><td>Q4</td><td>$3.8M</td></tr>
52 </tbody>
53</table>
54
55<!-- Icon with adjacent text -->
56<button aria-label="Search">
57 <img src="search-icon.svg" alt="" aria-hidden="true" width="20" height="20" />
58</button>

best practice

Alt text should convey the content and function of the image, not describe its visual appearance. Write alt="CEO presenting the new product on stage" rather than alt="Person standing on stage". For complex data visualizations, always provide the underlying data in an adjacent table or a link to a detailed description.
Best Practices

Responsive Images Checklist

Always include width and height attributes on every img element to prevent Cumulative Layout Shift (CLS) — the browser calculates aspect ratio and reserves space before the image loads
Use loading=lazy for images below the fold; use loading=eager with fetchpriority=high on the Largest Contentful Paint (LCP) image
Provide srcset with at least 3 width breakpoints (640w, 1024w, 1920w) for responsive resolution switching — include corresponding images at those resolutions
Use the picture element with type attributes for AVIF and WebP format selection, always with a JPEG or PNG fallback
Set decoding=async on all images to avoid blocking the main thread during image decode — this is especially impactful for large images
Use an image CDN (Cloudinary, Imgix, Cloudflare Images, Next.js Image) for automatic resizing, format conversion, quality optimization, and cache management
Compress images aggressively — aim for 60-80% quality for photographs. The visual difference between 80% and 100% JPEG quality is negligible but the file size difference is 2-3x
Use object-fit: cover and object-position for CSS-controlled image cropping within containers — this gives you responsive aspect ratio control without distorting the image
Preload the LCP image using <link rel=preload as=image> in the document head to initiate the fetch before the browser discovers the img element in the HTML
Serve images from a CDN with long-lived cache headers: Cache-Control: public, max-age=31536000, immutable — use content-based filenames (hashes) for cache invalidation

Format Selection Guide

Content TypePrimary FormatFallback
PhotographsAVIF (best compression) or WebPJPEG
Screenshots / UIWebP or PNG (lossless)PNG
Logos / IconsSVG (vector, scales infinitely)PNG with @2x for retina
Simple animationsWebP or AVIF animated, or MP4 videoGIF (last resort — 256 color limit)
IllustrationsSVG (if vector) or WebPPNG

info

When in doubt, use a single high-quality JPEG with loading="lazy" and width/height attributes. This covers 99% of use cases and is better than over-engineering responsive images for a small blog or personal site. Add srcset and <picture> only when performance metrics or design requirements demand it.

Live preview of an optimized responsive image gallery demonstrating format badges and resolution indicators:

preview
$Blueprint — Engineering Documentation·Section ID: HTML-19·Revision: 1.0