Mastering Images in HTML5
Learn images in HTML5 from the basic to advanced: the img tag, key attributes, image optimization for web, layout shift prevention, and displaying images perfectly.
Close your eyes and picture your favorite website. Now imagine every single image removed. Just text sitting on a plain background. Not quite the same, right?
Images are what give the web its personality. They communicate in a split second. They explain things words can’t. They make your pages feel real and worth visiting. And the good news: working with images in HTML5 is genuinely straightforward once you know how the pieces fit together.
This tutorial covers everything you need, from your first img tag and its attributes, all the way to image formats, optimization, and getting your images to display perfectly. By the end, you’ll know exactly what you’re writing and why.
If you’re just getting started with HTML, our guide on what HTML5 is is a great starting point before diving in here.
01The img Tag in HTML: Your Starting Point
The img tag in HTML is how you put an image on a webpage. It’s one of the most-used tags you’ll ever write. Here’s the simplest version:
<img src="photo.jpg" alt="A beautiful mountain landscape">
Two things worth noticing immediately.
First, the img tag has no closing tag. It’s what HTML calls a void element: it stands on its own. There’s no </img> to write. You might occasionally see <img /> with a self-closing slash, which is a habit from older XHTML. That’s perfectly valid in HTML5, but the slash isn’t required.
Second, notice the two attributes: src and alt. You need both. Technically the browser will load an image with just src, but leaving out alt is a real mistake. You’ll see exactly why shortly.
If you’re still building your understanding of how HTML attributes work, our article on HTML tags, elements, and attributes gives you everything you need as a foundation.
How the src Attribute Works
The src attribute is short for “source”. It tells the browser where to find the image file. You give it a path, and the browser fetches and displays the image.
There are two types of paths you’ll use:
Absolute paths are complete URLs pointing to images anywhere on the internet:
<img src="https://daniyaldev.com/wp-content/uploads/2026/01/social-share-scaled.png"
alt="DaniyalDev website preview">
Relative paths point to image files in your own project, relative to where your HTML file sits:
<!-- Image in an 'images' folder next to your HTML file -->
<img src="images/photo.jpg" alt="My photo">
<!-- Image one folder level up -->
<img src="../assets/banner.jpg" alt="Banner">
<!-- Image in the same folder as the HTML file -->
<img src="logo.png" alt="Logo">
For your own project files, always use relative paths. They work on any server without changes, and they keep your code portable.
02img Tag Attributes in HTML: The Full Breakdown
There are more img tag attributes in HTML than just src and alt. Knowing all of them separates beginner HTML from confident HTML.
Here’s what a well-written img tag actually looks like, with everything labeled:
src
: path to the image file
alt
: text description
width
: display width (pixels)
height
: display height (pixels)
loading
: lazy or eager
decoding
: async, sync, or auto
Now let’s go through each attribute so you know exactly what it does.
The alt Attribute
The alt attribute gives your image a text description. When the image fails to load, this text appears in its place. Screen readers read it aloud for visually impaired users. Search engines read it to understand what the image contains.
<img src="sunset.jpg" alt="Orange and pink sunset over a calm ocean">
The next article in this series goes deep on alt text specifically, because it’s a topic that deserves its own dedicated space. For now, the rule is simple: always include a descriptive alt attribute on every meaningful image.
width and height
These two attributes set the display size of the image in pixels:
<img src="photo.jpg" alt="Mountain view" width="800" height="600">
Always set both. There’s a very real reason for this, and we cover it in detail later in this article when we talk about layout shift.
The title Attribute
The title attribute shows a small tooltip when a desktop user hovers their mouse over the image:
<img src="product.jpg" alt="Red running shoes" title="Available in sizes 6 to 13">
This is optional and purely a bonus. Never put important information here, since touch screen users won’t see it at all. Think of it as a small extra detail for desktop visitors.
The loading Attribute
The loading attribute controls when the browser fetches the image. Two values you’ll use:
<!-- Fetched only when the image is near the viewport -->
<img src="gallery-photo.webp" alt="Gallery photo" loading="lazy">
<!-- Fetched immediately, as soon as the page loads -->
<img src="hero-banner.webp" alt="Page hero banner" loading="eager">
Use loading="lazy" on any image that doesn’t appear in the initial visible area of the page. It can meaningfully reduce your initial page load time. We’ll cover this in depth in a dedicated lazy loading article later in this series.
The decoding Attribute
The decoding attribute hints to the browser how to process the image data:
<img src="photo.webp" alt="Beach view" decoding="async">
With decoding="async", the browser decodes the image in a background thread so it doesn’t block other content from rendering on screen. For most images, especially larger ones, this is a smart choice to make.
The crossorigin Attribute
When loading images from a different domain, such as a CDN, the crossorigin attribute becomes relevant:
<img src="https://cdn.yoursite.com/photo.webp"
alt="CDN-hosted image"
crossorigin="anonymous">
This tells the browser to make the request with CORS headers. It’s especially important if you plan to use a cross-origin image inside an HTML <canvas> element. For regular image display, you usually won’t need it.
03Image Formats Explained: JPEG, PNG, WebP, and AVIF
This is where a lot of beginners lose confidence, and honestly it makes sense: there are too many options and not enough plain explanation.
Choosing the right format is one of the biggest decisions you’ll make when working with images in HTML5. Get it right and your pages load faster and look better. Get it wrong and you’re either serving blurry images or enormous files that slow everything down.
Here’s each format, clearly explained:
JPEG
The timeless classic for photos
Photos with lots of color and detail
Lossy
No
Universal (every browser)
PNG
When transparency is non-negotiable
Logos, icons, graphics with transparency
Lossless
Yes (alpha channel)
Universal (every browser)
WebP
The modern standard for the web
Almost everything: photos, graphics, transparency
Lossy and lossless
Yes
All modern browsers
AVIF
The best compression available today
High-quality photos where file size is critical
Lossy and lossless
Yes
Very good and growing fast
JPEG: The Reliable Classic
JPEG has been around since 1992, and it’s still everywhere on the web. It uses lossy compression, which means it throws away some image data to produce a smaller file. Done well, the quality loss is nearly invisible.
Use JPEG for photographs with lots of colors, gradients, and natural detail. The key limitation: JPEG does not support transparency at all. If your image needs a see-through background, JPEG is not the right tool.
PNG: When You Need That Transparent Background
PNG uses lossless compression, meaning every single pixel is preserved exactly as-is. No quality is sacrificed. The major advantage over JPEG is the alpha channel, which gives you full transparency support.
Use PNG for logos, icons, and any graphic where the background needs to be transparent. The important caveat: PNG files for full-size photographs are enormous. A photo that’s 250KB as a WebP could easily be 3MB as a PNG. Avoid using PNG for photos.
WebP: Your Default Choice for New Projects
WebP was created by Google specifically for web use. It handles both lossy and lossless compression, supports transparency, and produces files roughly 25 to 35 percent smaller than equivalent JPEGs at the same visual quality.
All modern browsers support WebP. If you’re starting a new project today, make WebP your go-to format for images. It outperforms both JPEG and PNG in nearly every situation, with no real downside on modern browsers.
AVIF: The New Contender Worth Knowing
AVIF is the newest format on this list. It can achieve compression that’s up to 50 percent better than JPEG at equivalent visual quality. It supports transparency, and it handles complex photographic detail particularly well.
Browser support for AVIF is strong and growing quickly. The one practical note: encoding AVIF files takes more processing power than WebP, so some older tooling can be slower with it.
The practical strategy right now: use AVIF as your first choice with a WebP fallback. We’ll show you exactly how to pull that off using the <picture> element in an upcoming article in this series.
04Picking the Right Format: A Simple Decision Guide
No more guessing. Here’s a straightforward reference:
| Your situation | Format to use |
|---|---|
| Photo on a blog, landing page, or portfolio | WebP with JPEG as fallback |
| Logo or icon with a transparent background | WebP or PNG |
| Hero image where quality really matters | AVIF with WebP as fallback |
| Graphic with text, sharp edges, or flat colors | PNG or lossless WebP |
| Old project, need every browser to work | JPEG or PNG |
| Animated image | WebP (or GIF for maximum compatibility) |
05Image Optimization for Web: File Size Changes Everything
Here’s a fact that trips up a lot of beginners: you can use the perfect format and still have a slow, frustrating website if your files aren’t optimized.
Image optimization for web is about reducing file size without noticeably hurting visual quality. A 5MB uncompressed photo and a well-optimized 280KB WebP can look completely identical when displayed on a webpage. The difference in load time is not subtle.
This matters beyond user experience too. Page speed is a known ranking factor for search engines, and images are consistently the biggest opportunity for improvement. Google’s web.dev platform has documented this extensively.
Resize Before You Export
If your image will display at 800 pixels wide, don’t upload a 4000-pixel version. The browser downloads the full-size file and then scales it down on screen. All that extra data your visitor downloaded gets thrown away immediately. You’re wasting their bandwidth for nothing.
Always resize your image to approximately match its display dimensions before uploading. Tools like Photoshop, GIMP, Figma, or even a basic photo editor can do this in seconds.
Compress Your Images
Compression reduces file size by removing data the human eye barely registers. For lossy formats like JPEG and WebP, quality settings around 75 to 85 percent usually hit the sweet spot: images that look excellent at dramatically smaller file sizes.
Three free tools worth bookmarking:
- Squoosh (squoosh.app): Built by Google. Lets you compare formats and quality settings side by side in real time. Excellent for understanding what you’re actually trading off.
- TinyPNG (tinypng.com): Simple drag-and-drop compression for PNG and JPEG files. Surprisingly effective.
- ImageOptim: A desktop app for Mac. Great for batch-compressing multiple images at once.
Think About Different Screen Sizes
A full 1400-pixel image downloaded on a mobile phone with a 390-pixel screen is pure waste. HTML5 has a direct solution for this: the srcset attribute, which lets you serve differently-sized versions of the same image to different devices. We’re covering srcset in full in the next article after this one. For now, just keep the problem in the back of your mind.
06Width and Height: Set Them on Every Single Image
This looks like a small detail. It isn’t.
Always set both width and height on your img tags in HTML:
<img src="photo.webp" alt="Mountain landscape at dusk" width="800" height="600">
Without these two attributes, the browser has no idea how much space to reserve for the image before it finishes downloading. What happens next is genuinely irritating for users: the page loads, the text appears, and then the image arrives and shoves all the content downward. Your visitor was about to click something, and suddenly the button jumped 200 pixels. This phenomenon is called Cumulative Layout Shift (CLS), and it’s a real Google ranking metric now.
When you set width and height, the browser carves out the exact space from the very start. The page stays stable as images load, even on a slow connection.
Here’s the part beginners sometimes worry about: “But if I set fixed pixel dimensions in HTML, doesn’t that break responsive layouts?” Not at all. Modern browsers use the HTML width and height values to calculate the image’s aspect ratio, then respect whatever size you apply with CSS. You get layout stability without losing flexibility:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
/* CSS makes the image responsive */
img {
width: 100%;
height: auto;
display: block;
}
</style>
</head>
<body>
<!-- HTML dimensions prevent layout shift.
CSS controls the actual display size.
Both work together, not against each other. -->
<img src="https://daniyaldev.com/wp-content/uploads/2026/01/social-share-scaled.png"
alt="DaniyalDev homepage preview"
width="1200"
height="630">
</body>
</html>
The HTML attributes communicate the shape. CSS controls the actual rendered size. They’re not competing.
07Displaying Images in HTML5 Perfectly
Getting the image onto the page is one thing. Getting it to look exactly right is another. By default, HTML displays images inline, at their natural size, flowing alongside text like any other character. That’s fine for simple cases, but most real projects need more control.
These are the CSS techniques you’ll use constantly when working with images in HTML5.
The Responsive Image Rule
Three lines of CSS that every image in every project should have:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
img {
max-width: 100%; /* Never wider than its container */
height: auto; /* Preserve aspect ratio */
display: block; /* Remove the inline gap beneath */
}
</style>
</head>
<body>
<img src="https://daniyaldev.com/wp-content/uploads/2026/01/social-share-scaled.png"
alt="Responsive image example"
width="1200"
height="630">
</body>
</html>
max-width: 100% lets the image shrink on smaller screens but never grow larger than its natural width. height: auto keeps the aspect ratio correct. display: block eliminates the small gap that browsers add below inline images by default.
object-fit: The Property That Fixes Container Sizing
Here’s a situation you’ll run into constantly: you have a fixed-size container (an image card, a thumbnail slot, an avatar circle), and your image needs to fill it perfectly. If you just stretch the image to match the container dimensions, it distorts. The aspect ratio breaks and it looks terrible.
The object-fit CSS property solves this. Click through the options below to see exactly what each value does:
In practice, here’s how you’d use it for a card component:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
.card-img-wrap {
width: 100%;
height: 220px;
overflow: hidden;
border-radius: 12px;
}
.card-img-wrap img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
</style>
</head>
<body>
<div class="card-img-wrap">
<img src="https://daniyaldev.com/wp-content/uploads/2026/01/social-share-scaled.png"
alt="Card thumbnail image"
width="1200"
height="630"
loading="lazy">
</div>
</body>
</html>
Centering an Image on the Page
Images are inline elements by default, so they sit in the flow of text. To center one on its own line, make it a block element and use auto margins:
<style>
.img-centered {
display: block;
margin: 0 auto;
max-width: 100%;
height: auto;
}
</style>
<img src="https://daniyaldev.com/wp-content/uploads/2026/01/social-share-scaled.png"
alt="Centered image"
class="img-centered"
width="800"
height="420">
If your image lives inside a flex or grid container, centering becomes even simpler: justify-content: center on the parent and you’re done.
08Accessibility and Images in HTML5: What You Must Know Now
Accessibility is a genuinely important part of working with images in HTML5, and the heart of it is one rule you can apply immediately: if the image carries meaning, describe it. If it’s purely decorative, use an empty alt.
<!-- This image teaches something: describe it clearly -->
<img src="error-chart.png"
alt="Line chart showing error rates spiking by 300% on Tuesday afternoon"
width="900"
height="450">
<!-- This image is decoration only: empty alt tells screen readers to skip it -->
<img src="decorative-swoosh.png" alt="" width="1200" height="80">
An empty alt="" is not a mistake. It’s intentional and correct. Screen readers encountering an empty alt attribute simply skip the image entirely. That’s exactly the right behavior for a decorative divider, an abstract background texture, or a visual flourish that doesn’t add information.
We’re covering alt text properly in the next article, including how to write great descriptions, how to handle complex images, and the full impact on both accessibility and SEO. If you want a preview of how semantic HTML and images connect, our semantic HTML guide touches on the <figure> and <figcaption> elements that pair with images beautifully.
09Common Mistakes When Using Images in HTML5
These come up constantly. Knowing them now means you won’t have to debug them later.
Leaving Out the alt Attribute Entirely
<!-- Wrong: no alt attribute -->
<img src="team-photo.jpg">
<!-- Right: descriptive alt for meaningful images -->
<img src="team-photo.jpg" alt="The DaniyalDev team at the 2025 company meetup" width="1200" height="800">
<!-- Right: empty alt for decorative images -->
<img src="bg-pattern.png" alt="" width="1440" height="200">
Using PNG for Full-Size Photographs
A high-resolution photo saved as PNG can easily be 4 to 8 MB. The same photo as an optimized WebP might be 200 to 400 KB. Both can look identical on screen. PNG is for graphics, logos, and images that need transparency. Not for photographs.
Forgetting width and height on Every Image
<!-- Wrong: no dimensions, causes layout shift -->
<img src="hero.webp" alt="Hero image">
<!-- Right: dimensions preserve space before the image loads -->
<img src="hero.webp" alt="Hero image" width="1400" height="700">
Uploading Massive Unoptimized Files
A 7MB uncompressed photo on a landing page actively hurts your page speed and your SEO. Aim for under 200KB for most images on the web. Hero images can go a bit higher, but 400KB is a reasonable upper limit in most cases. Compress everything before it goes live.
Using Local Absolute File Paths
<!-- Wrong: this path only works on your computer -->
<img src="C:\Users\YourName\Desktop\project\images\photo.jpg" alt="Photo">
<!-- Right: relative path works on any server -->
<img src="images/photo.jpg" alt="Photo">
Setting Both Dimensions Without object-fit
If you set a fixed width and height in CSS that don’t match the image’s natural aspect ratio, the image stretches and distorts. The fix is always object-fit: cover or object-fit: contain:
<style>
/* Wrong: will distort if aspect ratios don't match */
.wrong-img {
width: 300px;
height: 200px;
}
/* Right: object-fit handles the size difference gracefully */
.right-img {
width: 300px;
height: 200px;
object-fit: cover;
}
</style>
<img src="https://daniyaldev.com/wp-content/uploads/2026/01/social-share-scaled.png"
alt="Image with proper sizing"
class="right-img"
width="1200"
height="630">
10A Complete Real-World Example: Image Cards
Let’s put everything covered in this article on images in HTML5 together. Here’s a responsive image card grid you could drop into a real project today:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Cards</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: system-ui, sans-serif;
background: #0f172a;
color: #cbd5e1;
padding: 2rem;
}
h2 {
font-size: 1.5rem;
color: #ffffff;
margin-bottom: 1.5rem;
}
/* Responsive card grid */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
}
/* Individual card */
.card {
background: #1e293b;
border-radius: 16px;
overflow: hidden;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4);
}
/* Fixed-height image container: prevents layout shift,
keeps all cards uniform regardless of image proportions */
.card__img-slot {
width: 100%;
height: 200px;
overflow: hidden;
}
.card__img-slot img {
width: 100%;
height: 100%;
object-fit: cover; /* Fills slot without distortion */
display: block;
transition: transform 0.3s ease;
}
.card:hover .card__img-slot img {
transform: scale(1.05);
}
.card__body {
padding: 1.25rem;
}
.card__title {
font-size: 1rem;
font-weight: 700;
color: #ffffff;
margin-bottom: 0.4rem;
}
.card__text {
font-size: 0.83rem;
color: #64748b;
line-height: 1.55;
}
</style>
</head>
<body>
<h2>Latest Articles</h2>
<div class="card-grid">
<article class="card">
<div class="card__img-slot">
<!--
Every img tag here has:
- Descriptive alt text
- width and height (prevents layout shift)
- loading="lazy" (below the fold on many devices)
- decoding="async" (non-blocking decode)
-->
<img
src="https://daniyaldev.com/wp-content/uploads/2026/01/social-share-scaled.png"
alt="What is HTML5: beginner guide article preview"
width="1200"
height="630"
loading="lazy"
decoding="async"
>
</div>
<div class="card__body">
<h3 class="card__title">What Is HTML5?</h3>
<p class="card__text">A beginner-friendly guide to modern HTML5 and everything it brings to the table.</p>
</div>
</article>
<article class="card">
<div class="card__img-slot">
<img
src="https://daniyaldev.com/wp-content/uploads/2026/01/social-share-scaled.png"
alt="Semantic HTML tutorial article preview"
width="1200"
height="630"
loading="lazy"
decoding="async"
>
</div>
<div class="card__body">
<h3 class="card__title">Semantic HTML Explained</h3>
<p class="card__text">Write HTML that search engines and screen readers understand and love.</p>
</div>
</article>
<article class="card">
<div class="card__img-slot">
<img
src="https://daniyaldev.com/wp-content/uploads/2026/01/social-share-scaled.png"
alt="HTML document structure tutorial article preview"
width="1200"
height="630"
loading="lazy"
decoding="async"
>
</div>
<div class="card__body">
<h3 class="card__title">HTML Document Structure</h3>
<p class="card__text">Build the perfect HTML5 document structure from the ground up.</p>
</div>
</article>
</div>
</body>
</html>
Notice what’s happening in that example:
- Every
<img>has a descriptivealt, bothwidthandheight,loading="lazy", anddecoding="async". That’s the full set. object-fit: coverkeeps every card image uniform, regardless of what the original image proportions are.- The grid uses
auto-fillandminmax, which means it naturally collapses from three columns to two to one as the screen shrinks. No media query needed for the basic layout. - The image is inside a fixed-height wrapper with
overflow: hidden. That’s the cleanest pattern for card images you’ll find.
This is production-ready. You can use it today.
11Quick Reference: Images in HTML5
Every img tag attribute in HTML you’ll actually use, summarized in one place:
| Attribute | What it does | Example value | Use it? |
|---|---|---|---|
| src | Path to the image file | images/photo.webp | Always |
| alt | Text description (or empty for decorative images) | “Sunset over mountains” | Always |
| width | Display width in pixels (prevents layout shift) | 800 | Strongly recommended |
| height | Display height in pixels (prevents layout shift) | 600 | Strongly recommended |
| loading | Controls when the browser fetches the image | lazy | Recommended |
| decoding | Hints how the browser should decode the image | async | Optional (good habit) |
| title | Hover tooltip text for desktop users | “View full size” | Optional |
| crossorigin | CORS settings for cross-domain images | anonymous | When needed |
And for image formats, keep this mental shortcut handy:
- Photos and most images: WebP (JPEG as fallback for older browsers)
- Transparent backgrounds: WebP or PNG
- Critical hero images: AVIF (WebP fallback)
- Old project, every browser must work: JPEG or PNG
12You’re Ready to Use Images Properly
Your understanding of images in HTML5 is now genuinely solid. You know how the img tag works, what every attribute does and when to use it, which image format fits which situation, how to optimize file sizes, and how to display images correctly with CSS.
Most developers pick up the basics and stop there. You just went further.
The next articles in this series go even deeper: writing great alt text, serving responsive images with srcset, and using the <picture> element for format fallbacks and art direction. Each one builds directly on what you covered here.
The most useful thing you can do right now is open a project and put this into practice. Look at the images you’re already using and ask: right format? dimensions set? optimized? Those three questions alone will make a real, visible difference. Keep writing code.
Mastering Images in HTML5
Loading challenge…
Ready to Practice?
Select a difficulty level above to load your challenge.