Vocabulary for this course

The terms the chapters assume, in plain words. You can open this from any chapter.

accessible name
What a browser tells a screen reader an element is called, taken from its text, its label, or an alternative description.
aria-label
An attribute that gives a control an accessible name when no visible text can serve as one.
attribute
A name, sometimes with a value, inside an opening tag that describes the element further, such as where a link goes.
control
An interactive part of a page, such as a text box, checkbox, or button, that a person can operate.
element
One complete piece of a page: an opening tag, its content, and a closing tag, or a single tag when it holds nothing.
empty element
A tag that holds nothing and has no closing partner, such as an image or a line break.
for attribute
An attribute on a label that names the control it describes, so clicking the text operates that control.
form action
The address a submitted form sends its values to, declared in the opening tag of the form.
id attribute
An attribute that gives one element a unique name, which a link or a label can point to.
label
The text attached to a control that says what it is for; clicking it focuses or operates the control it belongs to.
landmark
A page region with a recognised purpose, such as header, nav, or main, that a screen reader can jump to directly.
markup
The tags and attributes that describe the structure of a document, as opposed to its styling or behaviour.
method
The attribute that says whether a form's values travel in the address or in the request body.
name attribute
An attribute that gives a form control a key for its value when the form is submitted.
regular expression
A pattern of characters used to test or match text, such as the shape an email address must have.
request body
The part of a form submission that carries the field values, separate from the address.
reset button
A button that puts every control in a form back to the value it had when the page loaded.
sandbox
An isolated place where a page runs without reaching the rest of the site or the network.
screen reader
Software that speaks a page aloud or shows it in braille, so someone who cannot see the display can still use it.
tag
The name of an element written in angle brackets, such as p or img, which marks where that piece of the page begins or ends.

HTML from the ground up

Responsive images and performance

Images are most of a page’s weight. Learn to reserve their space, load them at the right time, and serve the size that fits.

Part 9 of 13

Intermediate15 min readBack to Courses

Weight is the experience

On a typical page, images are the heaviest thing you ship — often more than all the code together. On a phone in a lift, the difference between a page that arrives and a page that does not is usually pictures. Three habits decide most of it: reserve the space, load what is needed, and send a file that fits the screen.

Reserve the space before the image arrives

Give every <img> its own width and height attributes, in pixels, matching the file. The browser reads them before the file downloads, works out the shape, and leaves exactly that much room on the page.

Without them the page does not know how tall the image will be, so it lays out the text and then shoves everything down when the image lands. That jump is why you tap a link and end up somewhere else — the page moved under your thumb while it was loading.

An image that holds its place

<img src="./starter.jpg"
     alt="A jar of bubbling sourdough starter"
     width="800" height="600">

What each piece does

  • width and height — the file’s real pixel size. The browser reads them before the file downloads, derives the aspect ratio from the pair, and reserves exactly that much room.
  • Both are needed for the arithmetic: one alone describes a length, and the two together describe the shape the space must hold.

Load offscreen images later

By default the browser downloads every image on the page immediately, even the ones far below the fold. loading="lazy" changes that: the image is fetched shortly before it scrolls into view, and not before. A gallery with twelve large photographs then loads two or three instead of twelve.

The exception is worth remembering: never mark the image at the top of the page lazy. It is on screen immediately, and delaying it is the opposite of what lazy is for — that image is what the visitor is waiting to see.

A gallery that holds still

The three photographs below have no dimensions, so the page jumps when they load. Give each image its width and height, and load the two below the fold lazily.

Live Preview
Console output will appear here...

1 left to do

  • The images declare their width
  • The images declare their height
  • The offscreen images load lazily

width and height go on the <img> in pixels — the shape matters more than the exact numbers. loading="lazy" is the third attribute.

Serve the size that fits

An image shown 400 pixels wide does not need to be a 2000-pixel file. Below is the pattern that lets the browser choose between files you offer, using the same <picture> idea from the media chapter — here as srcset and sizes on the image itself.

The browser chooses from what you offer

srcset is a menu, not a command. Each candidate carries a descriptor — 400w says how wide the file is, 2x says it is for a screen with twice the pixel density — and sizes tells the browser how much space the image will occupy at each viewport width. With both, it can pick the smallest file that still looks right.

Without sizes, the browser assumes the image fills the viewport, which is often wrong and can make it download a larger file than the layout needs. The src attribute stays as the fallback for a browser that understands none of it, and it should name a real file.

One image, three files, one rule

<img src="./starter-800.jpg"
     srcset="./starter-400.jpg 400w,
             ./starter-800.jpg 800w,
             ./starter-1600.jpg 1600w"
     sizes="(max-width: 600px) 100vw, 600px"
     alt="A jar of bubbling sourdough starter"
     width="800" height="600"
     loading="lazy">

The first screen is the page

Some images are the reason the visitor came; others are further down and can wait. fetchpriority="high" on the one at the top tells the browser to spend its early bandwidth there, while loading="lazy" on the rest keeps them out of the first load. The two attributes are not opposites — they are a ranking.

decoding="async" lets the browser decode an image off the main thread, which keeps text and controls responsive while a large picture is prepared. It is a hint rather than a guarantee, but it costs nothing on an image that is not needed for the first paint.

What the Network panel shows

The Network panel is the honest version of this chapter. Reload with it open and sort by size: the largest row is usually a photograph, and its transferred size is what the reader waited for. Compare the file you offered with the size the layout actually needs — a 2000-pixel photograph shown at 400 pixels is five times the width and roughly twenty-five times the pixels it can display. Then check the timing column: an image that starts late is a lazy image doing its job, or a hero that should have been first. Numbers from the panel beat any guess about which file is heavy.

Three performance mistakes: swapping width and height, which reserves the wrong shape and makes the jump worse; marking the hero image loading="lazy", which delays the one thing the visitor is waiting for; and offering a srcset with no sizes, which leaves the browser guessing how wide the image will be. Check the Network panel, not the intention.

Try these next

  • Give one image three srcset candidates and a sizes rule for phone and desktop.
  • Mark the first image fetchpriority="high" and the rest lazy, then reload with the Network panel open.
  • Add decoding="async" to a below-the-fold image and compare when the text appears.

A hero that loads first

The portrait at the top is what the page is for; the two supporting shots can wait. Give every image its width and height, load the lower two lazily, and mark the portrait high priority and decode it in the background.

Live Preview
Console output will appear here...

1 left to do

  • The images declare their width
  • The images declare their height
  • The supporting images load lazily

Add width and height to each <img>, loading="lazy" to the lower two, and fetchpriority="high" plus decoding="async" to the portrait.

Open the browser’s Network panel and reload. Sorting by size shows exactly which file is slowing the page down — it is almost always an image.

Check what you learned

One question at a time. A wrong answer explains itself — take another go.

Part 1 of 5

What do width and height on an <img> actually do?