Every website you visit — from a simple blog to a complex web application — is built from the same three technologies: HTML, CSS, and JavaScript. They are not interchangeable; each one has a distinct job, and understanding the division of responsibility between them is one of the most important foundations in web development.
The three layers
Think of a webpage as a building. HTML is the concrete and steel — the raw structure that holds everything up. CSS is the interior design — the paint, the furniture, the layout. JavaScript is the plumbing and electrics — the systems that make things actually work when you interact with them.
How the browser processes them
When you navigate to a URL, the browser fetches the HTML file first. It reads through it top to bottom, building a tree of elements called the DOM (Document Object Model). The DOM is the browser's internal representation of the page — a structured map of every element and its relationships.
As the browser parses the HTML it encounters references to CSS files and JavaScript files. CSS is downloaded and used to build a second internal structure called the CSSOM (CSS Object Model), which describes the styles that apply to each element. The browser merges the DOM and CSSOM into a render tree, calculates the position and size of every element (layout), and then paints pixels to screen.
JavaScript runs after the DOM is available (or immediately if placed in the <head> with special attributes). It can read and modify both the DOM and the applied styles at any time, which is how interactive behaviour — updating content without a page reload, responding to user input, animating elements — is achieved.
<head>) delays everything that follows it.
Why separation of concerns matters
Keeping HTML, CSS, and JavaScript in separate files is a principle called separation of concerns. It matters for several practical reasons:
- Maintainability — changing the visual design of a site should not require touching the HTML structure or the JavaScript logic. With separate CSS files, a designer can restyle an entire site without touching a single line of markup.
- Cacheability — browsers cache external CSS and JS files. If your stylesheet is a separate file, it is downloaded once and reused across every page. Inline styles are re-downloaded with every page.
- Readability — HTML that is free of inline styles and inline scripts is dramatically easier to read, debug, and hand off to other developers.
- Reusability — a single external stylesheet can govern the appearance of hundreds of pages. A single JavaScript file can add the same behaviour to every page that loads it.
A practical example: a button that changes colour on click
This is the same feature built with each layer doing exactly its job. Notice how each file is completely independent and could be swapped out without touching the others.
HTML — the structure
The HTML defines that a button exists and gives it an identity. It says nothing about what colour the button is or what happens when it is clicked.
CSS — the style
The CSS describes how the button looks in its default state, and how it looks when the JavaScript adds an active class to it. The CSS knows nothing about JavaScript — it just defines rules for class names.
background: #2563eb;
color: #fff;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background 0.3s;
}
.my-button.active {
background: #16a34a;
}
JavaScript — the behaviour
The JavaScript listens for a click event and toggles the active class on the button. It does not set any colours directly — it delegates that entirely to CSS.
btn.addEventListener('click', () => {
btn.classList.toggle('active');
});
This is a deliberate design choice: JavaScript manipulates state (active or not active) and CSS responds to that state with the appropriate visual treatment. Mixing colour values directly into JavaScript is harder to maintain and defeats the purpose of CSS.
Inline vs external: when to use each
Both CSS and JavaScript can be written inline inside the HTML file or in separate external files. Each approach has legitimate uses.
| Approach | When to use it |
|---|---|
<style> in HTML |
Single-page prototypes, email HTML, critical above-the-fold styles to avoid a render-blocking request. |
External .css file |
Any real project. Enables caching, reuse across pages, and clean separation of concerns. |
<script> inline in HTML |
Small snippets, quick experiments, or tiny config objects passed from server to client. |
External .js file |
Any real project. Load with defer or async to avoid blocking rendering. |
defer to external script tags (<script src="app.js" defer>) so the browser downloads the script without blocking HTML parsing, and runs it after the DOM is ready. This removes the need to wrap everything in DOMContentLoaded handlers.
Why code playgrounds are useful for experimenting
Understanding how HTML, CSS, and JavaScript interact is much faster when you can see the result instantly. Code playgrounds like CodePen and the SmartiTools Code Playground give you three panels — one for each language — and render the output live as you type.
This tight feedback loop is ideal for learning. You can change a CSS property and immediately see the visual effect, or add a line of JavaScript and watch the behaviour update in real time, without needing to set up a local development environment, manage files, or reload a browser tab manually.
Playgrounds are also excellent for isolating problems. When debugging a tricky interaction between a CSS transition and a JavaScript class toggle, stripping everything back to a minimal example in a playground is far faster than hunting through a full project.
Try it in the Code Playground
Write HTML, CSS, and JavaScript side by side and see the result live — no setup required.
Open Code Playground