WebTech1223411 logo WebTech1223411Web tech, read closely
Front-End

Responsive Images and the Sizes Attribute Most Sites Skip

I audited a product landing page last month where the hero image weighed 1.9 MB on a phone. The developers had done the "right" thing: they added srcset with five widths from 400 to 2400 pixels.

A browser DevTools network panel listing image files of different widths beside a phone layout

I audited a product landing page last month where the hero image weighed 1.9 MB on a phone. The developers had done the "right" thing: they added srcset with five widths from 400 to 2400 pixels. The browser still downloaded the 2400 pixel file on a 390 pixel wide screen, every single time.

The cause was one missing attribute. Responsive images on the web depend on two attributes working together, srcset and sizes, and most teams only write the first. This article explains how the browser actually picks a file, why the sizes attribute matters more than people think, and how to check in a few minutes if your images are doing what you intended.

How Browsers Choose a Responsive Image

When the browser meets an img element with a srcset list of widths, it needs two facts before it can choose a file: how wide the image will be displayed, and the device pixel ratio of the screen. The pixel ratio it knows. The display width it does not, at least not early enough.

Image requests start while the HTML is still being parsed, often before the CSS has loaded. At that moment the browser has no layout, so it cannot measure your image. The sizes attribute is how you tell it in advance. Without sizes, the browser assumes the image will be as wide as the whole viewport, which is the default value of 100vw.

Then it multiplies. A phone 390 CSS pixels wide with a pixel ratio of 3 asks for roughly 1170 pixels. If your largest candidate is 2400 and the next one down is 1200, it picks 1200. That alone is often bigger than needed when the image only fills half the screen.

Writing a sizes Attribute That Matches Your Layout

The sizes attribute is a list of media conditions paired with widths, read from left to right. The browser uses the first condition that matches. A typical value for a card grid reads like this in plain words: "on screens at least 1024 pixels wide, the image is 33vw; on screens at least 640 pixels wide, it is 50vw; otherwise it is 100vw minus 32 pixels of padding."

To write it, open the page and note the image's rendered width at each of your layout breakpoints. You do not need pixel precision. Getting within 10 to 15 percent is enough, because the browser rounds up to the next candidate anyway.

LayoutRendered widthsizes entry
Phone, single columnFull width minus paddingcalc(100vw minus 32px)
Tablet, two columnsAbout half the screen50vw
Desktop, three columns in a 1200px containerAbout 380px380px

Notice the last row uses a fixed pixel width. Once the container stops growing, the image stops growing too, so a vw value would overestimate it on very large monitors.

Picking the Widths in srcset

More candidates is not automatically better. Each width is a separate file to generate, store and cache. For most layouts, four or five widths cover everything:

  • A small file around 400 pixels for low density phones and thumbnails.
  • A middle file around 800 pixels, the workhorse for most phones at 2x.
  • A large file around 1200 pixels for 3x phones and tablets.
  • One or two wider files, 1600 and 2000, only if the image can be displayed full width on desktop.

Steps of roughly 400 pixels keep the wasted bytes small. A practical rule: if two neighbouring files differ by less than 20 percent in size on disk, drop one of them.

The "Always Serve Retina Images" Habit Costs More Than It Gives

A lot of front end advice says to always serve images at the full device pixel ratio so they look crisp on high density screens. On a 3x phone, that means three times the width and roughly nine times the pixels. I think this is usually a bad trade.

Most people cannot tell the difference between a photo served at 2x and one at 3x on a phone held at normal distance. The byte difference is not subtle at all. On the landing page from the introduction, capping photographs at 2x density cut the hero image from 410 KB to 190 KB with no visible change in a side by side test with five colleagues.

Browsers are allowed to pick a smaller candidate than the exact match, and some do on slow connections, but you cannot rely on that. Capping the largest file you offer is the dependable way to control it. Line art, logos and text in images are the exception. Those show blur quickly, and they are usually better as SVG anyway.

When to Use the picture Element Instead

srcset with sizes handles one job: the same image at different resolutions. It is the right tool roughly nine times out of ten. Reach for the picture element only in two cases.

Art direction

When the crop needs to change, such as a wide landscape banner on desktop that becomes a tight portrait crop on phones, picture with media conditions lets you swap entirely different images.

Format fallbacks

When you want to offer AVIF or WebP with a JPEG fallback, picture with type attributes lets each browser take the best format it supports. Browser support for modern formats is now broad, so many teams serve WebP alone, but older Safari versions still benefit from a fallback.

Checking Your Images in DevTools

You do not need a performance tool to verify this. Open the page in a desktop browser, then:

  1. Turn on device emulation and pick a phone with a pixel ratio of 2 or 3.
  2. Open the Network panel, filter by images and enable "Disable cache" so you see fresh requests. Our piece on how browser caching decides what reloads explains why a cached file can hide the problem.
  3. Reload and look at which file names were downloaded for each image.
  4. In the Elements panel, select the image and check the currentSrc property in the properties view. It shows which candidate the browser chose.

If the chosen file is more than about 1.5 times the rendered width times the pixel ratio, your sizes value is too generous. The Network panel has more useful views like this, covered in our guide to DevTools features developers never open.

FAQ

Do I still need width and height attributes with srcset?

Yes. They let the browser reserve space before the image loads, which prevents layout shift. Use the intrinsic dimensions of any candidate, since only the ratio matters.

Does lazy loading change how srcset works?

No. Lazy loading only delays when the request starts. The browser still uses sizes and the pixel ratio to pick a candidate once the image approaches the viewport.

Can I set sizes to auto?

For lazy loaded images, recent Chromium browsers accept sizes="auto" and measure the real layout width. Other browsers ignore it, so keep a normal value after auto as a fallback.

The Practical Takeaway

Pick your three heaviest images, add a sizes attribute that matches their real layout widths, cap photographs at 2x density and confirm the chosen file with currentSrc in DevTools. That small pass usually cuts image weight on phones by a third or more. Find more layout and CSS guides in our front end section.

LV
Lorenzo Vidal

Lorenzo started as a visual designer and moved into CSS after watching too many of his layouts fall apart on phones. He writes about front-end craft, interfaces and accessibility, and still tests everything with the keyboard first.

More posts by Lorenzo

More in Front-End

01doorganico 084goad 3hot8 4465456 after5internprogram ahandfulofblessings ahmadpc ahomcybersecurity allodialresources annodex antiquesandperiodcollectibles aotc asianworldkashmir beedlectrics bloggertemplatefree bluefeatheragency bodyweightsolution campaign08blog carfixadvisor catstreetcollective cbstvsports cnfanspurchasing committeeof500yearsofdignityandresistance covertopsdjs cs-kaiyuangame cuestacomunicaciontotal cxoutlet dancebetgame deskgearhub destinyvillastay detectmagazine di33 diamondsteelbuildings donmo dyanadropship emarsysfinance emimattl escapechan eskitarih evautoplay everythingweddings-orlando farmzone feedviewerapp foxstudiosscratch gamevui123 gleasongrade greetingsday hacklabasu haskell iw-kaiyun jagoanproperti jilidskripsi joltbusinessfinance juegodepokergratis juegospucca kaeru-festival latestmehndidesigns lestanzediottaviano litemagazines localcommunityhero lustrsazan mariashebets menswheels newwebstechs1 nikkit ootheday oxigenvpn plurfitness prefetial probudgetcarpetcleaning psychicmrsmartin pyaten qvantor rejoignezlogis rexzbot riselayouts ruchin rwxqsgd5 sakaltime shibiaowang shop-bot skrtips strcoding tetapatrium topselller uneplanteartificielle vipertechcr wo-kygaming yamaha-mekar yeknava yoybuysheets zenunwa yamaha-mekar jilidskripsi ankertoto ankertoto ankertoto ankertoto