Size (still) Matters on the Web
The size of web applications remains a critical factor affecting user experience, performance, SEO, and business success. Developers must carefully consider application size to ensure optimal performance and user satisfaction.
I still believe that size matters on the web. Large images and JavaScript bundles can delay the moment an application becomes useful, especially on a slow or unreliable connection. They also increase network traffic, which can affect hosting costs. On IoT devices, limited storage and processing capacity make every asset count.
A smaller download does not automatically make an interface easier to use, but it can help users reach that interface sooner. That has mattered since the early days of the web.
From the 1990s to 2025: A Size Comparison
In the 1990s, network capacity was limited. Users connected through leased lines (1-44 Mbps) and dial-up modems (2.4-56 Kbps), so even modest downloads could take time.
Access speeds are much higher today, but applications and user expectations have grown as well. Size still matters, although the resources we download and the performance we measure have changed.
Web Traffic in the 1990s
- Email: about 20 KB for text-only messages
- Web page: about 14 KB with basic styling
- Image: about 30 KB, which was exceptional
Users expected transfers to take time. A page might require several network round trips, and DNS lookups added latency.
Web Page Weight in 2025
The 2025 Web Almanac’s HTTP Archive data reports median home-page weights of 2.56 MB on mobile and 2.86 MB on desktop. For mobile home pages, the median sizes of individual resource types included:
- HTML: 22 KB
- CSS: 77 KB
- Fonts: 122 KB
- JavaScript: 632 KB
- Images: 911 KB
These are medians measured separately for each resource type, so they do not add up to the median total page weight.
Page loading can also involve secure connection setup and DNS lookups. Techniques such as caching, HTTP/3, and content delivery networks can reduce some of this overhead.
Performance Metrics
Download size is only one part of perceived performance. Rendering and JavaScript execution also affect how quickly a page feels ready. Commonly used metrics include:
- First Contentful Paint (FCP): 1.8 seconds
- Largest Contentful Paint (LCP): 2.5 seconds
- Time to Interactive (TTI): 3.5 seconds
I pay particular attention to size when users may have a low-bandwidth connection, when network traffic affects hosting costs, or when an application runs on a device with limited storage.
Separate Static Assets from Application Data
In early web applications, each page request often transferred both the content and the formatting markup generated by the framework. AJAX later made it easier to request data separately from the page.
Today, I prefer to keep static assets and application data distinct. HTML, CSS, JavaScript, and images can be optimized before deployment. A RESTful service can return the JSON data needed by the application. The browser can cache static assets and request additional data as the user interacts with the page. This approach also applies to mobile applications that use web technologies.
Using Web Technologies in Limited Environments
In my work with devices that provide a web server and RESTful services, I have to account for limited disk space, memory, and network capacity. Users still expect a modern, responsive interface, so I try to deliver only the assets and functionality that interface needs. A few small assets can be more reliable to serve than one large bundle, and they avoid sending unused features.
Prefer Native Browser Features
I check regularly whether browser features can replace code or libraries we
added in the past. For example, CSS @starting-style can define the starting
style for an element entering a transition, avoiding a JavaScript
requestAnimationFrame() callback for that purpose.
When a built-in HTML control meets the need, I prefer it to a custom component.
An <input type="date"> can replace a date picker built from substantial
amounts of HTML, CSS, and JavaScript. Native popover and dialog features can
also replace libraries used only for those behaviors. Their appearance may vary
between browsers, but that can be a worthwhile tradeoff when download size is
important.
Bundle Only What You Use
Frameworks do not always make it easy to create a bundle containing only the features an application needs. Tree shaking can remove unused code, but dynamic web components may not be visible from a static HTML entry point. In that case, an explicit list of required components can be more reliable. The SFC project includes a bundler that selects only the components an application needs.
I apply the same judgment to libraries. A reactive programming library can be
useful when an application needs its operators and stream features. For a
narrowly scoped data model, a simple subscription API such as
model.subscribe("/animals/*", callback) may be enough. Building a small
implementation can also help me understand how the behavior works. I measure
the production bundle and choose the simplest solution that meets the need.
I also use SVG when it can replace a pixel-based image, and minification tools to remove unnecessary whitespace and shorten internal identifiers. A usable interface can often be built with native HTML, CSS, and JavaScript and less code than a more elaborate solution would require. I aim for a practical balance between the interface users need and the code it takes to deliver it.
Use the Browser’s Processing Power
Client-side processors are powerful, while server-side processing consumes resources and may be especially constrained on IoT devices. When a task can reasonably run on either side, I consider doing it in the browser. I also weigh the user’s device, privacy, and the amount of data that must be transferred; not every task belongs on the client.
For example, a server can return data in a format that is easy to produce, such as JSON, and let the browser transform it for the interface. This keeps the server logic focused and lets the client prepare the data needed for the current interaction.
Using Web Technologies in Limited Environments
When working with devices that expose a web server and RESTful services, the size of network packages is mission-critical. These are some practical lessons from building interfaces for constrained devices.
IoT devices often have very limited disk space, so hosting a large web framework may not be an option. At the same time, users still expect a modern, responsive interface. Unlike a full-featured web server, a small device may not be able to serve a large bundle reliably. Sending a few small assets can be more robust, and avoids downloading functionality the interface does not use.
Prefer Native Browser Features
Features built into modern browsers usually provide useful functionality without
the download cost of an extra library. It is worth revisiting older code
regularly to see whether newer browser capabilities can replace it. For example,
CSS @starting-style can define the initial style for an element entering a
transition, avoiding JavaScript callbacks such as requestAnimationFrame() for
that purpose.
Prefer built-in HTML controls when they meet the need. An <input type="date">
can replace a custom date picker made from a large amount of HTML, CSS, and
JavaScript. Likewise, native popover and dialog features can replace a
library used only to provide those behaviors. The browser’s appearance may vary,
but the tradeoff can be worthwhile on a device where every downloaded byte
matters.
Small, tailored bundles are not always easy to get from a framework. Some frameworks use tree shaking to remove unused code, but dynamically created web components may not be visible from a static HTML entry point. In that case, an explicit allow-list of required components is more reliable. The SFC project, for example, includes a bundler that selects only the components an application needs.
The same principle applies to libraries. A complete reactive programming
library can be useful when an application needs its full set of operators and
stream behavior. For a small, specific data model, a simple subscription API
such as model.subscribe("/animals/*", callback) may be enough. Implementing a
small piece yourself can also make its behavior easier to understand. Choose
based on the required behavior, and measure the production bundle rather than
including a library by default.
Use vector graphics such as SVG when they can replace pixel-based images, and run minification tools to remove whitespace and shorten internal identifiers. Often native HTML, CSS, and JavaScript provide a sufficiently usable interface with much less code. The goal is a sensible balance between the interface users need and the code required to deliver it.
Use the Power of Browser Devices
Client-side processors are powerful, while server-side processing consumes resources and can be especially limited on IoT devices. When an operation can reasonably be performed on either side, prefer doing it in the browser. This does not mean moving every task to the client: consider the user’s device, privacy, and the amount of data that would need to be transferred.
Servers can return data in a simple format that is easy to produce, such as JSON, and let the browser transform it for the interface. This keeps server work and device-side code focused, and lets the client prepare only the data needed for the current interaction.
Conclusion
I treat size optimization as part of development, not as a final cleanup task. My checklist is straightforward:
- Measure application size regularly in the CI/CD pipeline.
- Optimize images and bundles during development.
- Prefer native browser features when they meet the requirement.
- Check the production output before deployment.
See Also
- https://dev.to/relative-ci/why-web-application-size-matters-51bc
- https://almanac.httparchive.org/en/2022/page-weight
- https://github.com/mathertel/sfc