One-sentence summary
In this project lesson you will combine the semantic HTML, CSS layout, responsive design, a small piece of JavaScript and the accessibility ideas from this module into a single web page that introduces your own interests.
Why does it matter?
So far we have learned HTML, CSS and JavaScript separately. A real web page appears when these three parts work together. HTML carries the content, CSS gives the appearance, and JavaScript adds the behaviour.
Building a project from start to finish is different from solving small examples one by one. You decide what to do and in what order, how the page looks on a phone, and whether it is accessible to someone using a keyboard. This lesson helps you make those decisions in small, safe steps.
Step 1: Planning — what goes on the page?
Sketching the sections on paper before writing code makes the work easier. The goal is a single-page introduction to you.
An example plan:
1. Header: Short greeting + one-sentence introduction
2. About me: A few sentences
3. My hobbies: A card list (2–4 cards)
4. Hidden detail: A box opened with "Show more"
5. Footer: Who made the page (nickname)
Second example: a different interest
You can use the same skeleton for a different topic. If you are into basketball, the cards could be "My favourite position", "My training days" and "My goal". The skeleton stays the same; only the content changes.
Step 2: The semantic HTML skeleton
Semantic HTML means using tags with clear meaning instead of <div>: <header>, <main>, <section>, <footer>. These tags help screen readers understand the page correctly.
First the head of the document:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Interests</title>
<link rel="stylesheet" href="style.css">
</head>
The viewport line makes the page open at the correct scale on a phone; do not leave it out.
Then the body:
<body>
<header>
<h1>Hello, I am a student</h1>
<p>On this page I introduce the topics I enjoy.</p>
<button id="theme-button" type="button">Switch to dark theme</button>
</header>
<main>
<section aria-labelledby="hobbies-title">
<h2 id="hobbies-title">My hobbies</h2>
<ul class="cards">
<li>Robotics</li>
<li>Basketball</li>
<li>Reading</li>
</ul>
</section>
</main>
</body>
aria-labelledby tells assistive technology which heading names the section. If you add an image, remember to write its alt text:
<img src="robot.png" alt="Photo of the line-following robot I built">
Step 3: CSS layout and responsive design
If we define colours as CSS variables, switching themes becomes very easy. Variables live inside :root and are used with var().
:root {
--background: #ffffff;
--text: #1a1a1a;
--accent: #2563eb;
}
body {
font-family: system-ui, sans-serif;
background: var(--background);
color: var(--text);
margin: 0;
line-height: 1.6;
}
To centre the content and keep it at a readable width:
main {
max-width: 640px;
margin: 0 auto;
padding: 1rem;
}
Responsive means the page adjusts itself to the screen size. To stack cards on a narrow screen and place them side by side on a wide one, we use @media:
.cards {
list-style: none;
padding: 0;
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
}
@media (min-width: 600px) {
.cards {
grid-template-columns: 1fr 1fr;
}
}
For a dark theme, we change the variables when a class is added to body:
body.dark {
--background: #111827;
--text: #f3f4f6;
}
JavaScript will add and remove this class.
Step 4: JavaScript interaction
In modern JavaScript we use let and const and listen for events with addEventListener. We will add two small interactions: switching the theme and show-hide.
The theme button:
const button = document.getElementById("theme-button");
button.addEventListener("click", () => {
document.body.classList.toggle("dark");
const isDark = document.body.classList.contains("dark");
button.textContent = isDark ? "Switch to light theme" : "Switch to dark theme";
});
Now let us add a hidden detail to the HTML:
<button id="detail-button" type="button"
aria-expanded="false" aria-controls="detail">
Show more
</button>
<div id="detail" hidden>
<p>In the robotics club I am trying to build a line-following robot.</p>
</div>
And the code that opens and closes it:
const detailButton = document.getElementById("detail-button");
const detail = document.getElementById("detail");
detailButton.addEventListener("click", () => {
const isOpen = detail.hasAttribute("hidden") === false;
detail.toggleAttribute("hidden");
detailButton.setAttribute("aria-expanded", String(!isOpen));
});
Updating aria-expanded is important: this is how a screen reader knows whether the box is open or closed.
Hands-on practice
Combine the parts above and build your own page. Then try these test scenarios one by one:
- Open the page and narrow then widen the browser window. Do the cards stack on a narrow screen and sit side by side on a wide one?
- Press the theme button. Do the colours change and does the button text update?
- Press "Show more". Does the box open, and does it close on a second press?
- Without using the mouse, can you reach the buttons with only the
Tabkey and activate them withEnter?
One bug and its fix
On the first try the theme button did not work. The console showed this error:
Uncaught ReferenceError: dark is not defined
To find the problem we looked at the relevant line:
// Wrong: without quotes, dark is treated as a variable
document.body.classList.toggle(dark);
// Right: the class name is text and must be in quotes
document.body.classList.toggle("dark");
Class names are text; adding quotes fixed the error. Even a small mistake can stop a program.
Ideas to extend it
- Remember the chosen theme with
localStorageso it stays the same after a refresh. - Add a second section: "Things I want to learn".
- Add a small emoji or an image with
alttext to the cards.
Project strengthening plan
A working demonstration is not enough for Project: Personal Project Page. A strong project also makes its aim, user, limits, test conditions and failed attempts visible. Use the context of a page that explains the aim and test results of a robotics project to produce semantic HTML, organised CSS, small JavaScript where needed and an accessibility check. Although the lesson aims to “Combine semantic HTML, CSS, responsiveness and a little JavaScript into an accessible project page”, do not present an unmeasured result as a confirmed success.
1. Project summary and scope
Write three sentences: What problem are you solving, who is affected by it, and what will the first version deliberately not do? Stating what is outside the scope does not weaken a project; it makes the project finishable. Describe the connection between Step 1: Planning — what goes on the page? and Step 2: The semantic HTML skeleton as the main assumption, then name the test that can confirm or reject it.
2. Acceptance criteria
- Is the heading hierarchy logical?
- Do links work with keyboard and touch?
- Is there horizontal overflow on a mobile screen?
- Do images have alt text and dimensions?
- Are the responsibilities of HTML, CSS and JavaScript kept separate?
Do not leave an acceptance criterion for “Project: Personal Project Page” as a vague statement such as “it works”. Choose an observable measure such as time, distance, correct trials, screen width or user steps. When direct measurement is difficult, record whether the same behaviour appears in three consecutive trials.
3. Test matrix
| Test | Condition | Expected | Actual result | Next decision |
|---|---|---|---|---|
| Normal | Standard input and complete setup | The core task is completed | Fill in during the test | Keep it or make a small improvement |
| Boundary | Lowest or highest accepted value | The system remains stable | Fill in during the test | Review the threshold or rule |
| Error | Missing, wrong or unexpected input | A safe and clear response | Fill in during the test | Add error handling |
| Repeat | At least three trials under the same condition | Similar results | Fill in during the test | Investigate the source of inconsistency |
4. Version log
For every version of “Project: Personal Project Page”, record the date, the one main decision changed, the reason and the test result. A first version that fails is evidence about which assumption involving Step 1: Planning — what goes on the page? or Step 2: The semantic HTML skeleton should be reconsidered. Remove personal information and private background details from images.
5. Presentation and self-review
Prepare a two-minute explanation of “Project: Personal Project Page”: the problem, the solution approach, the most important result for a page that explains the aim and test results of a robotics project, and the next step. Instead of saying the project is complete, state which part has been verified and which part still needs development.
Common mistakes
Forgetting the viewport tag
Without this line the page looks tiny on a phone. Make sure it is inside <head>.
Not writing alt text for an image
If alt is empty, a user who cannot see the image will not know what it shows. Write a short, clear description.
Giving meaning through colour alone
Cues that rely only on colour, like "green box good, red box bad", cause trouble for colour-blind users. Use text in addition to colour.
Not updating aria-expanded
If you open and close the box but aria-expanded stays false, the screen reader gives wrong information. Change the value on every click.
Safety note
This page may be public, so do not put personal information on it:
- Do not write your home address, phone number, school name or full name.
- Do not add a clear photo of your face without asking an adult.
- Using a nickname or only your first name is safer.
There is no real form in this lesson; no data is sent anywhere, and everything stays in your own browser. Before publishing your page on the internet, always review it together with a parent.
Lesson summary
- A web page appears when HTML (content), CSS (appearance) and JavaScript (behaviour) work together.
- Semantic tags and
ariaattributes make a page accessible. - CSS variables and
@mediamake theming and responsive layout easy to build. - Small interactions are added with
addEventListener;aria-expandedmust be kept up to date. - Personal information is not shared, and the page is checked with an adult before publishing.
Review questions
- What are tags like
<header>,<main>and<footer>called, and why do we use them? - What does the
viewportmeta tag do? - Which CSS rule do we use to make a page responsive?
- When the theme button is pressed, both the colours change and the button text updates. Explain the two lines that make this happen.
- Why should we not write a home address or phone number on a personal project page?
Answers
- They are called semantic HTML tags. Because their meaning is clear, screen readers and search engines understand the page more accurately.
- The
viewporttag makes the page open at the correct scale for the device width; without it the page looks very small on a phone. - We use a
@mediaquery. For example,@media (min-width: 600px)defines a different layout on a wide screen. classList.toggle("dark")changes the colours by adding or removing the class onbody; the linebutton.textContent = ...updates the button text based on the state.- Because the page may be public, personal details create a safety and privacy risk; using a nickname is safer.
Source and verification note
For “Project: Personal Project Page”, verification focuses on whether the relationship between Step 1: Planning — what goes on the page? and Step 2: The semantic HTML skeleton remains consistent across examples. Examples use standards-oriented HTML, CSS and browser JavaScript. A page should be checked not only visually but also for keyboard use, focus order, mobile layout and meaningful heading structure.
Next lesson
Introduction to Electronics module: We move from web pages to the physical world and begin our first electronics experiments with basic ideas like circuits, voltage and the LED.