Build Your First Web App with HTML & CSS

From empty file to working webpage — step by step, nothing assumed.

🟢 Beginner ⏱️ 2 hours Web Development

Learn how to build your first web application from scratch using HTML and CSS. A step-by-step beginner tutorial that takes you from an empty file to a complete, styled portfolio webpage.

What You're Building

By the end of this tutorial, you'll have built a fully styled personal portfolio webpage — a complete, working web page that lives on your computer and can be published online. It will include:

  • A navigation bar
  • A hero section with your name and intro
  • An about section
  • A projects/skills section
  • A contact section
  • A footer
  • Responsive styling that looks good on desktop and mobile

This isn't a toy project. A personal portfolio is something you'll actually use — and the skills you practice building it are the exact same skills used to build every website on the internet.

Before You Start

What you need:

  • A computer running Windows, macOS, or Linux
  • VS Code (Visual Studio Code) — free download at code.visualstudio.com
  • A web browser (Chrome or Firefox recommended)
  • No prior coding experience required

What you should know:

  • How to create and save files on your computer
  • How to open a browser

That's it. Everything else, we'll build together.

Time commitment: 2 hours. Go at your own pace — there's no timer.

How This Tutorial Works

Each step tells you exactly what to do, shows you the code to write, and explains what that code is doing and why. Don't copy and paste — type the code yourself. Typing it builds muscle memory and forces you to actually read what you're writing. When something doesn't look right, the troubleshooting note at the end of each step will help.

At several points you'll see ✅ Checkpoint — a moment to check your work before moving forward.

Step 1: Set Up Your Project

What we're doing: Creating the folder and files that your project will live in.

1.1 — Create your project folder

Create a new folder on your computer called my-portfolio. You can put it anywhere — your Desktop, your Documents folder, wherever makes sense to you.

1.2 — Open the folder in VS Code

Open VS Code. Go to File → Open Folder and select your my-portfolio folder. VS Code will open the folder in the Explorer panel on the left.

1.3 — Create your files

In VS Code's Explorer panel, create two new files inside your my-portfolio folder:

  • index.html
  • style.css

To create a file: click the New File icon in the Explorer panel (or right-click inside the panel and choose New File). Name it exactly as shown above.

1.4 — Install the Live Server extension

In VS Code, click the Extensions icon in the left sidebar (it looks like four squares). Search for Live Server by Ritwick Dey and install it. This extension automatically refreshes your browser every time you save your HTML or CSS — you'll see your changes instantly without manually refreshing.

✅ Checkpoint: You should have a my-portfolio folder open in VS Code with two files: index.html and style.css. The Live Server extension should be installed.

Troubleshooting: If you can't find the Extensions panel, use the keyboard shortcut Ctrl+Shift+X (Windows/Linux) or Cmd+Shift+X (Mac).

Step 2: Build the HTML Structure

What we're doing: Writing the skeleton of your webpage — the HTML that defines what exists on the page, before any styling.

Open index.html and type the following code exactly:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Personal portfolio of [Your Name] — aspiring web developer and tech learner." />
    <title>[Your Name] | Portfolio</title>
    <link rel="stylesheet" href="style.css" />
  </head>

  <body>

    <!-- NAVIGATION -->
    <nav class="navbar">
      <div class="nav-logo">[Your Name]</div>
      <ul class="nav-links">
        <li><a href="#about">About</a></li>
        <li><a href="#projects">Projects</a></li>
        <li><a href="#contact">Contact</a></li>
      </ul>
    </nav>

    <!-- HERO SECTION -->
    <section class="hero" id="home">
      <div class="hero-content">
        <p class="hero-greeting">Hello, I'm</p>
        <h1 class="hero-name">[Your Name]</h1>
        <p class="hero-tagline">Aspiring Developer · Tech Learner · Problem Solver</p>
        <a href="#projects" class="btn-primary">See My Work</a>
      </div>
    </section>

    <!-- ABOUT SECTION -->
    <section class="about" id="about">
      <div class="container">
        <h2 class="section-title">About Me</h2>
        <p class="about-text">
          I'm currently learning web development and building projects to grow my skills.
          I'm passionate about technology, problem-solving, and creating things that actually work.
          This portfolio is one of my first projects — and definitely not my last.
        </p>
      </div>
    </section>

    <!-- PROJECTS / SKILLS SECTION -->
    <section class="projects" id="projects">
      <div class="container">
        <h2 class="section-title">Skills & Projects</h2>
        <div class="cards-grid">

          <div class="card">
            <div class="card-icon">💻</div>
            <h3 class="card-title">HTML & CSS</h3>
            <p class="card-text">Building structured, styled web pages from scratch.</p>
          </div>

          <div class="card">
            <div class="card-icon">🎨</div>
            <h3 class="card-title">Responsive Design</h3>
            <p class="card-text">Creating layouts that work on any screen size.</p>
          </div>

          <div class="card">
            <div class="card-icon">🚀</div>
            <h3 class="card-title">This Portfolio</h3>
            <p class="card-text">My first complete web project — built entirely from scratch.</p>
          </div>

        </div>
      </div>
    </section>

    <!-- CONTACT SECTION -->
    <section class="contact" id="contact">
      <div class="container">
        <h2 class="section-title">Get In Touch</h2>
        <p class="contact-text">
          I'm always open to learning opportunities, collaborations, and conversations about tech.
        </p>
        <a href="mailto:your@email.com" class="btn-primary">Send Me an Email</a>
      </div>
    </section>

    <!-- FOOTER -->
    <footer class="footer">
      <p>Built with HTML & CSS · [Your Name] · 2026</p>
    </footer>

  </body>

