Media Element
HTML 2.0
The image element embeds an image into the document. It’s one of the most commonly used HTML elements and supports modern features like responsive images, lazy loading, and performance optimization.
Interactive code playground requires JavaScript. Here's the code:
<img src="https://picsum.photos/400/300"
alt="A random placeholder image"
width="400"
height="300">
< img src = " path/to/image.jpg " alt = " Description of image " >
The <img> element is a void element (self-closing) and requires no closing tag.
Specifies the URL or path to the image:
Interactive code playground requires JavaScript. Here's the code:
<!-- Relative URL -->
<img src="/images/logo.png" alt="Company logo">
<!-- Absolute URL -->
<img src="https://example.com/photo.jpg" alt="Photo">
<!-- Data URL (inline image) -->
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><circle cx='50' cy='50' r='40' fill='%233b82f6'/></svg>"
alt="Blue circle">
Provides alternative text when the image cannot be displayed or for screen readers:
<!-- Informative image -->
< img src = " chart.png " alt = " Sales increased 25% in Q4 2024 " >
<!-- Decorative image -->
< img src = " divider.png " alt = "" >
<!-- Functional image (button/link) -->
< img src = " home-icon.png " alt = " Go to homepage " >
<!-- Complex image with details nearby -->
< img src = " infographic.png "
alt = " Climate change statistics. See detailed data below. " >
< img src = " chart.png " alt = " chart " >
<!-- Redundant "image of" -->
< img src = " dog.jpg " alt = " image of a dog " >
<!-- Missing alt entirely -->
<!-- Filename as alt text -->
< img src = " IMG_1234.jpg " alt = " IMG_1234.jpg " >
Specify dimensions in pixels. Setting these prevents layout shifts during page load:
Interactive code playground requires JavaScript. Here's the code:
<style>
img {
border: 2px solid #3b82f6;
max-width: 100%;
height: auto;
}
</style>
<!-- With width/height: reserves space immediately -->
<img src="https://picsum.photos/400/300"
alt="Landscape photo"
width="400"
height="300">
<p>Text below image stays stable while loading</p>
Provides multiple image sources for different screen densities:
Interactive code playground requires JavaScript. Here's the code:
<!-- Different resolutions for different pixel densities -->
<img src="photo-400.jpg"
srcset="photo-400.jpg 1x,
photo-800.jpg 2x,
photo-1200.jpg 3x"
alt="Responsive photo"
width="400"
height="300">
<!-- 1x: Standard displays
2x: Retina/HiDPI displays
3x: High-end mobile displays -->
Let the browser choose the best image based on viewport width:
Interactive code playground requires JavaScript. Here's the code:
<img src="photo-800.jpg"
srcset="photo-400.jpg 400w,
photo-800.jpg 800w,
photo-1200.jpg 1200w,
photo-1600.jpg 1600w"
sizes="(max-width: 600px) 100vw,
(max-width: 1200px) 50vw,
800px"
alt="Adaptive image"
width="800"
height="600">
<!-- Browser picks best image based on:
- Viewport size
- Screen density
- Network conditions (in some browsers) -->
How sizes works:
(max-width: 600px) 100vw - On screens ≤600px, image fills viewport width
(max-width: 1200px) 50vw - On screens ≤1200px, image is 50% of viewport
800px - Default: image displays at 800px
Interactive code playground requires JavaScript. Here's the code:
<style>
.responsive-img {
width: 100%;
max-width: 800px;
height: auto;
display: block;
}
</style>
<img class="responsive-img"
src="https://picsum.photos/800/600"
srcset="https://picsum.photos/400/300 400w,
https://picsum.photos/800/600 800w,
https://picsum.photos/1200/900 1200w"
sizes="(max-width: 600px) 100vw,
(max-width: 1000px) 80vw,
800px"
alt="Fully responsive image"
width="800"
height="600">
Control when images load to improve page performance:
Interactive code playground requires JavaScript. Here's the code:
<!-- Lazy load images below the fold -->
<img src="hero.jpg" alt="Hero image" loading="eager">
<p>Scroll down to see lazy-loaded images...</p>
<!-- These load when near viewport -->
<img src="https://picsum.photos/600/400?random=1"
alt="Lazy image 1"
loading="lazy"
width="600"
height="400">
<img src="https://picsum.photos/600/400?random=2"
alt="Lazy image 2"
loading="lazy"
width="600"
height="400">
Values:
lazy - Defer loading until image nears viewport (recommended for below-fold images)
eager - Load immediately (default, use for above-fold images)
Control how the browser decodes the image:
<!-- Async decoding: don't block page rendering -->
< img src = " large-photo.jpg " alt = " Large photo " decoding = " async " >
<!-- Sync decoding: decode before rendering (rare use case) -->
< img src = " critical-ui.png " alt = " UI element " decoding = " sync " >
<!-- Auto: let browser decide (default) -->
< img src = " photo.jpg " alt = " Photo " decoding = " auto " >
Use async decoding for large images to prevent blocking the main thread.
Hint to the browser about image loading priority:
<!-- High priority: critical above-fold image -->
<!-- Low priority: below-fold image -->
< img src = " footer-logo.png "
<!-- Auto: default browser behavior -->
< img src = " content.jpg " alt = " Content " fetchpriority = " auto " >
Use the <picture> element for format fallbacks:
Interactive code playground requires JavaScript. Here's the code:
<picture>
<!-- Modern format: best compression -->
<source srcset="photo.avif" type="image/avif">
<!-- Widely supported modern format -->
<source srcset="photo.webp" type="image/webp">
<!-- Fallback for older browsers -->
<img src="photo.jpg" alt="Photo with modern formats"
width="400" height="300">
</picture>
Format comparison:
AVIF : Best compression (~30% smaller than WebP), limited support
WebP : Great compression (~25% smaller than JPEG), wide support
JPEG/PNG : Universal support, larger file sizes
Control CORS requests for images:
<!-- Anonymous: no credentials -->
< img src = " https://cdn.example.com/image.jpg "
<!-- Use credentials: send cookies/auth -->
< img src = " https://api.example.com/user/avatar.jpg "
crossorigin = " use-credentials " >
When to use:
Canvas manipulation with drawImage()
CSS filters applied to cross-origin images
WebGL textures
Control what referrer information is sent:
<!-- Don't send referrer -->
< img src = " https://external.com/pixel.gif "
referrerpolicy = " no-referrer " >
<!-- Send origin only -->
< img src = " https://cdn.example.com/image.jpg "
<!-- Full referrer for same-origin, origin for cross-origin -->
referrerpolicy = " strict-origin-when-cross-origin " >
Associate clickable areas with an image using <map> and <area>:
Interactive code playground requires JavaScript. Here's the code:
<img src="https://picsum.photos/400/300"
alt="Clickable regions"
usemap="#regions"
width="400"
height="300">
<map name="regions">
<area shape="rect" coords="0,0,200,150"
href="#top-left" alt="Top left">
<area shape="rect" coords="200,0,400,150"
href="#top-right" alt="Top right">
<area shape="rect" coords="0,150,200,300"
href="#bottom-left" alt="Bottom left">
<area shape="rect" coords="200,150,400,300"
href="#bottom-right" alt="Bottom right">
</map>
Interactive code playground requires JavaScript. Here's the code:
<img src="https://picsum.photos/800/600"
srcset="https://picsum.photos/400/300 400w,
https://picsum.photos/800/600 800w,
https://picsum.photos/1200/900 1200w"
sizes="(max-width: 600px) 100vw, 800px"
alt="Optimized responsive image"
width="800"
height="600"
loading="lazy"
decoding="async"
fetchpriority="low">
Interactive code playground requires JavaScript. Here's the code:
<div id="status">Loading image...</div>
<img src="https://picsum.photos/400/300?random=3"
alt="Event demo"
id="event-img"
width="400"
height="300">
<script>
const img = document.getElementById('event-img');
const status = document.getElementById('status');
img.addEventListener('load', () => {
status.textContent = '✓ Image loaded successfully';
status.style.color = 'green';
});
img.addEventListener('error', () => {
status.textContent = '✗ Failed to load image';
status.style.color = 'red';
});
</script>
Interactive code playground requires JavaScript. Here's the code:
<style>
.img-container {
position: relative;
width: 400px;
height: 300px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.img-container img {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
}
</style>
<div class="img-container">
<!-- Blurred thumbnail loads instantly -->
<img src="https://picsum.photos/40/30?blur=10"
alt="Placeholder"
style="filter: blur(20px);">
<!-- Full image fades in when loaded -->
<img src="https://picsum.photos/400/300"
alt="Full resolution image"
loading="lazy">
</div>
Interactive code playground requires JavaScript. Here's the code:
<style>
.img-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
.img-grid img {
width: 100%;
height: 150px;
border: 2px solid #3b82f6;
}
</style>
<div class="img-grid">
<div>
<img src="https://picsum.photos/400/600"
alt="Cover"
style="object-fit: cover;">
<p>object-fit: cover</p>
</div>
<div>
<img src="https://picsum.photos/400/600"
alt="Contain"
style="object-fit: contain; background: #f0f0f0;">
<p>object-fit: contain</p>
</div>
<div>
<img src="https://picsum.photos/400/600"
alt="Fill"
style="object-fit: fill;">
<p>object-fit: fill</p>
</div>
</div>
Interactive code playground requires JavaScript. Here's the code:
<style>
.responsive {
max-width: 100%;
height: auto;
display: block;
}
.rounded {
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.circle {
border-radius: 50%;
width: 150px;
height: 150px;
object-fit: cover;
}
</style>
<img src="https://picsum.photos/400/300"
alt="Responsive"
class="responsive rounded">
<img src="https://picsum.photos/300/300"
alt="Circle"
class="circle">
<!-- Descriptive and concise -->
alt = " Orange sunset over mountain peaks " >
<!-- Empty for decorative -->
< img src = " border.png " alt = "" >
<!-- Functional description for links -->
< img src = " search-icon.svg " alt = " Search " >
alt = " Bar chart showing 40% revenue increase " >
< figcaption > Quarterly revenue growth </ figcaption >
alt = " A beautiful sunset with orange and pink hues over the mountain peaks with some clouds in the sky and trees in the foreground during golden hour " >
<!-- Redundant "image of" -->
< img src = " dog.jpg " alt = " image of a dog " >
< img src = " important.jpg " >
< img src = " banner.jpg " alt = " banner " >
For complex images like infographics or charts:
Interactive code playground requires JavaScript. Here's the code:
<!-- Option 1: Link to detailed description -->
<figure>
<img src="complex-chart.png"
alt="Sales data chart"
aria-describedby="chart-desc">
<figcaption id="chart-desc">
Detailed description: Sales increased from $10M in Q1
to $15M in Q4, with steady growth each quarter.
</figcaption>
</figure>
<!-- Option 2: Longdesc (deprecated but still useful) -->
<img src="infographic.png"
alt="2024 climate change statistics"
longdesc="climate-data.html">
<!-- Avoid: Don't use title as primary description -->
< img src = " photo.jpg " title = " Beach photo " >
<!-- Better: Use alt, add title only for extra context -->
alt = " Sunset beach in Hawaii "
title = " Photo taken in Maui, December 2024 " >
Interactive code playground requires JavaScript. Here's the code:
<style>
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 10px;
}
.gallery img {
width: 100%;
height: 150px;
object-fit: cover;
border-radius: 8px;
transition: transform 0.2s;
}
.gallery img:hover {
transform: scale(1.05);
}
</style>
<div class="gallery">
<img src="https://picsum.photos/300/300?random=1"
alt="Gallery image 1" loading="lazy">
<img src="https://picsum.photos/300/300?random=2"
alt="Gallery image 2" loading="lazy">
<img src="https://picsum.photos/300/300?random=3"
alt="Gallery image 3" loading="lazy">
<img src="https://picsum.photos/300/300?random=4"
alt="Gallery image 4" loading="lazy">
</div>
Interactive code playground requires JavaScript. Here's the code:
<style>
.avatar {
width: 80px;
height: 80px;
border-radius: 50%;
object-fit: cover;
border: 3px solid #3b82f6;
}
.avatar-container {
display: inline-block;
position: relative;
}
.avatar-badge {
position: absolute;
bottom: 0;
right: 0;
width: 24px;
height: 24px;
background: #10b981;
border: 2px solid white;
border-radius: 50%;
}
</style>
<div class="avatar-container">
<img src="https://i.pravatar.cc/150?img=12"
alt="User profile picture"
class="avatar">
<div class="avatar-badge" title="Online"></div>
</div>
Interactive code playground requires JavaScript. Here's the code:
<style>
.img-fallback {
position: relative;
display: inline-block;
width: 300px;
height: 200px;
background: #f3f4f6;
}
.img-fallback img {
width: 100%;
height: 100%;
object-fit: cover;
}
.img-fallback::after {
content: "⚠️ Image not available";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #6b7280;
font-size: 14px;
display: none;
}
.img-fallback img[alt]::after {
display: none;
}
</style>
<div class="img-fallback">
<img src="broken-link.jpg"
alt="This image will fail to load"
onerror="this.style.display='none'; this.parentElement.style.display='flex'; this.parentElement.style.alignItems='center'; this.parentElement.style.justifyContent='center';">
</div>
Feature Chrome Firefox Safari Edge Basic <img> 1+ 1+ 1+ 12+ srcset & sizes38+ 38+ 9+ 13+ loading="lazy"77+ 75+ 15.4+ 79+ decoding65+ 63+ 11.1+ 79+ fetchpriority101+ ❌ 17.2+ 101+ WebP format 23+ 65+ 14+ 18+ AVIF format 85+ 93+ 16+ 85+
✅ Always set width and height to prevent layout shifts
✅ Use loading="lazy" for below-fold images
✅ Use srcset and sizes for responsive images
✅ Compress images (use tools like ImageOptim, Squoosh)
✅ Serve modern formats (WebP, AVIF) with fallbacks
✅ Set fetchpriority="high" on LCP image
✅ Use appropriate image dimensions (don’t serve 4K for 400px display)
✅ Consider using a CDN with automatic optimization