LayerPort

Guide · Deep dive

Why copied websites break offline.

The symptom is always the same -- images gone, fonts fallen back to Arial, a hero that never appears -- and the cause is always the same too: something in the copy still points at the origin. Here is where those references hide, how to find them, and what a capture has to rewrite.

In brief

  1. The dependency you cannot see

    An absolute URL to the origin works while you are online, which is why a bad copy looks fine on the day you make it.

  2. Seven places references hide

    HTML attributes, srcset, CSS url(), JavaScript strings, JSON, SVG href and the web manifest. Fix the HTML alone and the page still leaks.

  3. file:// makes it worse

    Modules and fonts are blocked from file:// by CORS, so a copy can look broken for a reason that has nothing to do with the copy. Always test over a local server.

  4. A service worker can hide the break

    A cached worker keeps serving the old assets for a while. Test in a fresh profile or with Bypass for network.

  5. Localization rewrites everything

    Assets pulled down and every reference in nine text formats rewritten to local paths, then a portability check that refuses local-only references.

The root cause, in one sentence

A copied site breaks offline because some reference in it still resolves to the original server, and the browser is happy to follow that reference as long as it has a network. On the day you make the copy everything works, because the origin is still up. Disconnect, or wait for the origin to move, and the leaks show.

The reason this is hard is not the images in the HTML -- anyone finds those. It is the references that live in places a text search for <img never looks.

Where references hide

A copy that only rewrites HTML attributes gets the first row and leaks the other six. The last column is what you see when each one fails.
WhereLooks likeWhat breaks offline
HTML src, href, poster<img src="https://cdn…/hero.jpg">Images, scripts, stylesheets, video posters
srcset and sizessrcset="…/a.jpg 640w, …/a.jpg 1280w"One width works, the others 404 as the viewport changes
CSS url()background: url(…), @font-face { src: url(…) }Backgrounds and every custom font
JavaScript stringsimport("https://…/m/Ticker.js"), fetch("/api/…")Animations, components, data loaded at runtime
JSON"image": "https://…"Anything a script renders from data
SVG<use href="…#icon">, <image href=…>Icons and illustrations
manifest.webmanifest, og:image"icons": [{"src": …}]PWA icons, social previews

Source: MDN — <img>: srcset and sizes · MDN — @font-face

What you lose when each kind of reference breaks

ShareValue
Images35.6%
JavaScript24.7%
Fonts4.8%
CSS3%
HTML0.9%
Other (video, JSON…)31%
Share of median mobile page weight by resource type (2,559 KB total, July 2025). Images and fonts are the visible failures; JavaScript is the one that takes the layout with it.

Source: HTTP Archive — Web Almanac 2025, Page Weight

Two references a grep for <img never finds

@font-face {
  font-family: "Satoshi";
  src: url(https://framerusercontent.com/assets/8b0c…/Satoshi-Variable.woff2) format("woff2");
  font-display: swap;
}

.hero {
  background-image: url("https://framerusercontent.com/images/2f1a…/bg.jpg?scale-down-to=2048");
}
The font URL is inside a stylesheet, often a stylesheet loaded from a third host. The background is a data attribute a script reads later. Both are absolute; both point away from your folder.

Source: MDN — @font-face

Two things that make a good copy look broken

file://. Double-click index.html and the browser opens it from the file system. ES modules (<script type="module">) are blocked there by the same-origin rules, and so are fonts and fetches. A perfectly localized site can show no animations and fallback fonts from file:// and be flawless over HTTP. Always test with a local server: python3 -m http.server 8080 is one line and needs nothing installed.

A service worker. If the site registered one, your browser may keep serving cached assets for a while after you go offline, which hides a leak until the cache expires. In DevTools → Application → Service Workers tick Bypass for network, or test in an incognito window.

Source: MDN — Cross-Origin Resource Sharing · MDN — Service Worker API

Diagnose it in DevTools

  1. Serve the folder over HTTP

    cd into it, python3 -m http.server 8080, open http://127.0.0.1:8080. Never file://.

  2. Hard-reload with Offline on

    Network panel → throttle Offline → Cmd/Ctrl+Shift+R. Note what is missing: it tells you which of the seven places the leak is in.

  3. List the foreign hosts

    Throttle back to online, reload, filter the Network panel with -domain:127.0.0.1. Sort by domain. Each remaining host is a dependency.

  4. Find where it is written

    For each host, search the folder: grep -rl "framerusercontent.com" . --include=*.html --include=*.css --include=*.js --include=*.json --include=*.svg. The file list is your rewrite list.

Source: Chrome DevTools — Network reference

What localization rewrites

A copy is real when

  • It renders completely over HTTP with the Offline throttle on.
  • The Network panel, filtered to foreign domains, shows only services you added on purpose.
  • grep for the original hosts across HTML, CSS, JS, JSON and SVG returns nothing you did not expect.
  • Fonts are the design's fonts at every width, and the phone layout opens its menu.

Sources

  1. MDN — <img>: srcset and sizes — Why a page can reference five files for one picture.
  2. MDN — @font-face — Where a font URL actually lives.
  3. HTTP Archive — Web Almanac 2025, Page Weight — Median bytes per resource type across ~16M pages, July 2025 crawl.
  4. MDN — Cross-Origin Resource Sharing — Why fonts and modules fail from file:// and across origins.
  5. MDN — Service Worker API — How a cached worker can hide a broken copy for a while.
  6. Chrome DevTools — Network reference — Filtering requests by domain, the Offline throttle.

FAQ

Why do images disappear in my copied site?

Either the src, srcset or CSS background still points at the origin, or the images were lazy and never loaded before you saved. Filter the Network panel for foreign domains to see which.

Why do animations work online and not offline?

The JavaScript that runs them is imported at runtime from the original host. A module graph has to be walked and localized; a copy of the HTML alone cannot do that.

How do I test offline properly?

Serve the folder with a local server -- never file:// -- set DevTools to Offline and hard-reload. Bypass any service worker. Then walk the routes at three widths.

Does this apply to Framer and Webflow?

Yes, and to hand-built sites. Webflow leans more on CSS backgrounds and its own CDN; Framer on runtime-imported modules and srcset. Same diagnosis either way.

Features · Workflow · Pricing · FAQ