Step 3: CSS Reset and Global Styles

What we're doing: Setting up the foundation of our CSS — resetting browser defaults and defining global styles that apply to the entire page.

Open style.css and type:

/* ===========================
   CSS RESET & GLOBAL STYLES
   =========================== */

*, *::before, *::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

:root {
  --color-bg: #0f0f1a;
  --color-surface: #1a1a2e;
  --color-primary: #6c63ff;
  --color-primary-light: #8b85ff;
  --color-text: #e0e0e0;
  --color-text-muted: #9a9ab0;
  --color-border: #2a2a3e;
  --font-main: 'Segoe UI', system-ui, -apple-system, sans-serif;
  --transition: all 0.3s ease;
  --radius: 12px;
  --max-width: 1100px;
}

html {
  scroll-behavior: smooth;
}

body {
  font-family: var(--font-main);
  background-color: var(--color-bg);
  color: var(--color-text);
  line-height: 1.7;
  font-size: 16px;
}

a {
  text-decoration: none;
  color: inherit;
}

ul {
  list-style: none;
}

img {
  max-width: 100%;
  display: block;
}

.container {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 2rem;
}

.section-title {
  font-size: 2rem;
  font-weight: 700;
  margin-bottom: 1.5rem;
  position: relative;
  display: inline-block;
}

.section-title::after {
  content: '';
  position: absolute;
  bottom: -8px;
  left: 0;
  width: 50px;
  height: 4px;
  background-color: var(--color-primary);
  border-radius: 2px;
}

.btn-primary {
  display: inline-block;
  background-color: var(--color-primary);
  color: #fff;
  padding: 0.85rem 2rem;
  border-radius: var(--radius);
  font-weight: 600;
  font-size: 1rem;
  transition: var(--transition);
  cursor: pointer;
}

.btn-primary:hover {
  background-color: var(--color-primary-light);
  transform: translateY(-2px);
}

Step 4: Style the Navigation

What we're doing: Creating a fixed navigation bar that stays at the top of the screen as the user scrolls down.

/* ===========================
   NAVIGATION
   =========================== */

.navbar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1.2rem 2rem;
  background-color: rgba(15, 15, 26, 0.95);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--color-border);
  z-index: 1000;
}

.nav-logo {
  font-size: 1.3rem;
  font-weight: 700;
  color: var(--color-primary);
  letter-spacing: 0.5px;
}

.nav-links {
  display: flex;
  gap: 2rem;
}

.nav-links a {
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--color-text-muted);
  transition: var(--transition);
}

.nav-links a:hover {
  color: var(--color-primary);
}

Step 5: Style the Hero Section

/* ===========================
   HERO SECTION
   =========================== */

