You build a web page, it looks perfect on your screen, and you feel good about it. Then a friend opens the same page on a different browser, or on an older phone, and something is off: a button is misaligned, an animation never starts, or the whole thing just sits there broken. Nothing changed in your code. So what happened?
What happened is that “the web” is not one single program. It is a shared set of rules that many different browsers each try to follow, on many different devices, at many different points in time. When you understand how that works, the mystery disappears, and you can start writing pages that behave well for almost everyone. That is exactly what this article is about.
One web, many browsers
A browser is the program a person uses to open web pages: Chrome, Firefox, Safari, Edge, and others. Each of these is made by a different team, and each has its own internal engine that reads your HTML, CSS, and JavaScript and turns them into something you can see and click.
Here is the key idea: those engines are all trying to follow the same published standards, but they do not all support exactly the same things at exactly the same time. A brand-new CSS feature might work in the latest Chrome today, arrive in Safari a few months later, and still be missing from a browser someone has not updated in two years.
You write: ┌─────────────────────────────┐
HTML/CSS/JS → │ Browser engine reads it │
│ and decides what to do │
└─────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
Chrome engine Safari engine Old browser
"I support "I support "I never heard
that feature" most of it" of that feature"
So the same page can produce three different results, not because your code is wrong, but because each engine interpreted it with a slightly different set of abilities. This is the root of almost every “it works on my machine but not theirs” story on the web.
What “feature support” actually means
When people say a browser “supports” a feature, they mean its engine knows how to handle that specific instruction. A feature can be a CSS property (like a particular layout tool), an HTML element, or a JavaScript function.
Support is not a yes/no switch for the whole browser. It is decided feature by feature, and it changes over time as browsers release new versions. That gives you a few realistic situations to plan for:
| Situation | What it means for you |
|---|---|
| Widely supported, old feature | Safe to use almost everywhere |
| New feature, supported in latest browsers | Works for updated users, missing for others |
| Experimental feature | May work today, may change or be removed |
| Removed or non-standard feature | Avoid; it can break at any time |
You do not have to memorize which browser supports what. The job of a developer is to assume nothing and instead ask, for each important feature, “is this safe enough for the people I expect to visit?” Tools exist that show support data for any given feature, and you check them the way a builder checks whether a material is rated for the climate.
Know your audience first
“Will this work everywhere?” is the wrong question to obsess over. The better question is “will this work for my visitors?” A site for designers using the newest Macs can be braver with new features than a government service that must support very old devices.
Progressive enhancement: build up from a solid base
There are two classic ways to think about supporting a range of browsers, and they are easiest to understand side by side.
The first is progressive enhancement. You start with a basic version of the page that works for everyone, even with very limited browsers, and then you layer nicer features on top for browsers that can handle them. The fancy stuff is a bonus, not a requirement.
Think of a staircase with a ramp built beside it. Everyone can get to the top using the ramp (the basic version). People who are able to take the stairs (modern browsers) get there faster and more comfortably, but nobody is left stranded at the bottom.
A simple example in words: imagine a contact form. The base version is plain HTML that submits and works in any browser. On top of that, a modern browser might add live validation, smooth animations, and instant feedback. If those extras fail, the form still submits. The core job is never at risk.
Graceful degradation: build full, then catch the gaps
The second approach is graceful degradation, and it runs in the opposite direction. You build the full, modern experience first, then make sure that when a feature is missing, the page degrades into something still usable instead of collapsing.
The classic phrase is “fails gracefully.” A video player that cannot play a fancy format falls back to a simpler one. A layout that cannot use a new positioning feature falls back to an older, plainer arrangement. The user might get a less polished result, but never a broken page.
| Approach | Starting point | Direction |
|---|---|---|
| Progressive enhancement | Basic version that works for all | Add features upward |
| Graceful degradation | Full modern version | Provide fallbacks downward |
In real projects these two ideas blend together. The shared goal behind both is the same: no visitor should ever hit a dead end just because their browser is older or different.
What a polyfill is
Now we get to the word in the title. A polyfill is a piece of code that adds a missing feature to a browser that does not have it yet. The name comes from “filling in the gaps” — like a filler paste you use to patch a hole in a wall so the surface is smooth again.
Here is the idea in plain terms. Suppose modern browsers have a built-in function called, say, niceThing(), but some older browsers never got it. Without help, calling niceThing() in an old browser causes an error. A polyfill checks whether the feature already exists and, if it does not, defines it in plain code that the old browser can run. After that, your page can call niceThing() everywhere and trust that it works.
// A polyfill, in spirit: only add the feature if it is missing
if (!window.niceThing) {
window.niceThing = function () {
// a hand-written version that does the same job
// using older, widely supported code
};
}
The important part is the if check. A good polyfill never overwrites a feature the browser already has. It only steps in when something is absent, so modern browsers use their fast built-in version and older browsers borrow the substitute. You usually do not write polyfills yourself; you include well-tested ones that others maintain, and only for the specific features you need.
Polyfills are not free
Every polyfill is extra code your visitors must download and run, and some features simply cannot be faithfully recreated. Add polyfills deliberately, only for features that matter and audiences that need them — not “just in case” for everything.
Transpilers: rewriting modern code into older code
A polyfill adds a missing feature at runtime. A transpiler does something related but different: before your site ever ships, it rewrites your modern source code into an older style that more browsers understand.
The word is a blend of “translate” and “compile.” You write code using the newest, most comfortable syntax. The transpiler runs on your machine and produces an equivalent version using older syntax that old engines accept. The behavior is the same; only the way it is written has been translated down to a more widely understood form.
Modern code you write → [ transpiler ] → Older-style code
(newest syntax) runs before shipped to browsers
you publish (more of them understand it)
A quick way to keep them straight:
| Tool | What it fixes | When it runs |
|---|---|---|
| Polyfill | A missing feature (function, object) | In the browser, at page load |
| Transpiler | Newer syntax an old engine can’t parse | On your machine, before publishing |
In practice they work as a team. The transpiler handles modern grammar, and polyfills handle modern features. Together they let you write comfortable, current code while still reaching people on older browsers. Most modern build setups wire both up for you once, so you rarely think about the mechanics day to day.
How to think about “will this work everywhere?”
You will not test on every browser that exists — nobody does. Instead, you build a habit of thinking, and it is simpler than it sounds:
- Decide who you are building for. A niche developer tool and a national bank have very different audiences and very different obligations.
- Use a solid base. Start with HTML and CSS that work broadly, so the core content and main actions never depend on the fanciest features.
- Check before you rely on something new. For any feature that matters, look up its support instead of guessing. If support is thin, plan a fallback.
- Add polyfills and transpiling deliberately, for the specific gaps your audience actually has — not blanket coverage of every browser ever made.
- Test on more than your own screen. Try a different browser, a phone, a slower connection. Surprises usually show up there, not on the machine you built it on.
The mindset that matters most
You are not aiming for a pixel-identical page in every browser — that is neither possible nor necessary. You are aiming for a page where every visitor can read the content and complete the main task. Equal experience is the goal, not identical appearance.
Recap
Let’s pull the threads together. The same page can behave differently because every browser has its own engine, and those engines support features at different times — so support is something you check per feature, not assume. To handle that range, progressive enhancement starts from a base that works for everyone and adds extras on top, while graceful degradation starts modern and falls back cleanly when a feature is missing. A polyfill is code that supplies a missing feature to browsers that lack it, and a transpiler rewrites modern syntax into an older form before you publish. Used together, and aimed at the audience you actually have, these tools let you write current code that still serves people on older or different browsers.
From here, a natural next step is to look more closely at how a browser actually turns your HTML and CSS into a rendered page, and how the developer tools built into every browser let you inspect and debug exactly what each engine is doing. That is where these ideas stop being abstract and start being something you can watch happen.