HTML describes structure — what exists on the page. CSS describes presentation — how it looks. JavaScript describes behavior — what happens when something changes. Most confusion for beginners comes from mixing these up: trying to make something look right using JavaScript, or trying to add interactivity using CSS. Keeping the three separate in your head (even if the code lives in one file) makes debugging dramatically easier.
Using <div> for everything works, but <nav>, <article>, <button>, and <section> exist for real reasons: screen readers use them to build a navigable outline of your page, search engines weight them differently, and browsers give you free behavior (a <button> is keyboard-accessible by default; a <div onclick> is not, unless you rebuild that yourself).
Every element is a box: content, padding, border, margin, in that order from the inside out. Almost every "why isn't this lining up" bug traces back to a misunderstanding of which of these four is causing the gap. box-sizing: border-box is worth setting globally early in a project — it makes width calculations include padding and border, which matches how most people intuitively expect sizing to work:
*, *::before, *::after {
box-sizing: border-box;
}
Flexbox is for one-dimensional layout — a row or a column of items that need to align, distribute space, or wrap. Grid is for two-dimensional layout — rows and columns together, like a page template. Reaching for Grid when you just need to align three buttons in a row is usually more setup than the problem needs; reaching for Flexbox to build a full page layout usually means fighting it once things need to align on both axes at once.
A common early mistake is treating the DOM itself as the source of truth — reading values back out of elements, mutating them directly, and losing track of actual state. Frameworks like React exist largely to solve this, but the underlying principle applies even in plain JavaScript: keep your actual data in variables, and treat the DOM as a rendering of that data, not the data itself.
async function loadArticles() {
try {
const res = await fetch('/api/articles');
if (!res.ok) throw new Error('Request failed');
const data = await res.json();
render(data);
} catch (err) {
showError('Could not load articles.');
}
}
The part beginners skip most often is the try/catch and the res.ok check — fetch doesn't reject on a 404 or 500, only on network failure. Without checking res.ok, a broken API call fails silently and your page just shows nothing, with no clue why.
React, Vue, and Angular all still compile down to HTML, CSS, and JavaScript — they don't replace the need to understand the box model, event handling, or how the browser actually renders a page. Learning a framework before these fundamentals tends to produce code that works by accident and breaks in ways that are hard to debug, because the underlying "why" is missing.
Comments