.hero {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 8rem 2rem 4rem;
  background: linear-gradient(135deg, var(--color-bg) 0%, #16213e 100%);
}

.hero-content {
  max-width: 700px;
}

.hero-greeting {
  font-size: 1.1rem;
  color: var(--color-primary);
  font-weight: 600;
  letter-spacing: 2px;
  text-transform: uppercase;
  margin-bottom: 0.75rem;
}

.hero-name {
  font-size: clamp(2.5rem, 6vw, 4.5rem);
  font-weight: 800;
  line-height: 1.1;
  margin-bottom: 1rem;
  background: linear-gradient(135deg, #fff 0%, var(--color-primary-light) 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.hero-tagline {
  font-size: 1.1rem;
  color: var(--color-text-muted);
  margin-bottom: 2.5rem;
  letter-spacing: 0.5px;
}

Step 6: Style the About and Projects Sections

/* ===========================
   ABOUT SECTION
   =========================== */

.about {
  padding: 6rem 0;
  background-color: var(--color-surface);
}

.about-text {
  font-size: 1.1rem;
  color: var(--color-text-muted);
  max-width: 650px;
  line-height: 1.9;
}

/* ===========================
   PROJECTS / SKILLS SECTION
   =========================== */

.projects {
  padding: 6rem 0;
  background-color: var(--color-bg);
}

.cards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.5rem;
  margin-top: 1rem;
}

.card {
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 2rem;
  transition: var(--transition);
}

.card:hover {
  border-color: var(--color-primary);
  transform: translateY(-4px);
}

.card-icon {
  font-size: 2rem;
  margin-bottom: 1rem;
}

.card-title {
  font-size: 1.2rem;
  font-weight: 700;
  margin-bottom: 0.75rem;
}

.card-text {
  color: var(--color-text-muted);
  font-size: 0.95rem;
  line-height: 1.7;
}

/* ===========================
   CONTACT SECTION
   =========================== */

.contact {
  padding: 6rem 0;
  background-color: var(--color-surface);
  text-align: center;
}

.contact-text {
  color: var(--color-text-muted);
  font-size: 1.1rem;
  max-width: 500px;
  margin: 0 auto 2rem;
}

/* ===========================
   FOOTER
   =========================== */

.footer {
  padding: 2rem;
  text-align: center;
  background-color: var(--color-bg);
  border-top: 1px solid var(--color-border);
  color: var(--color-text-muted);
  font-size: 0.9rem;
}

Step 7: Make It Responsive

/* ===========================
   RESPONSIVE DESIGN
   =========================== */

@media (max-width: 768px) {
  .navbar {
    padding: 1rem 1.5rem;
  }

  .nav-links {
    gap: 1.2rem;
  }

  .nav-links a {
    font-size: 0.85rem;
  }

  .hero {
    padding: 7rem 1.5rem 4rem;
  }

  .hero-tagline {
    font-size: 1rem;
  }

  .about,
  .projects,
  .contact {
    padding: 4rem 0;
  }

  .section-title {
    font-size: 1.6rem;
  }

  .cards-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 480px) {
  .nav-logo {
    font-size: 1.1rem;
  }

  .nav-links {
    gap: 0.8rem;
  }

  .btn-primary {
    padding: 0.75rem 1.5rem;
    font-size: 0.9rem;
  }
}

Step 8: Publish Your Portfolio

What we're doing: Getting your project live on the internet — for free.

The easiest way to publish a static HTML/CSS project is Netlify Drop.

  1. Go to app.netlify.com/drop (no account required)
  2. Drag your entire my-portfolio folder into the drop zone
  3. Netlify generates a live URL instantly — something like https://random-name-123.netlify.app

Your portfolio is now live on the internet. Share that link.

If you want a custom subdomain: create a free Netlify account, and you can set something like yourname.netlify.app in a few clicks.

✅ Final Checkpoint: You have a live, published portfolio with a real URL.

What You Just Built — And What You Learned

You built a complete, styled, responsive personal portfolio webpage from scratch. In doing so, you practiced:

  • HTML document structure and semantic elements
  • CSS variables for maintainable design systems
  • Flexbox for navigation and centering
  • CSS Grid for responsive card layouts
  • Responsive design with media queries and fluid typography
  • Hover effects and transitions for interactive feel
  • Publishing a real website to the internet

Acabas de construir tu primera página web real. No un ejercicio — algo que puedes compartir, mostrar, y agregar a tu portafolio. Ese es el tipo de progreso que importa. Sigue construyendo cosas.

What to Build Next

Ready to keep building?

For more tutorials like this, visit our main Tutorials page, explore development guides, and join the newsletter for instant updates.

Subscribe to Newsletter