// CSS Course — Capstone Project

Style a
Developer
Portfolio

Your final project: take the HTML portfolio you built in the HTML course and style it into a polished, responsive, animated professional website using every CSS concept from all 12 chapters.

CSS Course 8 Steps ~4–5 Hours All 12 Chapters

What You're Building

You are going to style the HTML portfolio page you built in the HTML Capstone Project. The HTML structure is already complete — your job is to write the CSS that transforms it from unstyled HTML into a polished, dark-themed, responsive, animated developer portfolio.

Every CSS chapter is represented. Work through the 8 steps in order — each step builds on the previous one. By the end you will have a real portfolio you can actually use.

CSS Reset Design Tokens Typography Flexbox Nav CSS Grid Positioning Responsive Dark Mode Transitions Animations BEM Architecture CSS Variables
📖 Project Scenario
Your Brief

You are the CSS developer on Obed Angel's personal portfolio. The HTML has been written by the markup developer (you, in the HTML course). Now it is your job to style it. Obed wants a dark, professional aesthetic — think devtools meets design agency. He wants it to feel fast, polished, and responsive on any device. The design language should feel consistent throughout — same spacing rhythm, same colour tokens, same animation personality.

Think of yourself as a CSS engineer. Your output should be production quality — not just "it looks okay", but the kind of CSS that a professional team would be proud to ship.

Requirements — what the CSS must achieve
Foundation
  • Modern CSS reset at top
  • Full design token system in :root
  • Google Fonts loaded and applied
  • All values reference tokens — no magic numbers
Layout
  • Flexbox sticky navbar
  • CSS Grid for projects section
  • Sidebar layout for about section
  • Positioned badge on project cards
Typography
  • Fluid headings with clamp()
  • Gradient text on hero h1
  • Correct line-height per context
  • Letter-spacing on labels
Responsive
  • Mobile-first approach
  • Two breakpoints: 768px, 1200px
  • prefers-color-scheme dark mode
  • prefers-reduced-motion override
Interactions
  • Button lift on hover + :active press
  • Card lift with shadow transition
  • Animated nav underline
  • Image zoom on project card hover
Animations
  • Hero entrance: fadeUp on load
  • Staggered card entrance
  • Skills badge entrance animation
  • Loading spinner on form submit
Chapters used in this project
CH 01
Selectors & Specificity
CH 02
Box Model
CH 03
Typography
CH 04
Flexbox
CH 05
CSS Grid
CH 06
Positioning
CH 07
Responsive
CH 08
Transitions
CH 09
Animations
CH 10
CSS Variables
CH 11
Pseudo-Classes
CH 12
Architecture
🎨 Design Target
ObedAngel.dev — styled with CSS Mastery
Obed.dev About Skills Projects Contact sticky top:0 + animated underline gradient text + clamp() + fadeUp animation profile About — flex row: text + image side by side skill badges with fadeUp stagger + :hover scale Projects — CSS Grid auto-fit + card hover lift PRO position:absolute badge Contact Form — styled inputs + :focus-visible + :valid/:invalid name :focus-visible email :valid Send Message © 2025 Obed Angel footer with flex layout + social links

↑ Annotated design target. Every label shows the CSS technique responsible for that section. Build step by step.

Step-by-Step Instructions
Step 01 of 08 CH 12CH 10CH 02

Foundation: Reset, Tokens & Base Styles

Open the Playground CSS tab. This is the very first thing you write — before any component styles. Get the foundation right and everything else becomes simpler.

  • Write the modern CSS reset from memory: box-sizing, scroll-behavior, line-height, media display:block, form font:inherit
  • Define a complete :root token system: colours (bg, surface, card, border, accent, text, muted), spacing scale (xs → xl), radius, shadow, and font family variables
  • Set body styles using only tokens: background, color, font-family, font-size, line-height, -webkit-font-smoothing
  • Load Google Fonts in the CSS tab: Syne for headings, DM Sans for body, JetBrains Mono for code
/* Step 1: Foundation */
:root {
  --bg:        #0a0a0f;
  --surface:   #111118;
  --accent:    #7c6af7;
  --accent2:   #f7706a;
  --accent3:   #5af7c0;
  --text:      #e8e8f0;
  --muted:     #888899;
  --space-md:  16px;
  --space-lg:  32px;
  --radius:    8px;
  --shadow:    0 8px 32px rgba(0,0,0,.4);
  --font-body: 'DM Sans', sans-serif;
}
✓ Preview tab: dark background, body text visible, base styles applied — zero component CSS yet
Step 02 of 08 CH 03CH 01

Typography System

Style all text elements — headings, paragraphs, labels, code snippets. Use clamp() for all headings. Apply gradient text to the hero h1.

  • h1: clamp(32px, 5vw, 72px) · Syne font · weight 800 · line-height 1.05 · gradient text effect
  • h2: clamp(24px, 4vw, 40px) · Syne · weight 700 · line-height 1.2
  • h3: clamp(18px, 2.5vw, 24px) · Syne · weight 600
  • p: font-size 1rem · line-height 1.8 · color var(--muted)
  • Monospace labels: JetBrains Mono · 0.6875rem · letter-spacing 3px · text-transform uppercase
  • a: no underline · inherit colour · :hover changes to var(--accent)
  • a:focus-visible: visible outline — never suppressed
✓ Preview: heading hierarchy clearly visible · hero h1 shows gradient · all text uses correct tokens
Step 03 of 08 CH 04CH 06

Navigation: Flexbox + Sticky + Animated Underline

Style the sticky navigation. It must stick to the top, stay above page content, and have animated underlines on links.

  • nav: position: sticky; top: 0; z-index: 100 · background var(--surface) · border-bottom
  • Inner nav container: display: flex; align-items: center; justify-content: space-between · height 64px · padding horizontal
  • Logo link: Syne font · bold · var(--accent) colour
  • Nav links: flexbox row · gap · no underline by default
  • Animated underline: ::after pseudo-element · width: 0 → width: 100% on :hover · transition
  • Active link: colour var(--accent) · underline visible by default
✓ Scroll the page — nav sticks at top · hover links show growing underline
Step 04 of 08 CH 04CH 09

Hero Section: Layout + Entrance Animations

Style the hero with flexbox centring and load-time animations. Every visible element in the hero should animate in on page load.

  • Hero: min-height: 100vh · display flex · flex-direction column · justify-content center · padding
  • Gradient text on h1: background linear-gradient · -webkit-background-clip: text · -webkit-text-fill-color: transparent
  • Role subtitle: monospace font · var(--accent3) colour · letter-spacing
  • CTA buttons: primary (var(--accent) background), secondary (transparent, border only) · border-radius · padding · flex row
  • Entrance animation: @keyframes fadeUp (opacity 0 + translateY 24px → opacity 1 + translateY 0)
  • Apply with staggered delays: h1 at 0s, subtitle at 0.15s, description at 0.3s, buttons at 0.45s
✓ On page load: hero content fades up in sequence · gradient is on h1 · buttons have correct styles
Step 05 of 08 CH 02CH 05CH 06CH 08

Skills & Projects: Grid Layout + Card Interactions

Build the two most complex sections. Skills uses a flex wrap layout with animated badges. Projects uses CSS Grid with card interactions.

  • Skills badges: inline-flex · padding · border-radius pill · background/border using var() · fadeUp stagger entrance
  • Projects section heading: h2 with bottom border accent line
  • Projects grid: display: grid; repeat(auto-fit, minmax(300px, 1fr)); gap: 20px
  • Project card: background var(--card) · border · border-radius · overflow: hidden · position: relative
  • Card image: width 100% · height 200px · object-fit: cover · transition: transform 0.4s ease
  • Card hover: translateY(-6px) + box-shadow on card · scale(1.05) on image
  • PRO badge: position: absolute; top: 12px; right: 12px
  • Card body: padding · h3 title · p description · tech tags row · GitHub link
✓ Project cards sit in responsive grid · hover lifts card + zooms image · badge in top-right corner
Step 06 of 08 CH 07CH 11

Contact Form: Styles + Validation States

Style the contact form inputs. Use pseudo-classes for visual validation feedback — no JavaScript required.

  • Form inputs: full width · background var(--card) · border var(--border) · border-radius · padding · color var(--text)
  • input:focus: outline: none · border-color var(--accent) · box-shadow accent glow
  • input:focus-visible: outline always present for keyboard users
  • input:valid: border-color var(--accent3) green
  • input:invalid:not(:placeholder-shown): border-color var(--accent2) red
  • ::placeholder: color var(--muted) · font-style italic
  • Submit button: full width on mobile · var(--accent) background · transition: transform + box-shadow · :hover lift · :active press
✓ Inputs show purple glow on focus · green border on valid email · red on invalid · submit lifts on hover
Step 07 of 08 CH 07CH 10

Responsive Design + Dark Mode

Make the entire portfolio mobile-first responsive and add automatic dark mode support via CSS variables.

  • Verify: all base styles written mobile-first (no overrides, only additions)
  • @media (min-width: 768px): nav switches from stacked to horizontal · sidebar layout in about section · 2-column grid for projects
  • @media (min-width: 1200px): max-width container centred · 3-column projects grid · larger hero padding
  • Nav mobile: hide desktop links · show hamburger icon (CSS-only with :checked technique or just a flex column)
  • Light mode override: @media (prefers-color-scheme: light) — swap --bg, --surface, --card, --text, --muted tokens only. Primary accent stays purple.
  • @media (prefers-reduced-motion: reduce): all animation-duration to 0.01ms
✓ Resize browser: layout adapts at 768px and 1200px · light mode works on system preference change · animations disabled for reduced-motion users
Step 08 of 08 CH 12CH 01

Architecture Polish & Final Audit

Finalise the CSS with professional architecture practices and audit every rule before submission.

  • Add @layer reset, base, components, utilities at the top. Move rules into appropriate layers.
  • Audit: confirm zero magic numbers — every value is a token or a derived calc()
  • Audit: confirm zero !important declarations
  • Audit: confirm every interactive element has a :focus-visible outline
  • Rename all classes to BEM naming: .nav__link, .card__title, .card--featured, .btn--primary
  • Add the .sr-only utility for any visually hidden accessible text
  • Run the CSS through the browser DevTools Audit panel — fix any flagged issues
✓ Zero !important · Zero magic numbers · BEM class names · @layer organisation · Focus visible on all interactive elements

✅ You're Done When Your Portfolio Achieves All of These

+ Challenge Extensions

CSS-Only Dark/Light Toggle

Add a toggle button that switches between dark and light by adding a .light class to <html> via JavaScript, overriding CSS variable tokens.

Scroll-Reveal Animations

Use JavaScript's IntersectionObserver to add a .visible class to sections as they enter the viewport. CSS transition handles the reveal.

Skeleton Loading Cards

Show shimmer skeleton placeholders for the project cards while the page loads. Replace them with real content after 2 seconds.

CSS Custom Scrollbar

Style the browser scrollbar using ::-webkit-scrollbar pseudo-elements to match the dark theme with a purple thumb.

Print Stylesheet

Add @media print styles: hide navigation and decorative elements, convert to light background, ensure all text is black for printing.

CSS Particles Background

Create a subtle animated background pattern in the hero using CSS gradients and keyframes — no canvas, no JavaScript.

🚀 Submitting Your Project

When you are happy with the result, submit both your HTML and CSS files for review. Your instructor will check the visual output, code quality, and architecture.

  1. Save your CSS — use the Playground's Save button or copy to your computer as styles.css
  2. Update your HTML portfolio — make sure the <link rel="stylesheet" href="styles.css"> is in the <head>
  3. Push to GitHub — commit both index.html and styles.css to your html-capstone-project repository
  4. Check GitHub Pages — confirm the live site at your GitHub Pages URL shows the styled version
  5. Submit the GitHub Pages URL — the reviewer will see your live styled portfolio

Open the Playground — Start Styling

Load your HTML portfolio in the HTML tab, then switch to CSS to start writing. See results live in the Preview tab.

⚡ Open Playground → CSS Tab