Project: A Personal Profile Page
Your first complete page. One file, semantic structure, a photograph, a list, a table and a link out - built to a specification and checked against it.
-
HTML Basics
- What is HTML: The Structure Layer of Every Web Page
- HTML Document Structure: DOCTYPE, html, head and body
- Elements, Tags and Attributes: The Vocabulary of HTML
- HTML Comments: Notes That Ship With Your Code
- Block Level and Inline Elements
- Writing and Running Your First HTML Page
- How a Browser Turns Markup Into a Page
- Text and Formatting
- Links and Navigation
- Images and Media
- Lists
- Tables
-
Forms
- Form Structure: form, action and method
- Input Types: Text, Email, Number, Date and the Rest
- Labels: The Most Important Element in a Form
- Checkboxes, Radio Buttons and Grouping
- select, option, optgroup and datalist
- textarea, File Uploads and Hidden Fields
- Buttons: submit, reset and button
- Built In Form Validation
- GET or POST: What Happens When a Form Is Submitted
- Semantic HTML
- HTML5 Features
- Head and Metadata
- HTML with CSS
- HTML with JavaScript
- Accessibility
-
HTML SEO
- How Google Works: Crawling, Indexing and Ranking
- SEO Friendly HTML Structure
- Titles and Descriptions That Earn Clicks
- Headings and Content Structure for Search
- Internal Linking and Anchor Text
- robots.txt and XML Sitemaps
- Canonical URLs and Duplicate Content
- Structured Data and JSON-LD
- Image SEO
- Core Web Vitals and Mobile Friendliness
- DevTools and Debugging
- Editor Productivity
- HTML Best Practices
- HTML Projects
- Advanced Projects
- Practice and Exams
The brief
Build a single page introducing a person: who they are, what they do, how to reach them. One HTML file, no framework, no build step.
Requirements
- A valid document with a correct head.
- A page banner containing the name and a short role description.
- A main region with three sections: about, skills and contact.
- A photograph with meaningful alt text and dimensions.
- A skills list marked up as a list.
- A small table of some kind - languages spoken, or availability by day.
- At least two external links, opening in a new tab, correctly marked.
- An email and a telephone link.
- A footer with a copyright line.
- Zero validation errors and zero accessibility violations.
Starting structure
<!DOCTYPE html>
<html lang="en-IN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Meera Iyer - Front End Developer</title>
<meta name="description" content="Meera Iyer, a front end developer in Pune working on accessible, fast interfaces.">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="styles/profile.css">
</head>
<body>
<a href="#main-content" class="skip-link">Skip to main content</a>
<header>
<img src="images/meera-iyer.jpg"
alt="Meera Iyer, smiling, in front of a bookshelf"
width="200" height="200">
<h1>Meera Iyer</h1>
<p>Front end developer, Pune</p>
<nav aria-label="Sections">
<ul>
<li><a href="#about">About</a></li>
<li><a href="#skills">Skills</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
</header>
<main id="main-content" tabindex="-1">
<section>
<h2 id="about">About</h2>
<p>I build interfaces that stay usable on a slow connection and an old phone.</p>
<p>
I write occasionally about the browser on my
<a href="https://example.org/journal" target="_blank" rel="noopener noreferrer">
journal (opens in a new tab)
</a>.
</p>
</section>
<section>
<h2 id="skills">Skills</h2>
<ul>
<li>Semantic HTML and accessibility</li>
<li>CSS grid and flexbox layouts</li>
<li>JavaScript in the browser</li>
</ul>
<h3>Languages</h3>
<table>
<caption>Languages and level</caption>
<thead>
<tr><th scope="col">Language</th><th scope="col">Level</th></tr>
</thead>
<tbody>
<tr><th scope="row">Marathi</th><td>First language</td></tr>
<tr><th scope="row">English</th><td>Fluent</td></tr>
<tr><th scope="row">Hindi</th><td>Fluent</td></tr>
</tbody>
</table>
</section>
<section>
<h2 id="contact">Contact</h2>
<dl>
<div>
<dt>Email</dt>
<dd><a href="mailto:meera@example.com">meera@example.com</a></dd>
</div>
<div>
<dt>Phone</dt>
<dd><a href="tel:+912026001234">+91 20 2600 1234</a></dd>
</div>
</dl>
</section>
</main>
<footer>
<p><small>Written in 2026. Built with HTML and CSS.</small></p>
</footer>
</body>
</html>Why each decision was made
| Decision | Reason |
|---|---|
| Skip link first | Keyboard users bypass the navigation |
tabindex="-1" on main | The skip link moves focus, not only scroll |
One h1, the name | The page is about this person |
Photograph described, not alt="" | It is content on a profile page |
| Ids on the headings | The in page navigation targets them |
| Table with both header axes | Every cell is announced with its context |
| Description list for contact | The data is name and value pairs |
| New tab warning in the link text | Nobody is surprised by the back button failing |
A minimal stylesheet
:root {
--text: #1e293b;
--muted: #475569;
--accent: #1e3a8a;
--line: #cbd5e1;
}
* { box-sizing: border-box; }
body {
margin: 0;
font: 1rem/1.6 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
color: var(--text);
max-width: 45rem;
margin-inline: auto;
padding: 1.5rem 1rem 4rem;
}
img { max-width: 100%; height: auto; border-radius: 50%; }
h1 { font-size: 2rem; margin-bottom: 0.25rem; }
h2 { font-size: 1.375rem; margin-top: 2.5rem; }
a { color: var(--accent); }
a:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
nav ul { list-style: none; display: flex; gap: 1.25rem; padding: 0; }
table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: 0.5rem 0.75rem; border-bottom: 1px solid var(--line); }
caption { text-align: left; font-weight: 600; padding-bottom: 0.5rem; }
dl div { display: grid; grid-template-columns: 6rem 1fr; gap: 0.5rem; padding: 0.35rem 0; }
dt { font-weight: 600; }
dd { margin: 0; }
.skip-link { position: absolute; left: -9999px; }
.skip-link:focus { left: 1rem; top: 1rem; background: #fff; padding: 0.75rem 1rem; }
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}Checking your work
- Validate. Zero errors.
- Tab through the whole page. Everything reachable, focus always visible, skip link working.
- Turn images off. Does the alt text carry the meaning?
- Narrow the window to 320 pixels. No horizontal scrolling.
- Zoom to 200 percent. Nothing clipped or overlapping.
- Run an accessibility scan. Zero violations.
- Run the console audit snippets from the debugging note.
Extensions
- Add a dark mode with
prefers-color-scheme. - Add Open Graph tags and check the preview card.
- Add
Personstructured data with JSON-LD. - Add a
detailselement holding a longer biography. - Print the page. Add a print stylesheet that hides the navigation.
What this teaches
Everything in this project is a decision you will make on every page you ever build: which element carries which meaning, where the heading levels sit, what the alt text says, and how a keyboard moves through it. A profile page is small enough to get all of it right, which is the point.
Practice
- Build the page for yourself with your own content.
- Add a fourth section and keep the navigation and heading structure correct.
- Replace the table with a description list and explain which fits better.
- Ask someone else to navigate it with the keyboard and watch where they hesitate.