Guide 13 / Web
One File, Zero External Requests: How to Ship a Landing Page That Loads on Its Own
"No dependencies" is a claim about a file, and claims about files are countable. Below is the count on three real single-file pages - 24,490 bytes, 537 lines, zero fetchable references - the grep that reproduces it on any page you write yourself, the order to build in so the property survives your edits, and the five things this rule costs you, each one counted rather than confessed to.
Disclosure: I sell a three-page pack that this guide audits, and the files being counted are the files in that product. Every figure below came out of a command run against the ZIP while writing, the command is printed so you can run it on your own page, and the parts I could not test say so. No load time, score or conversion number appears here, because I measured none.
A normal landing page is a thin file with a long guest list. It asks a CDN for its stylesheet, Google for two font files, a tag manager for its analytics, an image host for the hero, and a form service for the only element that actually captures anything. Each of those is a request, a domain that has to resolve, and a thing that can break without touching your code. The alternative is a page that carries itself: one file, everything in it, nothing fetched.
That alternative has a price too, and most write-ups about it skip the
invoice. This one counts both columns. The subject is three templates I
ship - saas-landing.html,
event-landing.html and
local-business-landing.html - because auditing your own
product in public is more useful than auditing a stranger’s, and
because the numbers are reproducible in about ninety seconds.
1. The claim, and the one command that checks it
"Zero external requests" means: when this file loads, the browser
asks no other computer for anything. The way to check it is not the
Network panel alone - a panel shows what happened on one machine in
one run, and it does not show a url() that only fires on
a state you never reached. The check is a grep for every syntax that
can fetch, run over the whole file:
grep -o -E 'https?://|url\(|@import|<link|<img|src=|@font-face|integrity=|poster=' *.html | wc -l
Nine patterns, one number. On the three files it returns 0. Read individually, the same patterns give the shape of the thing:
| File | Bytes | Lines | Fetchable hits | script | media queries |
|---|---|---|---|---|---|
| saas-landing.html | 10,336 | 216 | 0 | 0 | 1 |
| event-landing.html | 8,332 | 180 | 0 | 1 | 0 |
| local-business-landing.html | 5,822 | 141 | 0 | 0 | 0 |
| All three | 24,490 | 537 | 0 | 1 | 1 |
Two things fall out of that table that are worth internalising before
you write your own. The first is that 12,169 of the 24,490 bytes -
about half the pack - sit inside
<style> blocks. Removing the dependency on a CSS
framework does not remove the CSS; it moves the CSS into your file and
makes it yours to maintain. The second is that a script tag is not a
network request. event-landing.html has 16 lines of inline
JavaScript and still scores zero on the grep, because the code is in
the file. The rule is about fetching, not about JavaScript.
2. The build order that keeps the property true
Most pages lose the property by accident: someone adds one icon font in month two and the claim is dead quietly. The order below is what keeps it alive, and each step names the threshold to stop at.
Step 1: start from the browser’s own type. All
three files declare font-family seven times between them
and @font-face zero times. The stacks are system ones -
-apple-system, "Segoe UI", Roboto, Arial, sans-serif in two
files, Georgia, "Times New Roman", serif in the local
business one. That choice is the difference between a page that paints
with the fonts the reader already has and one that sits waiting for a
font file from somebody else’s server. Write the
sentence down in your own README, because "it looks different on
Windows" is the first thing a colleague will notice.
Step 2: put every colour and radius in one block. Each
file opens with a :root rule; the three of them hold 21
custom properties, 8 in the SaaS page, 6 in the event page, 7 in the
local business one. Change those and the whole page changes, which is
what makes a template reusable instead of merely copyable. The
corollary is a limit: 21 tokens is a design system, 60 is a scavenger
hunt. If a value does not earn a token, hard-code it and accept the
inconsistency.
Step 3: let the container do the responsive work. The
pack contains one @media rule in 537 lines and it is not
doing the layout - see section 4. What does the layout instead is
repeat(auto-fit, minmax(260px, 1fr)), used seven times
across the three files, and
clamp() on the headings, once per file. A card row written
that way fits three cards, two or one without being told, because
auto-fit asks the browser how many 260-pixel columns fit
and hands the remainder to whatever is there. Breakpoints are for
behaviour; auto-fit is for wrapping, and most pages only
ever needed the wrapping.
Step 4: write the promise to the file’s own limit. This is the part that decides whether the page converts, and it is already specified in the markup you are filling in. The SaaS heading is a sentence with two holes:
<h1>The fastest way for [TARGET USER] to [CORE OUTCOME]</h1>
<p class="sub">[One sentence expanding the promise: what it does, who
it's for, the key differentiator. Keep under 40 words.]</p>
"Keep under 40 words" is a threshold printed in the file, and it is the
right one for a reason you can test on your own draft: the sub-line is
capped at max-width: 55ch, so at 40 words it is already
four or five lines on a phone. If your first sentence needs 60 words,
you have two sentences and one of them belongs lower down the page.
The same trick appears in the local business template, where the review
placeholder tells you what to ask a customer for - two sentences
mentioning what you fixed - rather than leaving "testimonials" to the
imagination. A template that states its copy rules is harder to fill in
badly than one that just has short lines.
Step 5: delete sections before you decorate them. The
SaaS file ships five <section> elements: features,
how it works, pricing, FAQ, final call to action. The logo strip above
the fold is five <span>s naming fake companies
(ACME CO, Globex, Initech, Umbrella, Stark Industries). If you cannot
name five real customers, delete the strip; a social-proof band with
invented logos is not a placeholder, it is a legal problem waiting for
traffic. Deleting is safe here precisely because there is no grid
dependency on a fixed column count.
3. What the rule costs you, counted
Five invoices, all of them measured on the same three files. This is the section a buyer should read before paying and the section a critic will skip, so it gets the numbers first.
-
Nothing captures anything.
grep -o -E '<form|<input|<textarea|<select'over the pack returns 0. There are 19 anchor elements between the three files, and 8 of them are literallyhref="#"- a link that scrolls to the top and records nothing. The event template’s three ticket buttons are<button>elements with no click handler, so they are furniture. The only actions that work out of the box are 2tel:links and 9 in-page jumps. A lead form is one element to add and it breaks the property immediately, because every hosted form endpoint is a fetch. -
No images, and no apology for them. Zero
<img>elements, so there is no hero photo, no team wall and no product shot. What is left doing the visual work is type, hairlines and a single gradient behind the event hero. If your offer needs to be seen - food, furniture, fabric - this is the wrong architecture, and no amount of CSS craft changes that. - No analytics, so no evidence. Nothing phones home, which is the point and also the blind spot: you will not know the page worked. If you add a counter, you have made a page that asks the internet for something, and you should update the claim rather than keep the marketing line.
-
No head metadata at all. The grep below returns 0
for all three files, and it is not a dependency question - it is
simply unwritten work:
grep -c 'name="description"' *.html. There is noog:tag, norel="canonical"and no<link rel="icon">. Each file does have a<title>, and all three still carry the one they shipped with, which names the template and its number rather than a business. Change the title, write a description, add anog:titleandog:description, or your link preview in Slack and Messages will be whatever the host guesses. -
Emoji and generated text do the work of assets. The
files use system emoji as iconography - the SaaS feature tiles carry
three of them, rendered by
.card .icon, and the pricing checkmarks are CSScontentrather than markup. Generated content is not part of the text a screen reader walks through in the same way an<img>withaltis. How it actually reads with a screen reader was not tested here, and the pack ships no accessibility claim to check that against.
4. The one media query, and why it is the honest thing to look at first
Here is the entire responsive breakpoint logic of the pack, from line
36 of saas-landing.html:
@media (max-width: 720px) { nav ul { display: none; } }
Below 720 pixels the four in-page nav links (Features, How it works,
Pricing, FAQ) are hidden and nothing replaces them: there is no menu
button and no script that could add one. So on a phone the header is
the product name and the "Get started" button. That is defensible - on
a one-screen page the nav is mostly decoration, and the sticky header
still carries the call to action - but it is a decision, and it is the
first thing to check on any page that claims to be responsive. The
shipped README.md in the pack does state it, in one
sentence, under "Responsive by default".
The other two files have no @media rule at all, and that is
not an oversight: they have no nav to collapse, their card rows are
auto-fit, their hero sizes come from
clamp(), and their two and three column blocks are declared
with minmax(220px, 1fr) and minmax(240px, 1fr),
which become one column by arithmetic. The local business file is
labelled mobile-first in its own header comment and is the smallest of
the three at 5,822 bytes.
There are three related loose ends worth naming, all countable, none tested in a browser by me:
-
Three
color-mix()declarations, no fallback. Two in the SaaS file (the icon tile background and the featured pricing card’s shadow), one in the event file (each agenda row’s bottom border).color-mix()is a modern function; where a browser does not know it, the declaration does not do what it says and you get the initial value instead, which for those three means an icon tile without its tint, no soft shadow, and possibly an invisible rule between agenda rows. The fix costs one line per declaration: put a plainrgba()or hex value first and let thecolor-mix()line override it in browsers that read it. I did not verify which browser versions implement it, so treat that as "check your own target", not as a support table. -
One sticky header, one smooth scroll, no motion opt-out.
position: stickyappears once andscroll-behavior: smoothonce, both in the SaaS file;prefers-reduced-motionappears zero times in the pack. That means the page scrolls smoothly for a reader who has asked their device not to do that. The one-line fix is to wrap the declaration in a@media (prefers-reduced-motion: no-preference)block. -
Generated checkmarks. Both list styles that show a tick
use
li::beforewith acontentvalue, which means the tick is decoration. If a list ever encodes meaning ("included" versus "not included"), the distinction has to be in the text, not in a pseudo-element.
5. Verifying it without a server
You do not need hosting to check the property. Three greps prove the file, and three browser acts prove the page. Each step below has a pass condition, and the whole ladder takes about two minutes.
-
The fetch grep from section 1. Run it in the
directory. Pass is
0. This is the check that catches aurl()in a hover state or a background image you forgot. -
Dump every link target and read it.
On the pack this prints eight lines of baregrep -o -E 'href="[^"]*"' *.html | sort | uniq -chref="#"alongside the in-page jumps and the twotel:numbers. No pattern decides for you here - a link to#pricingis an action, a link to#is furniture - so the output is a list to mark up, not a verdict. Then count the clickables that are not anchors:grep -c '<button' *.htmlreturns 3, all in the event file, and nothing in that file’s script listens to them. -
Count what you still have to fill in.
grep -o -E '\[[^]]+\]' *.html | wc -lreturns 97 on the pack: 75 distinct strings sitting on 51 lines. That is the honest labour estimate for the whole template, and every one you leave is a page that says "[City]" to a stranger. -
Open it over
file://with a cleared Network panel. Double-click the HTML or drag it into a window, reload, and read the request count in the panel’s footer. Pass is one request - the document - transferred at a size close to whatwc -creports. Anything else in that list has a Domain column telling you who you are now trusting. - Pull the network. Turn off Wi-Fi and reload. Pass is "looks the same, except the browser chrome says offline". A page that loses its fonts, its hero or its form when you do this was never a single file whatever its README claimed, and this is the one test a hosted page cannot fake - which is why it is worth thirty seconds.
- Move the file, then shrink the window. Copy it to another machine or email it to yourself: pass is "nothing to install". Then drag the window under 720 pixels and look at the header - if the nav has vanished with nothing replacing it, decide now whether that is your design or an oversight.
Two caveats I cannot settle from inside a file. Serve the page over HTTP
and you may see a request for /favicon.ico that no line of
your markup asked for, because browsers go looking for one; whether that
happens for you, and whether an inline data-URI icon is worth the bytes
it adds, is a test in your own browser and not a fact verified here. And
the ladder above proves only that the page carries itself - no speed
figure, no accessibility result and no conversion rate comes out of a
grep, and this guide claims none anywhere.
6. The only JavaScript in the pack, and what happens after its deadline
event-landing.html ships a countdown, and it is worth
reading closely because it is a small example of a large class: dynamic
content that will disagree with the static claims around it. The whole
thing is 16 lines. The four facts that matter:
-
The date is hard-coded. Line 162 reads
var eventDate = new Date("2026-11-01T09:00:00");, under a comment on the line above that says "EDIT THIS DATE". A buyer who uploads without editing line 162 publishes somebody else’s event date and a countdown that lies by three weeks. - It counts to the visitor’s clock, not the venue’s. The string has no timezone offset, and the file’s own comment says "(local time)". For a physical event that is a reasonable approximation, because the doors are where the venue is; for a webinar at 09:00 in your timezone it silently means 09:00 in theirs. If the event is online, put an explicit offset or a UTC time in the string.
-
After the event it shows zeros, forever. The next line
reads
if (diff < 0) diff = 0;, so on day two the hero says "0 days 00 hours 00 min 00 sec" above a "Get your ticket" button. That guard is doing something useful - it stops the page printing a negative number - but it is not a design. Swap the timer for a "recordings are here" band when the date passes, which you can do in that same guard. -
Markup degrades well; the interval does not. The four
boxes ship
--as their text, so with JavaScript off a reader sees dashes rather than a lie, which is the right default. On the other side, the last line issetInterval(tick, 1000);with no clear and no visibility check: it keeps rewriting four DOM nodes every second while the tab sits in a background window. I did not measure what that costs a laptop battery, and I am not going to guess.
The general rule, which applies to any page and not just this one: a countdown is the most fragile element on a landing page, because it is the only one whose correctness has an expiry date attached. Ticket prices, "last event sold out" and seat counts are the same family - claims with a fuse. If nobody is going to be responsible for turning them off, do not ship them, and let the page stay true by being quiet.
7. What to check first, in ten minutes
If you have one pass at a page someone else left you, spend it in this order, because the cost of each error rises as you go down the list.
- Placeholders. The count from section 5, step 3 is your work estimate, and an unfilled bracket is the mistake a stranger will quote back to you. Delete any section you cannot fill honestly.
-
Clickables. Every target that is not a real URL, a
phone number you answer or an anchor that exists on the page is
decoration, and on a landing page decoration is the thing people try to
press. The two
tel:links in this pack are the same fake 555 number, in the header and in the contact block - a detail only catchable by reading. - The head. Title, meta description, Open Graph title and description, a share image that lives on the same host as the page, a canonical, a favicon reference. None of those six are fetches if the image is your own file, and all of them are invisible until the first person shares the link.
- The dynamic claim. Any date, price, seat count or sold-out line, plus what it will say the day after. Section 6 is the worked example.
- The nav at 720 pixels. If it disappears with nothing replacing it, either shorten it to one link - which is what these pages do - or add a details-based disclosure so the menu needs no JavaScript.
- Then run the six-step ladder from section 5 and keep the output. A property you can re-check in ninety seconds is worth more than a claim you inherited.
What this page did not test
- No rendering, no speed figures. Nothing was opened in a browser while writing this guide, so there is no Lighthouse score, no Core Web Vitals number and no claim that 24,490 bytes is fast. The byte counts, line counts and grep results are the measurements; what they do to a real paint is not measured here.
-
No browser support table. Three
color-mix()declarations are in the files and their absence of a fallback is countable; which engines accept the function was not verified, so that is a question for your own target readers. -
No accessibility audit. The landmark elements, one
h1per file, 11h2s and 29h3s in reading order are facts. Whether a screen reader handles the generated checkmarks and emoji tiles acceptably was not tested. - No conversion evidence. These pages have never been put in front of a customer as part of this project - this store has recorded zero orders - so nothing here is a claim about what converts. Section 2’s thresholds come from the files’ own stated limits and ordinary typographic arithmetic, not from data.
- No hosting advice. Publishing a single HTML file is the easy half and depends on services that change; this page says nothing about which to use, because it tested none.
The pack this guide counted
The
HTML Landing Page Templates
are $9, one-time, six files: the three pages above,
plus README.md (26 lines), SUPPORT.md and
LICENSE.txt, for 27,339 bytes unzipped. Everything
counted in this guide is what you get: 24,490 bytes of HTML, zero
external references, one media query and its nav consequence stated in
the README, 97 bracketed placeholders, no form, no image, no
analytics, no meta description. If you want a page that captures
leads or shows photographs, this is the wrong nine dollars and the
guide above tells you why before you spend it.
The full catalog (contracts, trackers, content calendars, resumes, student and note files) lives at payhip.com/MonkeyRun, individual products run $4 to $9, and the coupon LAUNCH20 takes 20% off any single order at checkout.
One honest note on the catalog: the ten products inside it total $61 bought separately and the Complete Bundle is $19. That is $42 off. Two files can never beat $19 (the two dearest are $18), the four cheapest already come to exactly $19, and from four items up the bundle ties or wins - so buy the single file you need today, and take the bundle the moment you want four. And nothing above needs a purchase: the grep, the four-check verification and the build order are the method, they run on a file you write yourself, and they are complete without buying anything. Prices, file contents and instant download are on the catalog page, and the same zero-reference audit applied to four HTML resumes is in guide 07.