HTML Images & Visual Content Mastering Images in HTML5

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:

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:

Since 1992

JPEG

The timeless classic for photos

Best for:
Photos with lots of color and detail
Compression:
Lossy
Transparency:
No
Support:
Universal (every browser)
File size: Medium
Lossless

PNG

When transparency is non-negotiable

Best for:
Logos, icons, graphics with transparency
Compression:
Lossless
Transparency:
Yes (alpha channel)
Support:
Universal (every browser)
File size: Large
Recommended

WebP

The modern standard for the web

Best for:
Almost everything: photos, graphics, transparency
Compression:
Lossy and lossless
Transparency:
Yes
Support:
All modern browsers
File size: Small (25-35% smaller than JPEG)
Future-Ready

AVIF

The best compression available today

Best for:
High-quality photos where file size is critical
Compression:
Lossy and lossless
Transparency:
Yes
Support:
Very good and growing fast
File size: Very small (up to 50% smaller than JPEG)

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:

Format Decision Guide
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:

Interactive Demo: object-fit values




object-fit interactive demonstration
object-fit: cover
Fills the container completely. If the image and container have different aspect ratios, the image gets cropped. The most popular choice for thumbnails, cards, and image grids.

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 descriptive alt, both width and height, loading="lazy", and decoding="async". That’s the full set.
  • object-fit: cover keeps every card image uniform, regardless of what the original image proportions are.
  • The grid uses auto-fill and minmax, 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:

img Tag Attributes: Quick Reference
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

Choose a difficulty to load your challenge

Loading challenge…

Ready to Practice?

Select a difficulty level above to load your challenge.

Easy

1
Live Preview
Great Work!