Curriculum ▸ HTML Zero → Mastery ▸ Lesson 2: HTML vs CSS vs JavaScript Foundations

Lesson 2 — HTML vs CSS vs JavaScript Layer Roles & Separation

Learning Goals

Part 1 — The Big Idea

Web pages are best built in layers so each concern stays focused:

What each layer does

  • HTML: structure & semantics — headings, paragraphs, links, forms, landmarks.
  • CSS: presentation — layout, spacing, colors, typography, responsive rules.
  • JavaScript: behavior — events, dynamic updates, data fetching, state.
Key idea: HTML should be useful even without CSS/JS. CSS makes it beautiful; JS makes it interactive.

What not to mix

  • Don’t style with HTML attributes or deprecated tags (e.g., <font>).
  • Don’t wire events inline (e.g., onclick="...") — prefer JS listeners.

Part 2 — Where Each Layer Fits

HTML

All the content and semantic structure: <header>, <main>, <article>, <nav>, <button>

CSS

Visuals and layout: color schemes, spacing systems, grid/flex, fonts, animations.

JS

Behavior and state: event listeners, UI toggles, fetching data, saving preferences.

Part 3 — The Anatomy of a Triad Page

This minimal triad demonstrates each layer in its proper place.

<!DOCTYPE html> <!-- modern mode -->
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Triad Example</title>
    <link rel="stylesheet" href="styles.css"> <!-- CSS layer -->
  </head>
  <body>
    <header>
      <h1>Hello, Triad!</h1>
      <button id="themeBtn">Toggle Theme</button>
    </header>
    <main>
      <article>
        <h2>Why separation of concerns?</h2>
        <p>Structure, style, and behavior live in their own layers.</p>
      </article>
    </main>
    <script src="app.js" defer></script> <!-- JS layer -->
  </body>
</html>

Part 4 — Terms & Mental Model

HTML  →  Parser  →  DOM Tree
CSS   →  Parser  →  CSSOM Tree
DOM + CSSOM → Render Tree → Layout → Paint → Composite
JS can read/modify DOM & CSSOM and trigger reflow/paint when needed.

Part 5 — Build Your Layered Page (Step-by-Step)

  1. Create a folder lesson-02.
  2. Create index.html, styles.css, and app.js.
  3. Copy the HTML from Part 3 into index.html.
  4. Add base styles and a theme modifier in styles.css.
  5. Implement a theme toggle in app.js and store the preference with localStorage.
  6. Open index.html in the browser and test.
Starter CSS
:root { color-scheme: light dark; }
body { font-family: system-ui, sans-serif; margin: 0; line-height: 1.6; padding: 1.25rem; }
header { display: flex; gap: .75rem; align-items: center; justify-content: space-between; }
button { padding: .5rem .75rem; border: 1px solid #ccc; border-radius: .5rem; background: #f4f4f4; cursor: pointer; }
main { max-width: 60ch; }
.dark body { background: #121212; color: #eaeaea; }
.light body { background: #ffffff; color: #222; }
Starter JS
const btn = document.getElementById('themeBtn');
const saved = localStorage.getItem('theme');
if (saved) document.documentElement.className = saved;
btn.addEventListener('click', () => {
  const root = document.documentElement;
  const next = root.classList.contains('dark') ? 'light' : 'dark';
  root.className = next;
  localStorage.setItem('theme', next);
});

Part 6 — Open, Refresh, and Inspect

Tip: If the toggle “does nothing”, confirm the script is loaded with defer and check the Console for errors.

Part 7 — Common Anti-Patterns

❌ Inline styles

<p style="color:red;font-size:24px">Hi</p>

Why it hurts: hard to reuse or override; mixes concerns.

✅ Use classes + CSS

<p class="warning">Hi</p>
/* CSS */ .warning { color:red; font-size:24px; }

❌ Inline event handlers

<button onclick="doThing()">Click</button>

✅ Add listeners in JS

<button id="doBtn">Click</button>
<script>
  document.getElementById('doBtn').addEventListener('click', () => alert('Done!'));
</script>

Part 8 — Practice (Do First, Then Peek)

  1. Add a nav with two links and ensure it remains readable with JS disabled.
  2. Style the page title using CSS only (no inline styles).
  3. Implement a button that reveals a hidden paragraph via JS (use the hidden attribute).
  4. Break something on purpose (remove the stylesheet link) and use DevTools to diagnose.
One possible solution
<nav><a href="#">Home</a> · <a href="#">Docs</a></nav>
<h1 class="title">Layered Page</h1>
<p id="extra" hidden>Surprise content!</p>
<button id="revealBtn">Reveal</button>
/* CSS */
.title { color:#00ffff; font-weight:800; }
#extra[hidden]{ display:none; }
// JS
const extra = document.getElementById('extra');
document.getElementById('revealBtn').addEventListener('click', () => {
  extra.hidden = !extra.hidden;
});

Part 9 — Mini-Project: Profile Card (Layered)

Create a profile card that looks good with CSS and has a small JS interaction (toggle extra details).

Starter HTML
<section class="card profile">
  <h2>Your Name</h2>
  <p>Short bio line here.</p>
  <button id="moreBtn">Show more</button>
  <div id="more" hidden>
    <p>More details about you...</p>
  </div>
</section>
CSS & JS sketch
.profile { max-width: 420px; margin: 1rem auto; background:#1c1c1c; padding:1rem; border-radius:12px; border:1px solid #2a2a2a; }
#more[hidden]{ display:none; }
const more = document.getElementById('more');
document.getElementById('moreBtn').addEventListener('click', () => {
  more.hidden = !more.hidden;
});

Lesson 2 Dictionary

addEventListener
JavaScript method to attach event handlers without inline attributes (e.g., elem.addEventListener('click', fn)).
<article>
Self-contained composition (e.g., a card or post) within the main content.
<button>
Interactive control; pair with JS listeners for behavior.
class (attribute)
Token(s) used as styling/JS hooks (e.g., class="warning").
CSS
Presentation layer: layout, spacing, color, typography, responsiveness.
CSSOM
Tree of parsed CSS rules; combined with the DOM to create the render tree.
defer (script attribute)
Downloads a script during parsing and executes after the document is parsed.
<details>
Native disclosure widget used for hints/solutions in this lesson.
DOM
Document Object Model — parsed HTML as a live tree that JS can read/modify.
Event listener
Function responding to user/system events (click, input, etc.).
<header>
Introductory content/navigation for a page or section.
hidden (attribute)
Boolean attribute to hide content (e.g., toggle with JS by flipping elem.hidden).
id (attribute)
Unique identifier for an element (id="themeBtn"), used to select it in JS or link targets.
Inline styles
CSS placed directly on elements via style="..."; discouraged in favor of classes.
JavaScript
Behavior layer: events, state, DOM/CSSOM updates, storage, fetch.
<link>
References a stylesheet: <link rel="stylesheet" href="styles.css">.
localStorage
Key–value storage for persisting simple preferences (e.g., theme).
<main>
Primary content landmark of the page.
<nav>
Section containing navigation links.
<p>
Paragraph of text.
Render Tree
Combination of DOM + CSSOM used by the browser to layout and paint.
rel (attribute)
Relationship of a linked resource (e.g., rel="stylesheet" on <link>).
<script>
Loads and executes JavaScript. Use defer for non-blocking behavior.
Separation of Concerns
Keeping structure (HTML), presentation (CSS), and behavior (JS) in distinct layers.
src (attribute)
Specifies the external resource for scripts (and other elements), e.g., src="app.js".
<summary>
Label for a <details> disclosure widget.