Skip to main content

Lesson 5 of 5 30 min read

Build a simple personal webpage

Combine HTML, CSS and JavaScript into a responsive one-page portfolio, then check it for accessibility.

In this lesson you will

  • Plan a small page before writing code
  • Combine semantic HTML, responsive CSS and a JavaScript interaction in one project
  • Check a page for basic accessibility and mobile issues

The project

You'll build a one-page personal site with a header and navigation, an About section, a Skills list, a Projects grid and a contact footer. It will be responsive and include a small interaction: a button that reveals a short message.

Step 1: plan the structure

Before writing code, sketch the sections on paper:

  1. Header and nav
  2. About
  3. Skills
  4. Projects
  5. Footer
5-step diagram

Create a folder with three files: index.html, styles.css and app.js.

The project folder

my-portfolio/ (contains index.html, styles.css, app.js)

Step 2: the HTML

HTML
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Asha Menon | Aspiring Web Developer</title>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <header class="site-header">
      <p class="logo">Asha Menon</p>
      <nav aria-label="Main">
        <a href="#about">About</a>
        <a href="#skills">Skills</a>
        <a href="#projects">Projects</a>
      </nav>
    </header>

    <main>
      <section id="about" class="hero">
        <h1>Hi, I'm Asha. I build things for the web.</h1>
        <p>Second-year student learning front-end development.</p>
        <button id="hello" type="button">Say hello</button>
        <p id="message" hidden>Thanks for visiting! Let's build something together.</p>
      </section>

      <section id="skills">
        <h2>Skills</h2>
        <ul class="skills">
          <li>HTML</li>
          <li>CSS</li>
          <li>JavaScript</li>
        </ul>
      </section>

      <section id="projects">
        <h2>Projects</h2>
        <div class="cards">
          <article class="card">
            <h3>Expense tracker</h3>
            <p>Records daily spending and shows a weekly total.</p>
          </article>
          <article class="card">
            <h3>Recipe finder</h3>
            <p>Filters a list of recipes by ingredient.</p>
          </article>
        </div>
      </section>
    </main>

    <footer>
      <p>Email: asha@example.com</p>
    </footer>
    <script src="app.js" defer></script>
  </body>
</html>

Step 3: the CSS

CSS
* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: system-ui, sans-serif;
  line-height: 1.6;
  color: #0F172A;
}

.site-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 24px;
  background: #0B1220;
  color: #FFFFFF;
}

.site-header nav { display: flex; gap: 16px; }
.site-header a { color: #FFFFFF; text-decoration: none; }
.site-header a:hover, .site-header a:focus-visible { color: #22D3EE; }

main { max-width: 960px; margin: 0 auto; padding: 24px; }

.hero h1 { font-size: 1.75rem; }

button {
  padding: 10px 18px;
  border: 0;
  border-radius: 8px;
  background: #2563EB;
  color: #FFFFFF;
  font-size: 1rem;
  cursor: pointer;
}

.skills { display: flex; flex-wrap: wrap; gap: 8px; padding: 0; list-style: none; }
.skills li { padding: 4px 12px; border-radius: 999px; background: #E0F2FE; }

.cards { display: grid; gap: 16px; }
.card { padding: 16px; border: 1px solid #CBD5E1; border-radius: 12px; }

footer { padding: 24px; text-align: center; background: #F1F5F9; }

@media (min-width: 768px) {
  .hero h1 { font-size: 2.75rem; }
  .cards { grid-template-columns: repeat(2, 1fr); }
}

Step 4: the JavaScript

JavaScript
const helloButton = document.querySelector("#hello");
const message = document.querySelector("#message");

helloButton.addEventListener("click", () => {
  message.hidden = !message.hidden;
  helloButton.textContent = message.hidden ? "Say hello" : "Hide message";
});

The hidden attribute hides an element. Flipping it with ! turns the message on and off, and the button label changes to match.

Step 5: check your work

Work through this checklist before you call the page finished:

  • Resize the window to phone width (about 375px). Is there any horizontal scrolling? Is the text readable?
  • Press Tab repeatedly. Can you reach every link and the button, and can you see which one has focus?
  • Is there exactly one <h1>, and do the headings go h1 → h2 → h3?
  • Is there enough colour contrast between text and background?
  • Does the page work if you open it in a different browser?

Hands-on exercise

Build the page for yourself, replacing the sample content with your own name, skills and two project ideas. Then extend it: add a third project card, make the cards show three per row on screens wider than 1024px, and add a "Back to top" link in the footer. Run through the step 5 checklist and fix anything that fails.

Knowledge check

3 questions • 70% to pass • Practice only, no certificate

  1. 1.Why is the script tag given the defer attribute?
  2. 2.What does message.hidden = !message.hidden do?
  3. 3.Which check confirms that keyboard users can use your page?
0 of 3 answered

Key concepts

  • Plan the sections first, then write the HTML structure, then style it, then add behaviour.
  • Keep HTML, CSS and JavaScript in separate files linked from the page.
  • Mobile-first CSS with a media query makes the layout adapt to larger screens.
  • Always check keyboard access, heading order, contrast and small-screen layout before publishing.

Optional next step: DevCrest Academy

Modern React 19, TypeScript & Next.js

Ready for modern front-end development? The academy course builds on HTML, CSS and JavaScript with React, TypeScript and Next.js through guided projects.

  • Beginner to Intermediate
  • 10 weeks • 80 hours
  • Online Live
  • From ₹7,500 per student

Fees and batch dates are sample data pending confirmation

Or keep learning for free with Programming Fundamentals.