DEV Community

FreeToolsY
FreeToolsY

Posted on

Cutting a 625KB homepage down to 477KB without changing a single pixel

Cutting a 625KB homepage down to 477KB without changing a single pixel

How I found 168 redundant internal links in our server-rendered HTML, moved the duplication to the client, and kept the animation identical.


Our tool site has 160 tools. The homepage lists them in four places: a hero marquee, a "popular tools" ticker, the category explorer, and the footer.

That's fine for a human. It is not fine for a crawler.

When I finally dumped the server-rendered HTML and counted, the numbers were embarrassing:

/tools/ links in <html>:   432
unique tools:              160
most repeated tool:        6 times
HTML size:                 625 KB
Enter fullscreen mode Exit fullscreen mode

Four sections × 160 tools should be ~264 links. We were serving 168 more than that.

Where the 168 came from

The hero marquee and the popular ticker are infinite scrollers. A CSS marquee needs the content duplicated so it can loop seamlessly — so the server was rendering every item twice:

// every column rendered twice, on the server
{[...column, ...column].map((tool) => (
  <li key={tool.slug}><Link href={toolPath(tool.slug)}>…</Link></li>
))}
Enter fullscreen mode Exit fullscreen mode

Hero: 320 links (160 real + 160 clones).
Ticker: 16 links (8 real + 8 clones).

The clones exist purely for the animation. A crawler doesn't care about the animation. It just sees a page that mentions the same 160 URLs four times over, with two of those mentions being noise.

So: render the real items on the server, add the clones in the browser.

Moving the clone to useEffect

const tickerRef = useRef<HTMLUListElement>(null);

useEffect(() => {
  const el = tickerRef.current;
  if (!el) return;

  const source = Array.from(el.children) as HTMLElement[];
  for (const li of source) {
    const clone = li.cloneNode(true) as HTMLElement;
    clone.setAttribute("aria-hidden", "true");
    clone.setAttribute("data-ticker-clone", "");
    clone.querySelectorAll("a").forEach((a) => a.setAttribute("tabindex", "-1"));
    el.appendChild(clone);
  }

  return () => {
    el.querySelectorAll("[data-ticker-clone]").forEach((n) => n.remove());
  };
}, []);
Enter fullscreen mode Exit fullscreen mode

And the render side becomes the obvious thing:

{items.map((tool) => (
  <li key={tool.slug}><Link href={toolPath(tool.slug)}>…</Link></li>
))}
Enter fullscreen mode Exit fullscreen mode

Server sends 8. Browser appends 8. Animation unchanged.

The part I got wrong first

My first version cloned the whole <ul> and inserted it as a sibling:

el.parentElement?.insertBefore(clone, el.nextSibling);  // ← wrong
Enter fullscreen mode Exit fullscreen mode

Which produced two separate scrollers side by side. The animation ran, but the layout was wrong — immediately visible, obviously broken. A screenshot check caught it in under a minute, but it's the kind of thing you don't notice if you only look at numbers.

The fix: clone the <li> elements into the same <ul>. Then translateX(-50%) on one element does what it was designed to do — it scrolls exactly one duplicated track.

const source = Array.from(el.children);
for (const li of source) el.appendChild(li.cloneNode(true));
Enter fullscreen mode Exit fullscreen mode

Two lessons, and they're the same lesson: verify with your eyes, and clone the innermost node rather than the container.

Accessibility, not just SEO

Cloning <li> elements duplicates real <a> tags into the tab order. Screen readers and keyboard users would hit the same tool twice.

Every clone gets:

clone.setAttribute("aria-hidden", "true");
clone.querySelectorAll("a").forEach((a) => a.setAttribute("tabindex", "-1"));
Enter fullscreen mode Exit fullscreen mode

Visually identical, semantically half the size.

The result

                    before      after
HTML size           625 KB    477 KB     (-24%)
/tools/ links         432       264     (-39%)
most repeated          6x        4x
unique tools          160       160     (unchanged)
Enter fullscreen mode Exit fullscreen mode

Every unique tool is still linked from the homepage. Nothing became unreachable. The only links that disappeared are the ones that were never meant to exist for a reader.

What I deliberately did not remove

A crawler seeing the same URL in the hero, in the explorer, and in the footer is not a problem — those are genuine, useful internal links. Internal linking from a category page to its tools is one of the cheapest SEO wins there is.

The rule I used:

Remove duplication that exists for an animation. Keep duplication that exists for navigation.

That's the whole decision. The audit took about twenty minutes; the change was under thirty lines across two components.

One small thing I'd do differently

I'd write the "is this a real link or a clone?" audit as a permanent test instead of a one-off grep:

// expect: link count == sum of real sections, and clone markers == 0 in SSR output
it("sends no animation clones to the server", async () => {
  const html = await render(<HomePage />);
  expect(html).not.toContain("data-ticker-clone");
});
Enter fullscreen mode Exit fullscreen mode

We shipped the fix without that test. It'll work fine until someone refactors the marquee and quietly reintroduces it.


The site is freetoolsy.com — 160 browser-based tools, 159 of which never touch a server.

If you run a content-heavy homepage and have done something similar, I'm curious what number you started from.

Top comments (0)