Almost every win came from something nobody had designed on purpose, and the design survived every one of them. These are the lessons in the order I learned them.
I came into this expecting performance work to be a series of small sacrifices — lose an animation here, drop an image there. It has mostly been the opposite. Almost every real win came from something nobody had designed on purpose.
01
A budget is a decision made in advance
A performance budget is not a score to chase. It is a number agreed before the work starts, so that the conversation about whether to add something happens while it is still a question.
Without one, every individual addition is reasonable. One more font weight is reasonable. One more analytics script is reasonable. A chat widget is reasonable. Nobody ever adds the thing that breaks the page; the page is broken by nine reasonable additions and no agreed limit.
The budget's real function is procedural. It turns "should we add this" from a matter of taste into a matter of arithmetic, which is a much shorter conversation.
02
The biggest win is almost never the design
The first time I was asked to make a page faster I went looking at the animations, because those were the visible, expensive-feeling things. They were not the problem. The problem was a video that downloaded on every visit before anybody had scrolled, an image served at four times the size it was drawn at, and a third-party script loaded in the root layout for a widget that appeared on one page.
That pattern has repeated on every project since. The expensive things are rarely the ones that look expensive. They are the ones nobody chose — a default, an import that pulled a library in, a component re-exported from a shared file.
Which means the honest order of work is: measure, find the thing nobody decided, fix that. Only if the budget still cannot be met is there a design conversation, and that conversation belongs to the designer, not to me.
Nobody ever adds the thing that breaks the page. The page is broken by nine reasonable additions and no agreed limit.
05
The one image that matters, and all the others
The largest thing on screen when the page first paints is a single element, usually an image, and it gets different treatment from everything else: a high priority, a correct size hint, no lazy loading.
Everything below the fold gets the opposite. Lazy, no priority, and a size hint that reflects the width it is genuinely drawn at rather than the width of the file. A hero image sized for a desktop header, served to a phone at the same dimensions, is the single most common waste I have found in an existing codebase — and it is invisible, because the page looks correct.
The other half is format. Modern formats are meaningfully smaller at the same visual quality, and a framework image component will serve them and fall back automatically. Doing that is free. Not doing it is a choice to send more bytes for the same picture.
06
Animate two properties and nothing else
Transform and opacity are composited. Width, height, top, left, and most filters are not — changing them forces the browser to recalculate layout, and doing that inside a scroll handler produces exactly the stutter the animation was supposed to avoid.
The same applies to reading layout. Asking an element for its position or size inside a scroll or resize handler forces a synchronous layout calculation, and doing it on every event rather than once per frame is how a smooth design ends up feeling cheap on a mid-range phone.
The fix is unglamorous: batch the reads into one animation frame, write only transforms and opacity, and let the compositor do its job. The animation looks the same. It just stops costing anything.
07
Third-party scripts are somebody else's budget
Every embed, widget, tag manager and chat bubble is code you did not write, loaded at a time you did not choose, in a size that can change without warning. Mounting one in the root layout means every route pays for it, including the routes it is irrelevant to.
Mount it on the page that needs it. Load it after the page is interactive at the earliest. Where it can wait for a click or for the section to scroll into view, make it wait — a booking widget that loads when somebody scrolls to the booking section is indistinguishable, from the user's side, from one that loaded at the start.
And check the size again after a few months. It will have grown.
08
Measure the same way every time
The last lesson is about honesty. Numbers from a desktop machine on fast broadband are not the numbers your visitors get, and a single run is noise. We measure on the mobile preset, more than once, and report what came back rather than the best of five.
A performance claim without a number attached is not a claim. It is a feeling about a page, and feelings about pages are the reason the original problem existed.
If you take one thing
Agree the number before the work starts, then spend the effort on the things nobody designed. The animation is almost never what is costing you the second you are trying to find.

