An interactive tutorial covering the three pillars of web development - HTML structure, CSS styling, and JavaScript interactivity - with 14 live demos, cheatsheets, and a scored quiz.
Explain what HTML is and why it is the foundation of every web page.
Write a valid HTML5 document from scratch with proper meta tags.
Distinguish between block-level and inline elements and know when to use each.
Use attributes correctly - including global, boolean, and element-specific attributes.
Use semantic elements to improve accessibility, SEO, and code readability.
Build a multi-section page with forms, tables, links, images, and multimedia.
description
What is HTML?
HTML
HTML (HyperText Markup Language) is the standard language for creating
and structuring content on the web. Think of it as the skeleton
of a web page - it defines what content exists (headings,
paragraphs, images, links) while CSS and JavaScript control how that
content looks and behaves.
Why does this matter? Without well-structured HTML,
search engines cannot index your content correctly, screen readers
cannot navigate it, and browsers may render it unpredictably.
Writing clean, semantic HTML is the single most important best practice
in front-end development - it makes your site accessible to
everyone, including users who rely on assistive technologies.
HTML uses tags (e.g., <p>, <h1>) to wrap content and give it meaning.
Tags are paired - an opening tag (<p>) and a closing tag (</p>) - with content in between.
Some tags are self-closing (e.g., <img>, <br>) because they have no child content.
The browser reads HTML top-to-bottom and builds a tree structure called the DOM (Document Object Model).
title
Headings & Paragraphs
HTML
Headings (<h1> to <h6>) and
paragraphs (<p>) are the most fundamental HTML
elements. Headings define a hierarchy of importance:
<h1> is the main page title (use only one per page),
<h2> marks major sections, <h3>
sub-sections, and so on. Search engines use this hierarchy to
understand your content structure, and screen readers let users
navigate by heading level - so getting the hierarchy right matters
for both SEO and accessibility.
Paragraphs are block-level elements that automatically add spacing
above and below. The browser collapses multiple spaces and line
breaks inside a <p> into a single space - if you
need to preserve formatting, use <pre> (preformatted text)
instead. For a line break without starting a new paragraph, use
the self-closing <br> tag. For a thematic break
(horizontal rule), use <hr>.
<!-- Heading hierarchy - use in order, never skip levels -->
<h1>Main Page Title</h1> <!-- Only ONE h1 per page -->
<h2>Section Heading</h2>
<h3>Sub-section Heading</h3>
<h4>Detail Heading</h4>
<!-- Paragraphs add automatic spacing -->
<p>This is a paragraph. The browser adds margin
above and below automatically.</p>
<p>This is another paragraph. Extra spaces
and line breaks are collapsed into one.</p>
<!-- Preformatted text preserves whitespace exactly -->
<pre>
This text preserves
all spaces and
line breaks exactly as written.
</pre>
<!-- Line break and horizontal rule -->
<p>Line one.<br>Line two (same paragraph).</p>
<hr> <!-- Thematic break / horizontal rule -->
science
Interactive: Heading Hierarchy Preview
Select a heading level and type your text. Click Add to build a heading hierarchy. Notice how each level gets progressively smaller - this visual hierarchy matches the semantic importance.
Add headings above to build a hierarchy…
format_bold
Text Formatting & Comments
HTML
HTML provides elements for giving text semantic meaning
beyond just visual appearance. <strong> marks text as
important (browsers render it bold, but screen readers
also emphasise it). <em> marks text as
emphasised (rendered italic, but with vocal stress in screen
readers). These are different from <b> (bold) and
<i> (italic), which are purely visual with no
semantic meaning.
HTML comments (<!-- ... -->) are
invisible to users but visible in the source code. They are essential
for documenting your code, temporarily disabling elements during
debugging, and leaving notes for other developers (or your future self).
<!-- ===== SEMANTIC formatting (preferred) ===== -->
<p><strong>Important:</strong> Submit your assignment by Friday.</p>
<p>Read the <em>entire</em> brief before starting.</p>
<!-- ===== Additional formatting elements ===== -->
<p><mark>Highlighted text</mark> draws attention.</p>
<p><del>Deleted text</del> and <ins>inserted text</ins>.</p>
<p>H<sub>2</sub>O is water. E = mc<sup>2</sup>.</p>
<p><code>console.log()</code> is an inline code snippet.</p>
<!-- ===== VISUAL-ONLY formatting (use sparingly) ===== -->
<p><b>Bold (no semantic meaning)</b></p>
<p><i>Italic (no semantic meaning)</i></p>
<!-- This is an HTML comment - invisible to users -->
<!-- TODO: Add the contact form here -->
<!-- <p>This paragraph is commented out / disabled.</p> -->
science
Interactive: Text Formatting Preview
Type text and click a formatting tag to see it rendered and view the generated HTML code.
format_list_bulleted
Lists - Ordered, Unordered & Description
HTML
HTML provides three types of lists. Unordered lists
(<ul>) display bullet points - use them when
the order doesn't matter. Ordered lists
(<ol>) display numbered items - use them for
step-by-step instructions, rankings, or sequences. Description
lists (<dl>) pair terms with their
definitions - use them for glossaries, FAQs, or metadata. Lists
can also be nested (a list inside another list) to
create multi-level hierarchies.
<!-- Unordered list (bullet points) -->
<ul>
<li>HTML - structure</li>
<li>CSS - style</li>
<li>JavaScript - interactivity</li>
</ul>
<!-- Ordered list (numbered) -->
<ol>
<li>Plan your layout</li>
<li>Write the HTML structure</li>
<li>Add CSS styling</li>
<li>Add JavaScript interactivity</li>
</ol>
<!-- Nested list -->
<ul>
<li>Front-end
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
</li>
<li>Back-end
<ul>
<li>Node.js</li>
<li>Python</li>
</ul>
</li>
</ul>
<!-- Description list (term + definition pairs) -->
<dl>
<dt>HTML</dt>
<dd>HyperText Markup Language - structures web content.</dd>
<dt>CSS</dt>
<dd>Cascading Style Sheets - controls visual presentation.</dd>
</dl>
science
Interactive: List Type Comparison
Click a list type to see it rendered and view the HTML code.
code_blocks
HTML Entities & Special Characters
HTML
Some characters have special meaning in HTML - for example,
< starts a tag, > ends one, and
& begins an entity reference. To display these
characters as visible text rather than HTML code, you must
use character entities. Entities start with
& and end with ;. Without them, the
browser will try to interpret the characters as HTML, which either
breaks your page or creates a W3C validation error.
Every valid HTML5 document starts with a <!DOCTYPE html>
declaration, which tells the browser to use the latest rendering mode
instead of falling back to legacy "quirks mode". Inside the
<head>, meta tags provide critical information:
charset sets the character encoding (always use UTF-8),
and the viewport meta tag enables responsive design on
mobile devices. Omitting these tags is a common beginner mistake that
leads to broken layouts on phones and garbled special characters.
<!-- The DOCTYPE is required - without it, browsers fall into
"quirks mode" and rendering becomes unpredictable. -->
<!DOCTYPE html>
<html lang="en">
<head>
<!-- UTF-8 supports every human language and emoji -->
<meta charset="UTF-8">
<!-- This meta tag makes the page responsive on mobile.
Without it, phones render the page at desktop width
and force the user to pinch-zoom. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- The title appears in browser tabs and search-engine results -->
<title>My First Page</title>
<!-- External stylesheet link (keeps HTML and CSS separated) -->
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h1>Hello, World!</h1>
<p>This is my first web page.</p>
<!-- Scripts load at the bottom so the HTML renders first -->
<script src="js/app.js"></script>
</body>
</html>
accessibility_new
Semantic HTML & Why It Matters
Best Practice
HTML5 introduced semantic elements - tags whose names
describe the role of their content, not just its appearance.
Using <nav> instead of <div class="nav">
tells the browser, screen readers, and search engines that the section
is a navigation block. This matters because:
Accessibility: Screen readers can jump between <main>, <nav>, and <aside> landmarks, letting visually-impaired users navigate efficiently.
SEO: Search engines rank pages higher when they can identify headings, articles, and navigation clearly.
Maintainability: When another developer reads <article>, they instantly know the section is a self-contained piece of content - no guessing required.
Every HTML element has a default display behaviour
that determines how it flows within the page. Understanding the
difference between block and inline
elements is essential - it controls whether elements stack vertically
or sit side-by-side, and what CSS properties (like width,
height, and margin) you can apply to them.
Block elements (<div>, <p>, <h1>–<h6>, <section>, <ul>) start on a new line and stretch to fill the full width of their parent container. You can set width, height, margin, and padding on all four sides.
Inline elements (<span>, <a>, <strong>, <em>, <code>, <img>) flow within a line of text and only take up as much width as their content. Vertical margin and explicit width/height have no effect on inline elements.
Inline-block combines both: the element flows inline but accepts width, height, and vertical margins - useful for buttons and badges.
<!-- Block elements stack vertically -->
<div class="card">
<h2>Block-level heading</h2> <!-- takes full width, new line -->
<p>Block-level paragraph.</p> <!-- takes full width, new line -->
</div>
<!-- Inline elements sit side-by-side within text -->
<p>
Visit <a href="/about">our about page</a> for
<strong>more info</strong> and <em>examples</em>.
</p>
<!-- Inline-block: flows inline but accepts width/height -->
<span style="display: inline-block; width: 100px; height: 30px;
background: teal; color: white; text-align: center;
line-height: 30px; border-radius: 4px;">
Badge
</span>
science
Interactive: Element Flow Playground
Add block, inline, and inline-block elements to see how they flow on the page.
link
Attributes, Links & Images
HTML
HTML attributes provide extra information about
elements and are written inside the opening tag. Some attributes are
universal (available on every element), while others are specific to
certain tags. Getting attributes right is critical - for example, a
missing alt attribute on an image means screen readers
cannot describe the image to blind users, and a missing href
means a link goes nowhere.
Global attributes work on any element: id, class, style, title, data-* (custom data), hidden, tabindex.
Boolean attributes (required, disabled, checked, hidden) are true just by being present - they don't need a value.
<a href> creates hyperlinks. Use target="_blank" with rel="noopener noreferrer" for security when opening external links in new tabs.
<img> always needs src (the file path) and alt (a description). For responsive images, add loading="lazy" and use the srcset attribute to serve different sizes.
<!-- Global attributes: id, class, data-*, title -->
<section id="features" class="container" data-section="2"
title="Product features">
<h2>Features</h2>
</section>
<!-- Links: internal, external, and anchor -->
<a href="/about">Internal link (same site)</a>
<!-- External link: opens in new tab securely -->
<a href="https://developer.mozilla.org"
target="_blank"
rel="noopener noreferrer">
MDN Web Docs ↗
</a>
<!-- Anchor link: scrolls to the element with id="features" -->
<a href="#features">Jump to Features</a>
<!-- Images: always include meaningful alt text -->
<img src="images/hero.jpg"
alt="Developer working at a laptop in a modern office"
width="800" height="450"
loading="lazy">
<!-- Responsive image: serve different files by screen size -->
<img srcset="images/hero-480.jpg 480w,
images/hero-800.jpg 800w,
images/hero-1200.jpg 1200w"
sizes="(max-width: 600px) 480px,
(max-width: 1000px) 800px,
1200px"
src="images/hero-800.jpg"
alt="Responsive hero image example">
<!-- Boolean attributes: just present = true -->
<input type="email" required disabled>
<!-- ↑ required and disabled have no ="value" needed -->
table_chart
Forms, Tables & Multimedia
HTML
Beyond basic text and images, HTML provides powerful elements for
collecting user input, displaying tabular data, and embedding media.
Proper use of <label> elements linked to inputs via
the for attribute is essential - it makes forms usable
for keyboard-only and screen-reader users. Similarly, tables should
always include <thead> and <th scope>
so assistive technologies can read column headers aloud.
<!-- Accessible form: every input has a linked label,
required fields are marked, and inputs use the correct type
so mobile keyboards show the right layout. -->
<form action="/register" method="POST">
<fieldset>
<legend>Create an Account</legend>
<label for="email">Email address</label>
<input type="email" id="email" name="email"
placeholder="you@example.com" required>
<label for="password">Password (min 8 characters)</label>
<input type="password" id="password" name="password"
minlength="8" required>
<label for="dob">Date of birth</label>
<input type="date" id="dob" name="dob">
<button type="submit">Register</button>
</fieldset>
</form>
<!-- Accessible table with scope attributes -->
<table>
<caption>Browser Market Share – 2025</caption>
<thead>
<tr>
<th scope="col">Browser</th>
<th scope="col">Share</th>
</tr>
</thead>
<tbody>
<tr><td>Chrome</td><td>65%</td></tr>
<tr><td>Safari</td><td>19%</td></tr>
<tr><td>Firefox</td><td>3%</td></tr>
</tbody>
</table>
<!-- Responsive video embed -->
<video controls width="100%" poster="thumb.jpg">
<source src="intro.mp4" type="video/mp4">
Your browser does not support the video element.
</video>
science
Interactive: Live Form with HTML5 Validation
Try filling out the form below. HTML5 validation attributes (required, type="email", minlength) provide built-in checking - no JavaScript needed for basic validation. Click Submit to test it, or type in the fields to see real-time feedback.
edit_note
Try It Yourself - Live HTML Editor
Interactive
Edit the HTML below and click Run to render it live.
Try adding new elements like <img>,
<table>, or <form> to see how
the browser displays them. This is the fastest way to build intuition
for how HTML tags translate into visible content.
science
Interactive: Live HTML Editor
Write HTML in the editor and click Run to see it rendered live.
Always include <!DOCTYPE html>, charset, and viewport meta tags - they prevent layout and encoding bugs.
Choose semantic elements (<nav>, <main>, <article>) over generic <div> tags for better accessibility and SEO.
Understand block vs inline: block elements stack and accept width/height; inline elements flow within text and ignore vertical margin.
Use correct attributes: alt on every image, rel="noopener noreferrer" on external target="_blank" links, and loading="lazy" for off-screen images.
Link every <label> to its input with the for attribute - this is not optional for accessible forms.
Use <thead> and <th scope> in tables so screen readers can announce column headers.
Use HTML5 validation attributes (required, type="email", minlength) for client-side form validation before JavaScript is even needed.
Validate your HTML using the W3C validator to catch errors early.
flag
Learning Objectives
By the end of this section you will be able to:
Write CSS rules using element, class, ID, and combinatory selectors.
Explain the box model and why box-sizing: border-box prevents layout surprises.
Use Flexbox and Grid to build responsive, modern layouts.
Understand the cascade and specificity to debug style conflicts.
Use position (relative, absolute, fixed, sticky) to place elements precisely.
Build mobile-first responsive designs using media queries.
Choose the right CSS units (rem, em, %, vh/vw) for scalable designs.
Add smooth transitions, keyframe animations, and CSS custom properties for theming.
palette
What is CSS?
CSS
CSS (Cascading Style Sheets) controls the visual presentation
of HTML elements - colours, fonts, spacing, layout, and animations.
By separating content (HTML) from presentation (CSS), you can
completely redesign a website without touching any HTML. This
separation is a core principle of web development because it makes
sites easier to maintain, faster to update, and more accessible.
Why does this matter? Imagine a site with 50 pages.
Without CSS, every visual change means editing all 50 HTML files.
With one shared stylesheet, a single line change - say, updating
a brand colour - propagates instantly across the entire site.
Selectors target which HTML elements to style (e.g., p, .card, #hero).
Properties define what to change (e.g., color, font-size, margin).
Values specify the desired setting (e.g., red, 1.5rem, 24px).
The cascade determines which rule wins when multiple rules target the same element - specificity and source order matter.
science
Interactive: CSS On / Off - See the Difference
Toggle CSS on and off to see how the same HTML looks with and without styling. This demonstrates exactly what CSS does - it transforms raw, unstyled content into a polished, readable layout.
colorize
Colours - RGB, HEX & HSL
CSS
CSS supports multiple colour formats. Named colours
(red, teal) are readable but limited to
~140 options. HEX (#1a6b52) is the most
common format - 6 hex digits representing red, green, and blue.
RGB (rgb(26, 107, 82)) uses decimal
values 0–255 for each channel. HSL
(hsl(155, 61%, 26%)) defines hue (0–360°), saturation
(0–100%), and lightness (0–100%) - it is the most intuitive for
choosing colour variations because you can adjust lightness and
saturation independently. All three formats also support an
alpha channel for transparency (e.g.,
rgba(), hsla(), or 8-digit hex).
Typography controls how text looks and reads. The key properties are
font-family (the typeface), font-size
(how big), font-weight (how bold), line-height
(vertical spacing between lines), text-align (left, center,
right, justify), and text-decoration (underline, strikethrough).
Good typography makes content readable and
scannable - a page with 1.6 line-height and proper
heading sizes is dramatically easier to read than one with default spacing.
/* Font stack - fallback chain from specific to generic */
body {
font-family: "Outfit", "Helvetica Neue", Arial, sans-serif;
font-size: 1rem; /* 16px default */
font-weight: 400; /* Normal weight */
line-height: 1.6; /* 1.6x the font size - optimal for readability */
color: #333;
}
h1 {
font-size: 2.5rem; /* 40px */
font-weight: 700; /* Bold */
line-height: 1.2; /* Tighter for headings */
letter-spacing: -0.5px; /* Slightly tighter tracking */
}
a {
text-decoration: none; /* Remove default underline */
color: teal;
}
a:hover {
text-decoration: underline; /* Underline on hover for clarity */
}
.caption {
font-size: 0.75rem;
font-style: italic;
text-transform: uppercase; /* ALL CAPS */
letter-spacing: 1px;
}
gradient
Backgrounds & Gradients
CSS
CSS backgrounds go far beyond solid colours. You can apply images,
gradients, and even multiple layered backgrounds to any element.
Linear gradients transition between colours along a
straight line. Radial gradients radiate from a center
point. Combining backgrounds with background-size,
background-position, and background-repeat
gives you full control over how images and patterns fill their container.
/* Solid colour */
background-color: #f0f4f8;
/* Linear gradient - direction + colour stops */
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
/* Radial gradient - centre outward */
background: radial-gradient(circle, #ffecd2 0%, #fcb69f 100%);
/* Background image with cover sizing */
background-image: url("hero.jpg");
background-size: cover; /* Scale to fill container */
background-position: center; /* Centre the image */
background-repeat: no-repeat;
/* Multiple backgrounds (layered, first on top) */
background:
linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4)),
url("hero.jpg") center / cover no-repeat;
tune
Selectors & Specificity
CSS
CSS offers many ways to target elements. Understanding
specificity - the system that decides which rule wins
when two rules compete - is crucial. Specificity is calculated as a
three-part score: IDs > Classes > Elements. The higher
the score, the more weight a rule carries. Knowing this saves hours of
frustration wondering "why isn't my style applying?"
/* ===== ELEMENT SELECTOR (specificity 0-0-1) =====
Targets every <p> on the page.
Low specificity - easy to override. */
p {
color: #333;
line-height: 1.6;
}
/* ===== CLASS SELECTOR (specificity 0-1-0) =====
Targets any element with class="highlight".
Best practice: prefer classes over IDs for styling
because they are reusable across many elements. */
.highlight {
background-color: #fff3cd;
padding: 4px 8px;
border-radius: 4px;
}
/* ===== ID SELECTOR (specificity 1-0-0) =====
Targets the ONE element with id="page-title".
Very high specificity - hard to override later.
Best practice: avoid IDs for styling; use them for
JS hooks and anchor links instead. */
#page-title {
font-size: 2rem;
font-weight: bold;
}
/* ===== COMBINATORS =====
Descendant selector: only <a> tags inside <nav> */
nav a {
text-decoration: none;
color: teal;
transition: color 0.2s ease;
}
/* Pseudo-class: style on hover state */
nav a:hover {
color: darkcyan;
text-decoration: underline;
}
/* ===== SPECIFICITY IN ACTION =====
Both rules target the same element:
.card p → specificity 0-1-1
p.intro → specificity 0-1-1 (tie → last one wins)
#hero .card p → specificity 1-1-1 (highest → always wins) */
check_box_outline_blank
The Box Model
Core Concept
Every HTML element is rendered as a rectangular box
with four layers: content (the text or image),
padding (space between content and border),
border (the visible edge), and
margin (space outside the border separating elements).
Why box-sizing: border-box matters:
By default, width only controls the content area - padding
and border are added on top, making elements wider than
expected. Setting box-sizing: border-box includes padding
and border within the declared width, which makes layout calculations
predictable. Most modern CSS resets apply this globally.
/* Apply border-box globally - this is considered
best practice in every modern project. */
*, *::before, *::after {
box-sizing: border-box;
}
.card {
width: 300px; /* Total width = 300px (including padding + border) */
padding: 20px; /* Inner spacing */
border: 2px solid #ccc;
margin: 16px auto; /* 16px vertical gap; auto centres horizontally */
border-radius: 12px; /* Rounded corners */
}
deployed_code
Interactive Box Model Visualiser
Use the buttons to adjust padding and margin on the box below.
Watch how each layer of the box model grows and shrinks in real time.
margin
padding
Content Area
padding: 20px; margin: 16px;
grid_view
Layout with Flexbox & Grid
CSS
Before Flexbox and Grid, developers used floats and absolute positioning
to build layouts - techniques that were fragile and hard to maintain.
Flexbox handles one-dimensional layouts (rows or
columns), while CSS Grid handles two-dimensional layouts
(rows and columns simultaneously). Choosing the right tool
means your layouts will be responsive, readable, and far easier to debug.
/* ===== FLEXBOX: Navigation bar =====
Items flow in a row, centred vertically,
with equal spacing between them. */
.navbar {
display: flex;
align-items: center; /* vertical centre */
justify-content: space-between;
padding: 12px 24px;
gap: 16px; /* space between flex children */
}
/* Make the nav responsive: stack vertically on small screens */
@media (max-width: 600px) {
.navbar {
flex-direction: column;
align-items: flex-start;
}
}
/* ===== CSS GRID: Card gallery =====
Auto-fill columns that are at least 280px wide.
The grid adapts from 1 to 3+ columns automatically. */
.card-gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 24px;
padding: 24px;
}
/* Span a featured card across two columns on wide screens */
.card-gallery .featured {
grid-column: span 2;
}
science
Interactive: Flexbox Playground
Change the Flexbox properties below and watch how the child items rearrange in real time. This is the fastest way to build intuition for justify-content, align-items, and flex-direction.
A
B
C
D
open_with
CSS Positioning
CSS
The position property controls how an element is
placed within the document flow. Understanding the five positioning modes
is essential for building overlays, sticky headers, tooltips, and any
layout where elements need to overlap or break out of normal flow.
static - the default. Elements follow normal document flow. top/left/right/bottom have no effect.
relative - the element stays in normal flow but can be offset from its original position. Crucially, it creates a positioning context for absolute children.
absolute - the element is removed from flow and positioned relative to its nearest positioned ancestor (not static). If none exists, it positions relative to the <html> element.
fixed - removed from flow and positioned relative to the viewport. It stays in place even when the user scrolls (used for sticky navbars and floating buttons).
sticky - a hybrid: the element scrolls normally until it reaches a specified offset, then "sticks" in place. Useful for table headers and section labels.
/* ===== RELATIVE + ABSOLUTE: Parent-child positioning =====
The parent is 'relative' so the child's 'absolute'
position is calculated from the parent, not the page. */
.tooltip-wrapper {
position: relative; /* Creates positioning context */
}
.tooltip {
position: absolute;
bottom: 100%; /* Place above the parent */
left: 50%;
transform: translateX(-50%); /* Centre horizontally */
background: #333;
color: #fff;
padding: 8px 12px;
border-radius: 6px;
white-space: nowrap;
display: none; /* Hidden by default */
}
.tooltip-wrapper:hover .tooltip {
display: block; /* Show on hover */
}
/* ===== FIXED: Sticky navigation bar =====
Stays at the top of the viewport during scroll. */
.navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000; /* Ensure it overlaps other content */
background: white;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
/* ===== STICKY: Section header sticks while scrolling =====
Scrolls normally until 0px from the top, then sticks. */
.section-header {
position: sticky;
top: 0;
background: white;
padding: 12px 0;
z-index: 10;
}
science
Interactive: Position Mode Playground
Change the position mode of the target box below. The grey parent has position: relative so it acts as the positioning context. Adjust the top and left offsets with the sliders.
position
top: 20px
left: 20px
parent (position: relative)
Sibling before
Target Box
Sibling after
devices
Responsive Design & Media Queries
CSS
Responsive design ensures your website looks and works
well on every screen size - from phones to ultra-wide monitors.
The key tool is the @media rule, which lets you apply
CSS conditionally based on viewport width, orientation, or other
features. Combined with fluid layouts (Flexbox, Grid, percentage widths)
and the viewport meta tag in HTML, media queries let you
build a single codebase that adapts to all devices.
Mobile-first approach: write your base CSS for small
screens, then use min-width media queries to add complexity
for larger screens. This is the industry standard because it keeps the
base styles simple and loads less CSS on slower mobile connections.
Choosing the right CSS unit is important for building layouts that scale
correctly across devices and respect user preferences. A common mistake
is using px for everything - this ignores the user's browser
font-size settings and creates rigid layouts that don't adapt.
px - absolute pixels. Use for borders, shadows, and small fixed details. Avoid for font sizes and layout widths.
rem - relative to the root (<html>) font size (usually 16px). Best for font sizes, spacing, and component sizing because it scales with user preferences.
em - relative to the parent element's font size. Useful for padding/margin that should scale with text, but compounds in nested elements (1.2em inside 1.2em = 1.44× the root).
% - relative to the parent's dimension. Ideal for fluid widths (width: 100%) and responsive images.
vh / vw - 1% of viewport height/width. Great for full-screen sections (min-height: 100vh) and hero banners.
ch - width of the "0" character. Perfect for setting readable line lengths (max-width: 65ch).
/* Best practice: use rem for type and spacing, % or viewport
units for layout, and px only for fine details. */
html {
font-size: 16px; /* 1rem = 16px (browser default) */
}
body {
font-size: 1rem; /* 16px - scales with user settings */
line-height: 1.6; /* Unitless - multiplier of font-size */
}
h1 { font-size: 2.5rem; } /* 40px at default, but scales */
h2 { font-size: 1.75rem; } /* 28px at default */
.container {
max-width: 65ch; /* ~65 characters wide - optimal readability */
padding: 2rem; /* Scales with root font size */
margin: 0 auto;
}
.hero {
min-height: 100vh; /* Full viewport height */
padding: 5vw; /* Responsive padding */
}
.border-detail {
border: 1px solid #ccc; /* px is fine for thin borders */
box-shadow: 0 2px 8px rgba(0,0,0,0.12); /* px for shadows */
}
animation
Transitions, Animations & Custom Properties
CSS
Transitions smoothly animate property changes between
two states (e.g., hover effects). Keyframe animations
allow multi-step, repeating, or auto-playing sequences. Both are
performant because the browser's compositor handles them - they run
at 60fps without blocking JavaScript.
CSS custom properties (variables) let you define
reusable values with --name: value and reference them
with var(--name). They cascade like regular properties
and can be changed dynamically with JavaScript, making them perfect
for theming and design tokens.
Write CSS rules in the editor and click Run to apply
them to the preview below. Try changing color,
font-family, display: flex, or
border-radius. Notice how the styles scope only to the
preview area without affecting the rest of the page.
science
Interactive: Live CSS Editor
Edit the CSS and click Run to see it applied to the sample HTML below.
Prefer class selectors over IDs for styling - they are reusable and have lower specificity, making overrides easier.
Always set box-sizing: border-box globally to avoid unexpected width calculations.
Use Flexbox for one-dimensional flows (navigation bars, centering) and Grid for two-dimensional layouts (card galleries, dashboards).
Understand position - use relative as a container for absolute children, fixed for viewport-locked elements, and sticky for scroll-aware headers.
Build mobile-first: write base styles for small screens, then add complexity with @media (min-width: ...) queries.
Use rem for font sizes and spacing, % or vw/vh for layout, and px only for fine details like borders.
Define reusable values with CSS custom properties (--name: value) and always respect prefers-reduced-motion for accessibility.
When a style "isn't working," check specificity first - a more specific rule elsewhere is probably winning the cascade.
flag
Learning Objectives
By the end of this section you will be able to:
Declare variables with const and let and explain why var is avoided.
Write functions (including arrow functions) and understand scope.
Use conditionals (if/else, switch, ternary) and loops (for, for...of, while).
Work with objects, destructuring, the spread operator, and template literals.
Select and modify DOM elements using both vanilla JS and jQuery.
Handle user events (click, input, submit) to build interactive UIs.
Handle errors gracefully with try/catch and throw custom errors.
Use Promises, fetch(), and async/await for asynchronous operations.
bolt
What is JavaScript?
JavaScript
JavaScript (JS) is the programming language of the web. While HTML
defines what content exists and CSS defines how
it looks, JavaScript defines what happens when users interact
with the page - clicking buttons, submitting forms, scrolling, typing,
or receiving new data from a server.
Why does this matter? Without JavaScript, web pages
are static documents. JS transforms them into applications -
think of Google Maps, Spotify Web Player, or online banking. It is the
only programming language that runs natively in every web browser,
making it an essential skill for any web developer.
JS runs in the browser's JavaScript engine (e.g., V8 in Chrome) - no compilation step needed.
It is dynamically typed: variables can hold any data type without a type declaration.
Event-driven: code executes in response to user actions or system events, not just top-to-bottom.
The DOM API lets JS read and modify every element on the page in real time.
data_object
Variables, Scope & Functions
JavaScript
Modern JavaScript uses const (for values that never change)
and let (for values that need reassignment). The older
var keyword is avoided because it is function-scoped
rather than block-scoped, which leads to subtle bugs in loops and
conditionals. This is one of the most important best practices in JS.
// ===== VARIABLES & SCOPE =====
const TAX_RATE = 0.1; // const – value never changes
let cartTotal = 0; // let – will be updated later
// var is function-scoped - DO NOT use in modern code:
// for (var i = 0; i < 3; i++) { ... }
// console.log(i); // 3 ← leaked outside the loop!
// let is block-scoped - stays inside its block:
// for (let j = 0; j < 3; j++) { ... }
// console.log(j); // ReferenceError ← correct behaviour
// ===== FUNCTIONS =====
// Traditional function declaration
function calculateTotal(price, quantity) {
const subtotal = price * quantity;
const tax = subtotal * TAX_RATE;
return subtotal + tax;
}
// Arrow function (concise ES6+ syntax)
const formatCurrency = (amount) => `$${amount.toFixed(2)}`;
// Using both together
const total = calculateTotal(29.99, 3);
console.log(formatCurrency(total)); // "$98.97"
// ===== ARRAYS & HIGHER-ORDER FUNCTIONS =====
const products = [
{ name: "Laptop", price: 999 },
{ name: "Mouse", price: 29 },
{ name: "Monitor", price: 449 },
];
// .filter() returns a new array of items matching the condition
const affordable = products.filter(p => p.price < 500);
// .map() transforms each item into a new value
const names = products.map(p => p.name);
// .reduce() accumulates values into a single result
const totalPrice = products.reduce((sum, p) => sum + p.price, 0);
console.log(affordable); // [{name:"Mouse",...}, {name:"Monitor",...}]
console.log(names); // ["Laptop", "Mouse", "Monitor"]
console.log(totalPrice); // 1477
alt_route
Control Flow - Conditionals & Loops
JavaScript
Control flow statements let your code make decisions
(if/else, switch) and
repeat actions (for, while,
for...of). Without these, programs could only execute
the same sequence every time. They are the backbone of any interactive
feature - validating form input, filtering a list, processing quiz
answers, or retrying a network request.
// ===== CONDITIONALS =====
const score = 82;
// if / else if / else - the most common branching pattern
if (score >= 90) {
console.log("Grade: A");
} else if (score >= 80) {
console.log("Grade: B"); // ← this runs
} else if (score >= 70) {
console.log("Grade: C");
} else {
console.log("Grade: F");
}
// Ternary operator - concise for simple conditions
const status = score >= 60 ? "Pass" : "Fail";
console.log(status); // "Pass"
// switch - cleaner when comparing one value against many options
const day = "Monday";
switch (day) {
case "Monday":
case "Tuesday":
case "Wednesday":
case "Thursday":
case "Friday":
console.log("Weekday");
break;
case "Saturday":
case "Sunday":
console.log("Weekend");
break;
default:
console.log("Invalid day");
}
// ===== LOOPS =====
// for loop - when you know the number of iterations
for (let i = 0; i < 5; i++) {
console.log("Iteration", i); // 0, 1, 2, 3, 4
}
// for...of - iterate over array values (ES6+, preferred)
const colours = ["red", "green", "blue"];
for (const colour of colours) {
console.log(colour);
}
// while - when the number of iterations is unknown
let attempts = 0;
while (attempts < 3) {
console.log("Attempt", attempts + 1);
attempts++;
}
// .forEach() - array method (functional style, no break/continue)
colours.forEach((colour, index) => {
console.log(`${index + 1}. ${colour}`);
});
science
Interactive: Grade Calculator (Conditionals in Action)
Enter a numeric score and click Calculate. The JavaScript behind this uses an if / else if / else chain - the exact same pattern from the code snippet above - to determine the letter grade in real time.
category
Objects, Data Types & Template Literals
JavaScript
JavaScript has primitive types (string,
number, boolean, null,
undefined, symbol, bigint)
and one structural type: objects. Arrays, functions,
dates, and regular expressions are all objects under the hood.
Understanding data types prevents bugs like accidentally concatenating
numbers as strings or comparing values with the wrong operator.
Template literals (backtick strings) let you embed
expressions directly inside strings using ${...} syntax.
They also support multi-line strings without escape characters - a
significant improvement over traditional string concatenation.
// ===== DATA TYPES =====
const name = "Alice"; // string
const age = 28; // number
const active = true; // boolean
const score = null; // null (intentionally empty)
let role; // undefined (not yet assigned)
// typeof checks the type at runtime
console.log(typeof name); // "string"
console.log(typeof age); // "number"
console.log(typeof active); // "boolean"
// ⚠ Comparison: always use === (strict) instead of == (loose)
console.log(0 == "0"); // true ← type coercion, dangerous!
console.log(0 === "0"); // false ← strict, no coercion, safe
// ===== OBJECTS =====
// Objects store key-value pairs (properties and methods)
const user = {
firstName: "Alice",
lastName: "Chen",
age: 28,
skills: ["HTML", "CSS", "JavaScript"],
// Method: a function that belongs to the object
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
};
// Accessing properties
console.log(user.firstName); // "Alice"
console.log(user["lastName"]); // "Chen" (bracket notation)
console.log(user.getFullName()); // "Alice Chen"
// Destructuring: extract properties into variables
const { firstName, skills } = user;
console.log(firstName); // "Alice"
console.log(skills[0]); // "HTML"
// Spread operator: copy and extend objects
const updatedUser = { ...user, age: 29, role: "Developer" };
// ===== TEMPLATE LITERALS =====
// Use backticks (`) instead of quotes for embedded expressions
const greeting = `Hello, ${user.getFullName()}!
You have ${user.skills.length} skills listed.
Your profile is ${user.active !== false ? "active" : "inactive"}.`;
console.log(greeting);
// "Hello, Alice Chen!
// You have 3 skills listed.
// Your profile is active."
text_snippet
String Methods
JavaScript
Strings are one of the most commonly used data types. JavaScript
provides dozens of built-in methods to search, extract, transform,
and split strings. Since strings are immutable
(they cannot be changed in place), every method returns a
new string rather than modifying the original.
const msg = " Hello, World! ";
// Length (property, not a method)
msg.length; // 19
// Trimming whitespace
msg.trim(); // "Hello, World!"
// Case conversion
msg.trim().toUpperCase(); // "HELLO, WORLD!"
msg.trim().toLowerCase(); // "hello, world!"
// Searching
msg.includes("World"); // true
msg.indexOf("World"); // 9 (position, or -1 if not found)
msg.startsWith(" Hello"); // true
// Extracting substrings
msg.trim().slice(0, 5); // "Hello"
msg.trim().slice(7); // "World!"
// Replacing
msg.trim().replace("World", "JavaScript"); // "Hello, JavaScript!"
msg.trim().replaceAll("l", "L"); // "HeLLo, WorLd!"
// Splitting into an array
"HTML,CSS,JS".split(","); // ["HTML", "CSS", "JS"]
"Hello World".split(" "); // ["Hello", "World"]
// Joining an array back into a string
["HTML", "CSS", "JS"].join(" & "); // "HTML & CSS & JS"
// Padding
"5".padStart(3, "0"); // "005"
// Template literal with expressions
const name = "Alice";
`Hello, ${name.toUpperCase()}!`; // "Hello, ALICE!"
account_tree
DOM Manipulation
JavaScript
The Document Object Model (DOM) is the browser's
in-memory representation of the HTML page. JavaScript can select
elements, change their content and styles, create new elements, and
remove existing ones - all without reloading the page.
Best practice: minimise direct DOM manipulation.
Each time you change the DOM, the browser may need to recalculate
layout (called a "reflow"). Batch your changes or use
DocumentFragment to avoid performance issues on complex pages.
// ===== SELECTING ELEMENTS =====
const title = document.getElementById("main-title");
const cards = document.querySelectorAll(".card"); // NodeList
const firstP = document.querySelector("p"); // first match
// ===== MODIFYING CONTENT & STYLES =====
title.textContent = "Updated Title";
title.style.color = "#00695c";
// classList is safer than overwriting className directly
title.classList.add("highlight");
title.classList.toggle("hidden");
// ===== CREATING & APPENDING ELEMENTS =====
// Using DocumentFragment to batch-insert (avoids multiple reflows)
const fragment = document.createDocumentFragment();
const fruits = ["Apple", "Banana", "Cherry"];
fruits.forEach(fruit => {
const li = document.createElement("li");
li.textContent = fruit;
li.classList.add("fruit-item");
fragment.appendChild(li);
});
// Only ONE reflow when the fragment is appended
document.getElementById("fruit-list").appendChild(fragment);
// ===== EVENT LISTENERS =====
document.querySelector("#submitBtn")
.addEventListener("click", function(event) {
event.preventDefault(); // stop form from refreshing the page
const input = document.querySelector("#nameInput");
alert("Hello, " + input.value + "!");
});
science
Interactive: DOM Manipulation Playground
Use the buttons to add, style, rename, and remove elements in real time.
auto_awesome
jQuery - Simplified DOM & AJAX
jQuery
jQuery is a lightweight library that simplifies DOM manipulation,
event handling, and AJAX calls. While modern vanilla JS has caught
up in many areas, jQuery remains valuable for projects that need
broad browser compatibility and concise syntax. Its
$.ajax() method is particularly useful for loading
content dynamically - a technique used on the Quiz page of this
application.
// Wait for the DOM to be fully ready before running code
$(document).ready(function() {
// ===== SELECTING & MODIFYING =====
// jQuery wraps elements in a powerful object with chaining
$("h1")
.css("color", "#00695c")
.addClass("animated")
.attr("data-loaded", "true");
// ===== EVENT HANDLING =====
// .on() attaches events; supports delegation for dynamic content
$("#quiz-container").on("click", ".answer-btn", function() {
// 'this' refers to the clicked .answer-btn, even if it was
// added to the DOM after page load (event delegation).
$(this).addClass("selected");
$(".answer-btn").not(this).removeClass("selected");
});
// ===== AJAX: Load quiz data from a JSON file =====
$.ajax({
url: "data/questions.json",
method: "GET",
dataType: "json",
success: function(data) {
// data is already parsed as a JS object
console.log("Loaded " + data.length + " questions");
renderQuiz(data);
},
error: function(xhr, status, err) {
console.error("Failed to load quiz:", status, err);
$("#quiz-container").html(
"<p class='error'>Could not load questions. Please try again.</p>"
);
}
});
// ===== ANIMATION =====
$(".card").hide().fadeIn(600);
});
bug_report
Error Handling - try / catch / finally
JavaScript
Errors are inevitable in real applications - users enter invalid data,
network requests fail, and APIs return unexpected responses. The
try...catch statement lets you gracefully handle
errors instead of crashing the entire page. The optional finally
block runs regardless of success or failure, making it ideal for cleanup
tasks like hiding loading spinners.
// ===== BASIC TRY / CATCH =====
try {
// Code that might throw an error
const data = JSON.parse('{ invalid json }');
} catch (error) {
// Runs only if an error occurred in the try block
console.error("Parsing failed:", error.message);
// "Parsing failed: Expected property name or '}' ..."
} finally {
// Always runs - whether the try succeeded or failed
console.log("Cleanup: hiding loading spinner");
}
// ===== THROWING CUSTOM ERRORS =====
function divide(a, b) {
if (typeof a !== "number" || typeof b !== "number") {
throw new TypeError("Both arguments must be numbers");
}
if (b === 0) {
throw new RangeError("Cannot divide by zero");
}
return a / b;
}
try {
const result = divide(10, 0);
} catch (err) {
if (err instanceof RangeError) {
console.warn("Division error:", err.message);
} else {
console.error("Unexpected error:", err);
}
}
// ===== VALIDATING USER INPUT =====
function validateEmail(email) {
if (!email || !email.includes("@")) {
throw new Error("Please enter a valid email address");
}
return true;
}
try {
validateEmail("not-an-email");
} catch (err) {
// Display the error to the user in the UI
document.getElementById("error-msg").textContent = err.message;
}
data_object
JSON - Data Exchange Format
JavaScript
JSON (JavaScript Object Notation) is the standard
format for sending data between a server and a web browser. It looks
almost identical to JavaScript object syntax, but with two key
differences: all keys must be double-quoted strings,
and values can only be strings, numbers, booleans, null, arrays, or
nested objects (no functions, undefined, or comments).
JSON.parse() converts a JSON string into a JavaScript
object, and JSON.stringify() does the reverse.
// ===== JSON format (what you receive from an API) =====
// Keys MUST be double-quoted. No trailing commas.
const jsonString = `{
"name": "Alice",
"age": 28,
"active": true,
"skills": ["HTML", "CSS", "JavaScript"],
"address": {
"city": "Perth",
"country": "Australia"
}
}`;
// ===== JSON.parse() - String → Object =====
const user = JSON.parse(jsonString);
console.log(user.name); // "Alice"
console.log(user.skills[0]); // "HTML"
console.log(user.address.city);// "Perth"
// ===== JSON.stringify() - Object → String =====
const obj = { name: "Bob", score: 95 };
const str = JSON.stringify(obj);
console.log(str); // '{"name":"Bob","score":95}'
// Pretty-print with indentation (useful for debugging)
console.log(JSON.stringify(obj, null, 2));
// ===== Common use: localStorage =====
// localStorage only stores strings - use JSON to save objects
localStorage.setItem("user", JSON.stringify(user));
const loaded = JSON.parse(localStorage.getItem("user"));
sync
Async JavaScript - Promises, fetch & async/await
JavaScript
JavaScript is single-threaded - it can only execute
one thing at a time. To avoid freezing the UI while waiting for slow
operations (network requests, file reads, timers), JS uses
asynchronous patterns. A Promise
represents a value that will be available in the future. The modern
async/await syntax makes asynchronous code read like
synchronous code, which is much easier to understand and debug.
The fetch() API is the modern replacement for
XMLHttpRequest (and jQuery's $.ajax).
It returns a Promise and supports a clean, chainable syntax.
// ===== PROMISES =====
// A Promise is either: pending, fulfilled, or rejected.
const myPromise = new Promise((resolve, reject) => {
const success = true;
setTimeout(() => {
if (success) {
resolve("Data loaded!"); // fulfilled
} else {
reject("Network error"); // rejected
}
}, 1000);
});
// Consuming a promise with .then() and .catch()
myPromise
.then(data => console.log(data)) // "Data loaded!"
.catch(err => console.error(err))
.finally(() => console.log("Done")); // Always runs
// ===== FETCH API =====
// fetch() returns a Promise - the modern way to make HTTP requests.
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json(); // Parse the JSON body (also a Promise)
})
.then(post => {
console.log("Title:", post.title);
})
.catch(error => {
console.error("Fetch failed:", error.message);
});
// ===== ASYNC / AWAIT =====
// Syntactic sugar over Promises - reads top-to-bottom like sync code.
async function loadUser(userId) {
try {
const response = await fetch(
`https://jsonplaceholder.typicode.com/users/${userId}`
);
if (!response.ok) {
throw new Error(`User not found (HTTP ${response.status})`);
}
const user = await response.json();
console.log(`Loaded: ${user.name} (${user.email})`);
return user;
} catch (error) {
console.error("Failed to load user:", error.message);
return null;
}
}
// Call the async function
loadUser(1); // Logs: "Loaded: Leanne Graham (Sincere@april.biz)"
edit_note
Try It Yourself - JavaScript Sandbox
Interactive
Write JavaScript below and click Run to execute it.
Use output() instead of console.log() to
display results in the output panel. Try using .filter(),
.map(), or .reduce() on arrays!
science
Interactive: JavaScript Sandbox
Write JavaScript and click Run. Use output() instead of console.log() to see results.
bug_report
Debugging with Browser DevTools
JavaScript
Every modern browser includes Developer Tools (DevTools)
that let you inspect HTML, debug JavaScript, monitor network requests,
and profile performance. Knowing how to use DevTools is one of the most
important practical skills a web developer can have - it turns hours of
guessing into minutes of targeted diagnosis.
The Console is your primary debugging tool.
console.log() prints values for inspection,
console.error() highlights problems, and
console.table() formats arrays and objects as tables.
The Elements panel lets you inspect and live-edit
HTML and CSS. The Sources panel lets you set
breakpoints and step through JavaScript line by line.
// ===== CONSOLE METHODS =====
console.log("Simple message");
console.log("User:", user); // Inspect objects
console.error("Something went wrong"); // Red error styling
console.warn("Check this value"); // Yellow warning
// Table format for arrays/objects
console.table([
{ name: "Alice", score: 95 },
{ name: "Bob", score: 82 }
]);
// Group related logs together
console.group("Quiz Results");
console.log("Score: 12/15");
console.log("Percentage: 80%");
console.groupEnd();
// Measure execution time
console.time("AJAX load");
// ... some operation ...
console.timeEnd("AJAX load"); // "AJAX load: 245ms"
// ===== BREAKPOINTS =====
// In the Sources panel:
// 1. Click a line number to set a breakpoint
// 2. Reload or trigger the code path
// 3. Execution pauses at that line
// 4. Hover variables to see their current values
// 5. Use Step Over (F10), Step Into (F11), Continue (F8)
// Or use the debugger statement in code:
function calculateGrade(score) {
debugger; // Execution pauses here when DevTools is open
if (score >= 90) return "A";
if (score >= 80) return "B";
return "F";
}
Open DevTools: Press F12 or Ctrl+Shift+I (Windows/Linux) / Cmd+Option+I (Mac).
Console tab: Run JavaScript live, inspect variables, and see errors.
Elements tab: Inspect any element, live-edit CSS, and see computed styles.
Network tab: Monitor AJAX requests, check response status codes, and measure load times.
Application tab: Inspect localStorage, cookies, and sessionStorage.
touch_app
Event-Driven Programming
JavaScript
JavaScript is fundamentally event-driven: instead of
executing code from top to bottom in a fixed sequence, you register
listeners that wait for specific events to occur - a click,
a keystroke, a form submission, a page load, or data arriving from a
server. When the event fires, the browser calls your listener function.
This model is what makes web pages interactive.
The event loop is the mechanism behind this. JavaScript
runs a single thread that continuously checks a queue of pending events.
When your code finishes executing, the engine picks up the next event
in the queue and runs its handler. This is why long-running synchronous
code (like a heavy loop) freezes the UI - it blocks the event loop from
processing other events like clicks or scrolls.
// ===== EVENT LISTENERS =====
// Register a function that runs when a specific event occurs.
// The browser calls it automatically - you don't call it yourself.
const btn = document.querySelector("#submitBtn");
// addEventListener(eventType, handlerFunction)
btn.addEventListener("click", function(event) {
event.preventDefault(); // Stop the default browser action
console.log("Button clicked!");
console.log("Target element:", event.target);
});
// ===== COMMON EVENT TYPES =====
// Mouse: click, dblclick, mouseenter, mouseleave
// Keyboard: keydown, keyup, keypress
// Form: submit, change, input, focus, blur
// Window: load, resize, scroll, beforeunload
// Touch: touchstart, touchend, touchmove
// ===== EVENT DELEGATION =====
// Instead of attaching a listener to every child element,
// attach ONE listener to the parent. The event "bubbles up"
// from the clicked child to the parent. This is more efficient
// and works with dynamically added elements.
document.querySelector("#quiz-container")
.addEventListener("click", function(event) {
// event.target is the actual element that was clicked
if (event.target.classList.contains("answer-btn")) {
event.target.classList.add("selected");
}
});
// ===== jQuery EQUIVALENT =====
// .on() supports delegation via a second selector argument:
$("#quiz-container").on("click", ".answer-btn", function() {
$(this).addClass("selected");
// 'this' is the .answer-btn that was clicked,
// even if it was added to the DOM after page load.
});
// ===== THE EVENT OBJECT =====
// Every handler receives an Event object with useful properties:
document.addEventListener("keydown", function(e) {
console.log("Key pressed:", e.key); // "Enter", "a", "Escape"
console.log("Ctrl held?", e.ctrlKey); // true/false
console.log("Target:", e.target); // the focused element
if (e.key === "Escape") {
closeModal();
}
});
Event bubbling: Events propagate from the target element up through its ancestors. This is why event delegation works - a click on a child <button> also triggers click handlers on its parent <div>, <body>, etc.
event.preventDefault(): Stops the browser's default action (e.g., prevents a form from reloading the page on submit, or a link from navigating).
event.stopPropagation(): Stops the event from bubbling further up the DOM tree. Use sparingly - it can break other listeners that depend on bubbling.
Prefer .addEventListener() over onclick:addEventListener allows multiple listeners on the same element and keeps JS separate from HTML. Inline onclick attributes mix concerns and only allow one handler.
Event delegation for performance: Instead of 100 listeners on 100 list items, attach one listener to the <ul> parent and check event.target. This uses less memory and automatically works with dynamically added items.
bolt
JavaScript Cheatsheet
Quick Reference
Variables & Types
const name = "Alice"; // Cannot reassign (preferred default)
let count = 0; // Can reassign
// var - avoid (function-scoped, leaks out of blocks)
// Primitives: string, number, boolean, null, undefined, symbol, bigint
typeof "hello" // "string"
typeof 42 // "number"
typeof true // "boolean"
// Always use === (strict) instead of == (loose coercion)
Functions
// Declaration
function add(a, b) { return a + b; }
// Arrow function (ES6+)
const add = (a, b) => a + b;
// Default parameters
const greet = (name = "World") => `Hello, ${name}!`;
Control Flow
// Conditionals
if (x > 10) { } else if (x > 5) { } else { }
const result = x > 0 ? "positive" : "negative"; // ternary
// Loops
for (let i = 0; i < 5; i++) { }
for (const item of array) { }
while (condition) { }
array.forEach((item, index) => { });
Always use const by default; switch to let only when reassignment is necessary. Never use var.
Always use === (strict equality) instead of == to avoid type coercion bugs.
Prefer for...of for iterating arrays and .forEach()/.map()/.filter() for functional transformations.
Use .addEventListener() (or jQuery's .on()) instead of inline onclick attributes - it keeps HTML and JS separated and supports multiple listeners.
Minimise DOM updates by batching changes with DocumentFragment or building HTML strings before inserting.
Always wrap risky operations (JSON parsing, network calls, user input) in try/catch to prevent unhandled crashes.
Use async/await with fetch() for clean, readable asynchronous code - it is the modern replacement for callback-based patterns and $.ajax().
Prefer event delegation (attach one listener to a parent) over attaching listeners to each child - it is more memory-efficient and works with dynamically added elements.
Use DevTools (F12) to debug: console.log() for inspecting values, the Sources panel for breakpoints, and the Network tab for monitoring AJAX requests.
Ready to Test Your Knowledge?
You've covered HTML structure, CSS styling, and JavaScript interactivity.
Head to the quiz and put what you've learned to the test!