Our homepage looked light: a headline, two product cards, some cartoon trolls. But it was shipping 312KB of JavaScript, and the very first thing that JavaScript did was reveal the page. Until it loaded, parsed, and ran, the headline sat in the HTML at opacity: 0. Twenty-three elements, including the biggest one on the screen, were invisible by default.

Turn off JavaScript and our homepage was a beige void with a navigation bar. On a slow connection it was that same void, just temporarily. We had built a fast static site and then hidden it behind the slowest thing on the page.

How sites end up like this

An animation library made it easy to add entrance effects. The elements started at opacity zero, twenty pixels below their final position. The animation ran in JavaScript, so the starting state shipped in the HTML and the finished state only existed after hydration. As we copied the pattern into each section, more of the page depended on JavaScript just to become visible.

The headline was the largest content element on the page, so hiding it also delayed Largest Contentful Paint. Crawlers that don’t run scripts couldn’t see it, and readers on slow connections had to wait for the bundle before they could read it.

Moving the animations to CSS

We rebuilt the homepage with its content visible in the HTML by default. Animations could run when supported, and the page stayed readable without them.

In that rebuild, the hero’s staggered entrance used pure CSS: a keyframe and four animation delays. About twenty lines of inline script and an IntersectionObserver drove the scroll reveals further down the page. The “hidden” starting states only applied after an inline script flagged that JavaScript was running. Crawlers and readers with scripts disabled could read the complete page, and readers who preferred reduced motion skipped the animations. The little Gantt chart still drew its bars when it scrolled into view, and the trolls still wiggled when poked. The contact form posted as a plain HTML form, with an enhanced interaction when JavaScript was available.

The rebuild removed the 312KB client-side bundle. At that point, the homepage no longer needed the animation library or UI framework; its remaining JavaScript consisted of small inline scripts for those interactions.

What we gave up

The CSS animations were simpler than the physics-based ones the library offered: an ease-out curve instead of a spring. We looked at the two side by side and preferred the smaller page. If a future feature needs client-side state, we can add JavaScript for that feature.

Why a small studio bothers

This is the same argument we make in defense of small software, applied to our own homepage. People visit to find out what we make and whether it’s useful to them. They should be able to read that as soon as the HTML arrives.