Lesson 5: Capstone Project: Styling a Modern Personal Portfolio Page

“Build a responsive personal portfolio landing page from scratch.”

Lesson 5: Capstone Project: Styling a Modern Personal Portfolio Page

The Portfolio Page Capstone Project

In this final lesson, we will combine everything we have learned throughout this course to style a modern, responsive personal portfolio website.

This project applies the CSS reset, native variables, the box model, Flexbox, CSS Grid, custom typography, and responsive media queries to build a polished, production-ready landing page layout.

---

Step 1: The HTML Structure (index.html)

Create an index.html file in your editor and add the following structural markup:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Developer Portfolio</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>

<!-- Navigation Block -->
<nav class="navbar">
<div class="nav-container">
<span class="brand">Jane Dev</span>
<div class="nav-links">
<a href="#work">My Work</a>
<a href="#contact">Let's Talk</a>
</div>
</div>
</nav>

<!-- Hero Block -->
<header class="hero">
<h1>Crafting Modern Digital Experiences</h1>
<p>I build clean, accessible, and fast-loading websites using 2026 standards.</p>
<a href="#work" class="cta-link">View Projects</a>
</header>

<!-- Grid Projects Block -->
<main id="work" class="portfolio-grid">
<div class="project-card">
<div class="project-tag">Web App</div>
<h3>E-Commerce Interface</h3>
<p>A fast online storefront built with modern layouts and fluid styling.</p>
</div>
<div class="project-card">
<div class="project-tag">Design System</div>
<h3>Visual Component Library</h3>
<p>An accessible UI design system structured with utility tokens.</p>
</div>
<div class="project-card">
<div class="project-tag">Optimization</div>
<h3>Performance Dashboard</h3>
<p>An interactive data tool optimized for mobile platforms.</p>
</div>
</main>

</body>
</html>

---

Step 2: The Project Stylesheet (styles.css)

Create a styles.css file in your editor and add the following styling rules. Notice the use of modern CSS variables, native selectors, box styling, Flexbox, Grid, and mobile-first media queries:

/* CSS Variables and Theme Configuration */
:root {
--primary: oklch(62% 0.23 260); /* vibrant blue */
--primary-hover: oklch(54% 0.23 260);
--text-dark: oklch(18% 0.04 240); /* dark charcoal */
--text-muted: oklch(45% 0.03 240);
--bg-main: oklch(98% 0.01 240); /* soft white background */
--card-bg: oklch(100% 0 0); /* solid white card background */
--border-color: oklch(90% 0.01 240);
}

/* Universal Sizing Reset */
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}

html {
scroll-behavior: smooth;
}

body {
font-family: system-ui, -apple-system, sans-serif;
background-color: var(--bg-main);
color: var(--text-dark);
line-height: 1.6;
}

/* Navigation (Styled with Flexbox) */
.navbar {
background-color: var(--card-bg);
border-bottom: 1px solid var(--border-color);
position: sticky;
top: 0;
z-index: 100;
}

.nav-container {
max-width: 1100px;
margin: 0 auto;
padding: 1rem 1.5rem;
display: flex;
justify-content: space-between;
align-items: center;
}

.brand {
font-weight: 700;
font-size: 1.25rem;
color: var(--primary);
}

.nav-links {
display: flex;
gap: 1.5rem;

& a {
text-decoration: none;
color: var(--text-dark);
font-weight: 500;
transition: color 0.2s;

&:hover {
color: var(--primary);
}
}
}

/* Hero Block (Styled with Flexbox) */
.hero {
max-width: 800px;
margin: 4rem auto;
padding: 0 1.5rem;
text-align: center;

& h1 {
font-size: 2.25rem;
letter-spacing: -0.025em;
color: var(--text-dark);
line-height: 1.2;
margin-bottom: 1rem;
}

& p {
font-size: 1.125rem;
color: var(--text-muted);
margin-bottom: 1.75rem;
}
}

.cta-link {
display: inline-block;
background-color: var(--primary);
color: #ffffff;
text-decoration: none;
padding: 0.75rem 1.75rem;
border-radius: 0.375rem;
font-weight: 600;
transition: background-color 0.2s;

&:hover {
background-color: var(--primary-hover);
}
}

/* Portfolio Showcase (Styled with CSS Grid) */
.portfolio-grid {
max-width: 1100px;
margin: 2rem auto 6rem;
padding: 0 1.5rem;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}

.project-card {
background-color: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 0.5rem;
padding: 2rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
transition: transform 0.2s, box-shadow 0.2s;

&:hover {
transform: translateY(-4px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
}

.project-tag {
display: inline-block;
background-color: oklch(93% 0.02 260);
color: var(--primary);
font-size: 0.75rem;
font-weight: 700;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
margin-bottom: 1rem;
text-transform: uppercase;
}

.project-card h3 {
font-size: 1.25rem;
margin-bottom: 0.5rem;
}

.project-card p {
color: var(--text-muted);
font-size: 0.95rem;
}

/* Desktop Layout Enhancements (Media Query Breakpoint) */
@media (min-width: 768px) {
.hero {
margin: 8rem auto;

& h1 {
font-size: 3.5rem;
}

& p {
font-size: 1.5rem;
}
}
}

---

Visual Output Demonstration

- The Navbar: Remains locked to the top of the browser viewport during scrolling. It uses Flexbox to align the logo to the left and links to the right with precise spacing. - The Hero Banner: Centered horizontally on the page. On mobile screens, the header displays in a compact size, then scales up to a clean, bold 3.5rem display on desktop viewports. - The Showcase Grid: On tablets and desktops, this layout organizes your projects into a neat three-column grid. On mobile devices, the columns stack vertically to maintain readability. - Card Components: Each project card features a smooth hover effect, casting a subtle drop shadow and lifting slightly (translateY(-4px)) when hovered over with a pointer.

---

Frequently Asked Questions (FAQs)

#### Q1: Why did we use :root for styling variables instead of declaring them directly inside element classes?
Declaring CSS custom properties inside the :root pseudo-class scopes them globally. This allows any element across your entire stylesheet to access and use these variables, making it easy to implement global theme updates or dark modes.

#### Q2: What does position: sticky; do for our navbar?
position: sticky is a hybrid of relative and fixed positioning. The element behaves like a standard layout item until it reaches a defined boundary (like top: 0), at which point it pins to the screen and floats over scrolling content.

#### Q3: Why is scroll-behavior: smooth useful?
scroll-behavior: smooth animates navigation jumps across the page. When users click anchor links (like #work), the browser smoothly slides down to the selected section instead of abruptly jumping, creating a more cohesive, high-quality user experience.

Shanawar AliFounder and developer at S Pro Coder, sharing practical coding and technology guides.