Three languages, three jobs
HTML, CSS and JavaScript are not competitors. Knowing which one owns a problem saves hours.
Every web page is built from three materials with strictly separate jobs. When you are stuck, naming the right material is usually the whole fix.
- HTML is structure and meaning. It says "this is a heading, this is a button, this is a list".
- CSS is presentation. It says "headings are large, buttons are blue, lists sit side by side".
- JavaScript is behaviour. It says "when this button is clicked, do something".
This ordering matters for real reasons. A page whose content lives in HTML is readable by search engines, screen readers, and slow connections. A page whose content only appears after JavaScript runs is invisible to all three until the JavaScript downloads, parses, and executes. That is the whole argument behind server-side rendering, which shows up in the frontend track.
Content in the HTML
- Visible immediately, even on a slow phone
- Readable by search crawlers and screen readers
- Works if a script fails to load
Content built by JavaScript
- Blank until the script runs
- Crawlers may see an empty page
- One script error can blank the whole screen
Real apps use both, deliberately. The skill is deciding per screen: this marketing page must be in the HTML, this drag-and-drop editor obviously cannot be. Frameworks give you that dial. Most people never touch it because they did not know it existed.
What to remember
- HTML is structure, CSS is appearance, JavaScript is behaviour.
- Content that only exists after JavaScript runs is invisible to a lot of the world.
- Choosing per screen is a real decision, not a framework default.
Terms in this lesson
Field notes
Loaded from a deliberately slow source. The lesson above was already readable while this was still travelling. That is streaming, and it is the same trick a chat interface uses.
The bug was three caches deep
A team spent two days on a "deploy that did not work". The deploy was fine. A CDN rule was caching the HTML document itself for an hour, so every visitor kept getting the previous build. The fix was one header; finding it needed knowing the copies existed.
Reported by a solo founder, 2024
Nobody had opened the empty state
A product launched with a dashboard that looked superb with demo data and completely blank on day one. Every new signup saw an empty white rectangle and assumed the app was broken. Signup-to-activation doubled after a two-hour fix.
Common enough to be a cliché
resolved in 900ms · region iad1
Hide field notes toggles a search param the loader reads. With it off, the slow promise is never created, so nothing streams.