What You Are Building
You are going to build a personal portfolio page — one page that introduces you, lists two or three projects you have worked on, and gives someone a way to contact you. It is a good first project because it is genuinely useful. A link you can put on a résumé or send to a recruiter is worth more than another exercise you throw away, and every technique in this course appears in it at least once.
Everything here is HTML only. The page will look plain, and that is deliberate: your job in this project is to get the structure right. A well-structured page is easy to style later; a badly structured one has to be rebuilt before CSS can help it. Resist the urge to reach for style attributes to make it look better as you go.
Work through the sections below in order rather than typing the finished example at the end. The point is the reasoning at each step — which element to choose and why — not the final file.
- A correct document skeleton, with a real title and description
- A header containing your name and a navigation menu
- A main region holding an introduction, a project list and a contact form
- Each project marked up as a self-contained article with a heading and an image
- A contact form with properly labelled fields
- A footer with copyright and a link or two
- A skip link, correct heading order, and alt text on every image
Step 1: Plan the Outline Before You Type
Open a notebook before you open your editor and write out the page as a list of headings. That list is your structure, and getting it right on paper takes two minutes, while getting it wrong in code costs an hour of rearranging.
The outline below has one <h1> — your name, because that is what the page is about — and three <h2> sections beneath it. Each project inside the Projects section is an <h3>, because a project is a subsection of that section. No level is skipped anywhere, which means anyone navigating by headings gets a clean picture of the page.
Then set up your files. Create a folder for the project, an index.html inside it, and an images folder next to that. Keep every name lowercase with hyphens instead of spaces. Doing this now saves you fixing broken paths later, when the site is uploaded to a server that treats capital letters as different characters.
Outline
-------
h1 Ananya Sharma
h2 About me
h2 Projects
h3 Line-following robot
h3 College bus timetable app
h3 Weather station with an ESP32
h2 Contact
Folder structure
----------------
portfolio/
index.html
images/
line-follower.jpg
bus-app.png
weather-station.jpg - Read your outline aloud. If it tells the story of the page on its own, the structure is right. If it sounds like a random list, fix it now — no amount of CSS later will make a confused structure make sense.
Step 2: The Skeleton, Header and Navigation
Start with the document skeleton from Lesson 2: doctype, lang, charset, viewport, title and description. Give the title something specific such as "Ananya Sharma — Computer Science student portfolio", because that string is what a search result and a shared link will show.
The first thing inside <body> should be a skip link — an anchor pointing at your main content. It is invisible until someone tabs to it, and it lets a keyboard user jump past your menu instead of pressing Tab through every link on every visit.
Then comes the <header>, holding your <h1> and a <nav>. The menu is a list of links, marked up as a real <ul> even though you will remove the bullets in CSS later, because the browser can then tell a screen reader how many items it has. Each link points at a fragment — #about, #projects, #contact — matching an id further down the page.
Note that <header> is not the same thing as <head>. The head is metadata nobody sees; the header is the visible banner at the top of the page.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ananya Sharma — Computer Science student portfolio</title>
<meta name="description" content="Projects in embedded systems and web development by a second-year computer science student.">
</head>
<body>
<a href="#content" class="skip-link">Skip to main content</a>
<header>
<h1>Ananya Sharma</h1>
<p>Second-year Computer Science student</p>
<nav aria-label="Main">
<ul>
<li><a href="#about">About</a></li>
<li><a href="#projects">Projects</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
</header> - Test the menu as soon as you have written it. Click each link and confirm the page jumps to the right place. If nothing happens, the
idfurther down does not match the fragment — remember that ids are case-sensitive.
Step 3: Main Content, Projects and the Form
Everything unique to this page goes inside a single <main id="content">. That id is what your skip link points at, and the element itself is the landmark a screen reader user jumps to.
Inside it, use a <section> for each themed part, each with its own <h2> and the id its menu link refers to. Within the Projects section, each individual project is an <article> — apply the test from Lesson 13 and it fits: a project description would still make sense lifted out of this page and shown somewhere else.
Give each project an image with real alt text describing what the picture shows, plus width and height attributes so nothing jumps around while the images load. Use a <ul> for the technologies used, because that is genuinely a list.
The contact form uses everything from the forms lessons: a label properly associated with every field, sensible input types so phones show the right keyboard, name attributes so the values actually get submitted, and method="post" because the submission creates something. A plain HTML page has nowhere to send it, so leave the action pointing at a placeholder for now — the form still demonstrates correct structure, and connecting it to a real handler is a later step.
<main id="content">
<section id="about">
<h2>About me</h2>
<p>I am a second-year computer science student interested in
embedded systems and web development. Most of my projects
start in the robotics lab on a Saturday afternoon.</p>
</section>
<section id="projects">
<h2>Projects</h2>
<article>
<h3>Line-following robot</h3>
<img src="images/line-follower.jpg"
alt="Small two-wheeled robot following a black tape track"
width="640" height="400">
<p>An Arduino robot that follows a taped track using two
infrared sensors, built for the inter-college competition.</p>
<ul>
<li>Arduino Uno</li>
<li>Infrared sensors</li>
<li>C++</li>
</ul>
</article>
</section>
<section id="contact">
<h2>Contact</h2>
<form action="/contact" method="post">
<p>
<label for="name">Your name</label><br>
<input type="text" id="name" name="name"
autocomplete="name" required>
</p>
<p>
<label for="email">Your email</label><br>
<input type="email" id="email" name="email"
autocomplete="email" required>
</p>
<p>
<label for="message">Message</label><br>
<textarea id="message" name="message" rows="5" required></textarea>
</p>
<p><button type="submit">Send message</button></p>
</form>
</section>
</main> - Click each form label and check that the matching field takes focus. It is the fastest way to confirm every
forandidpair really matches, and a broken pair is invisible otherwise.
Step 4: Finish It, Then Check It
Close the page with a <footer> containing a copyright line and any links you want repeated at the bottom. Then run through the checks below before you call it finished. Every one of them corresponds to a mistake that is easy to make and easy to fix now.
The complete page is in the example below. Run it, then change it: put your own name in, describe your own projects, adjust the sections. Working from something that already runs is a far better way to learn than starting from a blank file.
After that, the natural next steps are CSS to make it look like your own, then a free hosting service such as GitHub Pages to put it on the internet with a real address. Once it is live, come back and run the validator against the published URL — it is a good habit to get into early.
- Does it validate cleanly at
validator.w3.org? - Exactly one
<h1>, and no heading level skipped anywhere? - Does every image have meaningful
alttext, pluswidthandheight? - Does every form field have a label you can click to focus it?
- Does every field that must reach the server have a
name? - Can you use the whole page with the keyboard alone, including the skip link?
- Do all three menu links jump to the right sections?
- Is the page readable on a phone, with the viewport meta tag in place?
- Are there any leftover comments containing notes you would not want a stranger to read?
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ananya Sharma — Computer Science student portfolio</title>
<meta name="description" content="Projects in embedded systems and web development by a second-year computer science student.">
</head>
<body>
<a href="#content" class="skip-link">Skip to main content</a>
<header class="site-header">
<h1>Ananya Sharma</h1>
<p class="tagline">Second-year Computer Science student</p>
<nav aria-label="Main">
<ul>
<li><a href="#about">About</a></li>
<li><a href="#projects">Projects</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
</header>
<main id="content">
<section id="about">
<h2>About me</h2>
<p>I am a second-year computer science student interested in
embedded systems and web development. Most of my projects start
in the robotics lab on a Saturday afternoon and take a few
weekends to finish.</p>
<p>I am currently looking for a summer internship in embedded
software or front-end development.</p>
</section>
<section id="projects">
<h2>Projects</h2>
<article class="project">
<h3>Line-following robot</h3>
<img src="images/line-follower.jpg"
alt="Small two-wheeled robot following a black tape track"
width="640" height="400">
<p>An Arduino robot that follows a taped track using two infrared
sensors, built for the inter-college competition. The hardest
part was tuning the turn response so it did not overshoot
on sharp corners.</p>
<ul>
<li>Arduino Uno</li>
<li>Infrared sensors</li>
<li>C++</li>
</ul>
</article>
<article class="project">
<h3>College bus timetable app</h3>
<img src="images/bus-app.png"
alt="Phone screen showing a list of bus departure times"
width="640" height="400">
<p>A single-page timetable that works offline, built after missing
the last bus twice in one week. Around eighty students in my
year now use it.</p>
<ul>
<li>HTML and CSS</li>
<li>JavaScript</li>
</ul>
</article>
<article class="project">
<h3>Weather station with an ESP32</h3>
<img src="images/weather-station.jpg"
alt="Breadboard with a temperature sensor wired to an ESP32 board"
width="640" height="400">
<p>A temperature and humidity logger on the hostel roof that posts
a reading every fifteen minutes and charts the last week.</p>
<ul>
<li>ESP32</li>
<li>DHT22 sensor</li>
<li>Python</li>
</ul>
</article>
</section>
<section id="contact">
<h2>Contact</h2>
<p>Email me at
<a href="mailto:ananya@example.edu">ananya@example.edu</a>,
or use the form below.</p>
<form action="/contact" method="post">
<p>
<label for="name">Your name</label><br>
<input type="text" id="name" name="name"
autocomplete="name" required>
</p>
<p>
<label for="email">Your email</label><br>
<input type="email" id="email" name="email"
autocomplete="email" placeholder="you@example.com" required>
</p>
<p>
<label for="message">Message</label><br>
<textarea id="message" name="message" rows="5" required></textarea>
</p>
<p><button type="submit">Send message</button></p>
</form>
</section>
</main>
<footer class="site-footer">
<p>© 2026 Ananya Sharma</p>
<p><a href="#content">Back to top</a></p>
</footer>
</body>
</html> CSS
/* Deliberately minimal — the point of the project is the structure.
Replace all of this once you start the CSS course. */
body {
font-family: system-ui, Arial, sans-serif;
line-height: 1.6;
color: #222;
margin: 0;
}
.skip-link { position: absolute; left: -9999px; }
.skip-link:focus {
position: static;
display: inline-block;
padding: 8px 12px;
background: #ffe;
}
.site-header {
background: #7a0060;
color: #fff;
padding: 28px 24px;
}
.site-header h1 { margin: 0; font-size: 1.8rem; }
.tagline { margin: 4px 0 16px; opacity: 0.85; }
.site-header a { color: #fff; }
nav ul {
list-style: none;
display: flex;
flex-wrap: wrap;
gap: 18px;
margin: 0;
padding: 0;
}
main { padding: 24px; max-width: 720px; }
section { margin-bottom: 40px; }
.project {
border: 1px solid #e2e2e6;
border-radius: 8px;
padding: 16px 20px;
margin-bottom: 20px;
}
.project img {
max-width: 100%;
height: auto;
border-radius: 6px;
background: #f2f2f4;
}
input, textarea {
width: 100%;
max-width: 420px;
padding: 10px;
border: 1px solid #ccc;
border-radius: 6px;
font: inherit;
}
input:focus, textarea:focus {
outline: 2px solid #7a0060;
outline-offset: 2px;
}
button {
padding: 12px 22px;
border: none;
border-radius: 6px;
background: #7a0060;
color: #fff;
font-size: 1rem;
cursor: pointer;
}
.site-footer {
background: #222;
color: #fff;
padding: 20px 24px;
font-size: 0.9rem;
}
.site-footer a { color: #fff; } - The three image files do not exist, so the browser shows the alt text in their place — which is a useful reminder of how much that text is carrying. Swap in your own photos and screenshots when you build your real version.
- That is the whole course. You can now describe a document's structure accurately, mark it up so that browsers, search engines and assistive technology all understand it, and build a page you would be willing to show someone. CSS is the natural next step, and JavaScript after that.
