HTML Images & Figures
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 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).
| Attribute | Required | Description |
|---|---|---|
| src | Yes | Image URL or path |
| alt | Yes | Alternative text for screen readers and broken images |
| width | No | Intrinsic width in pixels (prevents CLS) |
| height | No | Intrinsic height in pixels (prevents CLS) |
| srcset | No | List of candidate images with width descriptors |
| sizes | No | Display size conditions for srcset selection |
| loading | No | Lazy or eager loading behavior |
| decoding | No | Hint for synchronous or asynchronous decode |
| fetchpriority | No | Relative fetch priority hint |
| 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 | /> |
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.
| Format | Compression | Transparency | Animation | Best For |
|---|---|---|---|---|
| AVIF | Best (AV1 intra-frame) | Yes | Yes | Photos, complex images — best quality/size ratio |
| WebP | Excellent (VP8/VP9) | Yes | Yes | Photos, graphics — broad browser support |
| JPEG | Good (lossy DCT) | No | No | Photographs with smooth gradients |
| PNG | Lossless (deflate) | Yes | No | Screenshots, graphics with text, transparency |
| GIF | Poor (LZW, 256 colors) | Yes (binary) | Yes | Simple animations (use video or WebP instead) |
| SVG | Vector — scales infinitely | Yes | Yes (SMIL) | Logos, icons, illustrations, charts |
| 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
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.
| Technique | HTML | Use Case |
|---|---|---|
| Resolution switching | srcset with w descriptors + sizes | Same image, different pixel densities |
| Art direction | <picture> + <source media> | Different crop per breakpoint |
| Format selection | <picture> + <source type> | AVIF/WebP with fallback |
| Pixel density | srcset with x descriptors (1x, 2x, 3x) | Retina displays, fixed-width images |
| 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
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.
| 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:
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.
| Attribute | Values | Effect |
|---|---|---|
| loading | lazy | eager | Lazy defers loading until image is near the viewport; eager loads immediately |
| decoding | async | sync | auto | Async decodes off the main thread; sync blocks rendering until decode finishes |
| fetchpriority | high | low | auto | Hint for relative fetch priority; high prioritizes the image fetch |
| 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
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.
| 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
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.
| Criterion | Use <img> | Use CSS background-image |
|---|---|---|
| Semantic role | Content — image adds information | Decorative — image is visual styling |
| Accessibility | Needs alt text for screen readers | Hidden from screen readers (no alt needed) |
| Responsive behavior | srcset/sizes for resolution switching | background-size with media queries |
| Lazy loading | Native loading="lazy" attribute | Requires JavaScript Intersection Observer |
| Printing | Printed by default | Usually not printed (print stylesheet needed) |
| SEO | Indexed by search engines | Not indexed |
| 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
Live preview comparing content image with decorative background:
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 Type | alt Text Guideline | Example |
|---|---|---|
| Informative | Briefly describe the content | alt="Golden Gate Bridge at sunset" |
| Functional (link/button) | Describe the destination or action | alt="View product details" |
| Decorative | Empty alt — screen readers ignore | alt="" role="presentation" |
| Complex (chart/diagram) | Brief summary + link to long description | alt="Bar chart showing Q1-Q4 revenue" + adjacent data table |
| Logo | Company name (linked to homepage) | alt="Acme Corp homepage" |
| Icon (with text nearby) | Empty alt (text already conveys meaning) | alt="" aria-hidden="true" |
| 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
Responsive Images Checklist
Format Selection Guide
| Content Type | Primary Format | Fallback |
|---|---|---|
| Photographs | AVIF (best compression) or WebP | JPEG |
| Screenshots / UI | WebP or PNG (lossless) | PNG |
| Logos / Icons | SVG (vector, scales infinitely) | PNG with @2x for retina |
| Simple animations | WebP or AVIF animated, or MP4 video | GIF (last resort — 256 color limit) |
| Illustrations | SVG (if vector) or WebP | PNG |
info
Live preview of an optimized responsive image gallery demonstrating format badges and resolution indicators: