Skip to content
SnapFrom

Not All Bytes Cost the Same

· · 4 min read

Page weight is the most quoted number in web performance and the least informative. It is a sum, and the things being summed are not comparable.

The median mobile page is 2,311 KB, and the median desktop page is 2,652 KB[3]. Those numbers get repeated constantly. What almost never gets said alongside them is that the same figure can describe two pages with completely different behaviour, because the mix matters far more than the total.

The composition, at the median

The Web Almanac breaks the median page down by type. On desktop: 1,054 KB of images, 613 KB of JavaScript, 131 KB of fonts, 78 KB of CSS, 18 KB of HTML. On mobile: 900 KB of images, 558 KB of JavaScript, 111 KB of fonts, 73 KB of CSS, and the same 18 KB of HTML[3].

By weight, images win. By cost, they do not, and the reason is in what the browser has to do with each kind of byte.

What the browser owes each type

MDN states the requirement flatly: “before anything is rendered to the screen, the HTML, CSS, and JavaScript have to be parsed”[1]. Images are conspicuously absent from that list. An image is decoded and drawn, and until it arrives the space it occupies is simply empty. The page around it works.

JavaScript is a different transaction. Script elements, “particularly those without an async or defer attribute - block rendering, and pause the parsing of HTML”[1]. The browser stops building the document, because a script it has not read yet might change the document.

Then it has to actually do something with the bytes: JavaScript “is parsed, compiled, and interpreted”[1]. That is three passes over the file before a single line of it has had any effect, and all of it happens on the one thread that also handles the interface.

MDN names the consequence and puts a number on it: if the main thread “is occupied parsing, compiling, and executing JavaScript, it is not available and therefore not able to respond to user interactions in a timely (less than 50ms) fashion”[1].

That is the asymmetry. A slow image makes the page look unfinished. A large script makes the page unresponsive, which is a different and worse failure, because the page looks ready and then ignores you.

CSS sits in between, and it is not where people think

There is a persistent belief that CSS is the render-blocking villain. MDN’s description is more specific: waiting to obtain CSS “doesn’t block HTML parsing or downloading, but it does block JavaScript because JavaScript is often used to query CSS properties’ impact on elements”[1].

So the stylesheet does not hold up the document. It holds up the scripts, because a script may ask what an element’s computed style is and the browser cannot answer until the CSSOM exists.

At 78 KB desktop and 73 KB mobile[3], CSS is also about a twelfth of the weight of the JavaScript sitting next to it. It is rarely the thing worth cutting first.

Half of it is never used

The number that should end the page-weight conversation is this one. The median mobile page ships 558 KB of JavaScript, up 14% in a year, and 613 KB on desktop[2]. Of that, “approximately half the bytes downloaded being unused during page load (206 kilobytes - or 44% of bytes delivered - at the median on mobile)”[2].

Not unused as in “not needed at all”. Unused as in: downloaded, parsed, compiled, and never executed during the load it was blocking.

That is 206 KB per page at the median doing the expensive kind of nothing. The equivalent waste in an image would be an image nobody scrolls to, which costs bandwidth and no main-thread time at all.

What this costs you, and what to do with it

A weight budget in kilobytes is the wrong instrument. Two pages at 2.3 MB, one of them 1.8 MB images and one of them 1.2 MB JavaScript, are not the same page, and no total will tell them apart.

The cheapest real win is usually not compression. Shaving 20% off 558 KB of JavaScript still leaves every remaining byte to be parsed and compiled on the main thread. Removing a script that was never executed removes the whole cost, including the three passes.

async and defer are load-bearing, not decorative. They are the specific attributes MDN names as the difference between a script that pauses HTML parsing and one that does not[1].

If you want one question to ask about a page, it is not “how many kilobytes”. It is “how many of these kilobytes have to run before anything works, and how many of those actually ran”.

Sources

  1. Populating the page: how browsers work - MDN Web Docs, Mozilla, accessed

    Supports: 'Before anything is rendered to the screen, the HTML, CSS, and JavaScript have to be parsed.' Script elements 'particularly those without an async or defer attribute - block rendering, and pause the parsing of HTML'. Waiting to obtain CSS 'doesn't block HTML parsing or downloading, but it does block JavaScript because JavaScript is often used to query CSS properties' impact on elements'. JavaScript 'is parsed, compiled, and interpreted', and if the main thread 'is occupied parsing, compiling, and executing JavaScript, it is not available and therefore not able to respond to user interactions in a timely (less than 50ms) fashion'.

  2. JavaScript - HTTP Archive, Web Almanac 2024, accessed

    Supports: 'In 2024, this upward trend resumed, with the median JavaScript payload rising by 14%, reaching 558 kilobytes on mobile and 613 kilobytes on desktop.' The chapter records 'approximately half the bytes downloaded being unused during page load (206 kilobytes - or 44% of bytes delivered - at the median on mobile)'.

  3. Page Weight - HTTP Archive, Web Almanac 2024, accessed

    Supports: 'The median page weight for a desktop page, as measured in October 2024 is 2,652 KB' and 'for mobile it's a slightly lower, but still weighty 2,311 KB'. By resource type at the median, a desktop page using images requests 1,054 KB of images against 900 KB on mobile, JavaScript is 613 KB desktop and 558 KB mobile, CSS is 78 KB and 73 KB, fonts are 131 KB and 111 KB, and HTML is 18 KB on both.