Build a Portfolio Resume Page

Build a responsive portfolio page with HTML, CSS Flexbox, and media queries.

Introduction

30 Second Summary

When you apply for a job, recruiters want to see what you can build. A personal portfolio page is the fastest way to show them you know your stuff.

In this project, you will build a clean, professional portfolio resume page using HTML and CSS. By the end, you will have a responsive page you can open in a browser and send to recruiters.

What You'll Build

You open your browser and see a polished portfolio page with your name, your role, your skills in a neat grid, your projects as cards, and your contact links. You drag the browser narrow and everything stacks beautifully for mobile.

By the end of this project, you'll have:

  • A hero section with your name, role title, and a call-to-action button that jumps to your projects.
  • A skills grid and project cards laid out with Flexbox so everything lines up without manual positioning.
  • A fully responsive layout that you can resize from desktop to phone-width and watch it adapt seamlessly.
  • Secret Mission: Smooth hover animations on your project cards and a color theme powered by CSS custom properties so you can retheme the entire site by changing 3 values.

Are there any prerequisites?

None. This project uses only HTML and CSS with no installs or accounts required. The guide includes setup instructions for everything you need.

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters.

Set Up Your Project

Every website starts with two things: an HTML file that holds your content, and a CSS file that controls how it looks. Your browser needs these files linked together correctly to display styles.

In this step, you will create your project folder, set up both files, and connect Google Fonts so your portfolio uses a clean, professional typeface called Inter.

In this step, get ready to:
  • Create a project folder and open it in VS Code.
  • Add your HTML boilerplate with a linked stylesheet and Google Fonts.
  • Verify that your page displays text in the Inter font.
Create your project folder

You need a dedicated folder on your Desktop to keep your portfolio files organized.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type VS Code and press Enter to open it.
  • In VS Code, click File in the top menu bar.
  • Click Open Folder.
  • Navigate to your Desktop.
  • Click New Folder (macOS) or right-click and select New then Folder (Windows).
  • Name it portfolio and open it.

You should see the Explorer sidebar on the left showing your empty portfolio folder.

Don't see the Explorer sidebar?

Press Cmd+Shift+E (macOS) or Ctrl+Shift+E (Windows) to toggle the Explorer panel.

If you see a Welcome tab instead of the folder, go to File > Open Folder and select the portfolio folder on your Desktop.

Help me open my project folder in VS Code

Add the HTML boilerplate and stylesheet

Your browser reads index.html as the entry point of your site. A separate style.css file keeps your styling organized and reusable.

  • In the Explorer sidebar, hover over the PORTFOLIO heading and click the New File icon (a page with a plus sign).
  • Type index.html and press Enter.
  • Paste the following code into index.html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Your Name | Front-End Developer</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Portfolio coming soon...</h1>
</body>
</html>

What does this code do?

  • The <!DOCTYPE html> and <html lang="en"> lines tell the browser this is a modern HTML page in English.
  • The viewport meta tag makes your page scale properly on phones and tablets.
  • The two preconnect links tell the browser to start connecting to Google Fonts early, so the font loads faster.
  • The Google Fonts link loads the Inter typeface at three weights: 400 (regular), 600 (semi-bold), and 700 (bold).
  • The <link rel="stylesheet" href="style.css"> line connects your CSS file to this HTML page.
  • Create another new file in the Explorer sidebar using the same New File icon.
  • Name it style.css and press Enter.
  • Paste the following code into style.css:
body {
    font-family: 'Inter', sans-serif;
}

What does this CSS do?

This rule tells the browser to display all text on the page in the Inter font. The sans-serif part is a fallback. If Inter fails to load, the browser uses its default sans-serif font instead.

  • Save both files by pressing Cmd+S (macOS) or Ctrl+S (Windows) in each tab.

See a white dot on the file tab?

A white dot on the tab name means the file has unsaved changes. Click into that tab and press Cmd+S (macOS) or Ctrl+S (Windows) to save it.

My file doesn't seem to be saving

✔️ Awesome, I've got everything!

Great. Make sure both files are saved (no dots on the tabs) before moving on.

ⓧ I'd like to double check the full code

Here is the complete index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Your Name | Front-End Developer</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Portfolio coming soon...</h1>
</body>
</html>

And here is the complete style.css:

body {
    font-family: 'Inter', sans-serif;
}
Open the page in your browser

Time to see your work. You will open the HTML file directly in your browser to confirm everything is linked correctly.

  • In the VS Code Explorer sidebar, right-click index.html.
  • Select Reveal in Finder (macOS) or Reveal in File Explorer (Windows).
  • Double-click index.html in the file manager window that opens. It will open in your default browser.

Before you look at the page, what do you expect the text to look like? Will it be in the browser's default serif font, or something different?

You should see a white page with the text "Portfolio coming soon..." displayed in the Inter font. Inter has a clean, modern look with rounded letterforms. It looks noticeably different from the browser's default Times New Roman serif font.

How do I know it's Inter?

Inter is a sans-serif font (no small strokes at the ends of letters). If you see smooth, rounded text without decorative strokes, the font loaded correctly. If the text looks like a newspaper (thin strokes with serifs), your Google Fonts link may have a typo.

Text looks like Times New Roman?

  • Check that your style.css file is saved and contains the font-family rule.
  • Confirm the <link rel="stylesheet" href="style.css"> line in index.html uses the exact filename style.css (not styles.css or Style.css).
  • Make sure you are connected to the internet. Google Fonts loads from the web.

Help me figure out why my font isn't loading

Your project skeleton is ready. Next up, you will fill this page with real portfolio content using semantic HTML.

Build the HTML Structure

Your project folder is set up and you can see placeholder text in the browser. Now you need to get all your actual portfolio content onto the page.

Before any visual design, you need your content structured in semantic HTML. Semantic elements like <header>, <main>, and <section> tell browsers and screen readers what each piece of content means. This makes your page accessible and gives you an immediate visible win.

In this step, get ready to:
  • Replace the placeholder with a header, navigation, main content area, and footer.
  • Fill each section with your portfolio content (name, bio, skills, projects, contact).
  • Verify all content appears in the browser as unstyled text.
Add the header and navigation

Every professional website starts with a navigation bar. Yours will contain a logo and links that let visitors jump to different sections of your page.

  • In VS Code, open index.html.
  • Find this line inside the <body> tags:
    <h1>Portfolio coming soon...</h1>
  • Delete that entire line and replace it with the following header code:
    <header>
        <nav class="navbar">
            <div class="logo">Portfolio</div>
            <div class="nav-links">
                <a href="#about">About</a>
                <a href="#skills">Skills</a>
                <a href="#projects">Projects</a>
                <a href="#contact">Contact</a>
            </div>
        </nav>
    </header>

What does this code do?

  • The <header> element wraps your site-wide navigation. Screen readers use this to identify the navigation area.
  • The <nav> with class="navbar" gives you a hook for styling later.
  • Each <a href="#about"> link points to a section ID further down the page. Clicking it scrolls the visitor there.
  • Save index.html and refresh your browser.
  • You should see the word "Portfolio" and four plain text links (About, Skills, Projects, Contact) at the top of the page.

Don't see the nav links?

  • Make sure you deleted the entire <h1>Portfolio coming soon...</h1> line before pasting the header code.
  • Check that your code is inside the <body> tags, not inside the <head> section.
  • My navigation links are not appearing in the browser.
Build the main content sections

The <main> element wraps all of your primary page content. Inside it, each <section> represents a distinct part of your portfolio.

  • Add the following code directly below the closing </header> tag to create your hero and about sections:
    <main>
        <section class="hero" id="home">
            <h1>Hi, I'm Your Name</h1>
            <p class="hero-subtitle">Front-End Developer</p>
            <a href="#projects" class="btn">View My Work</a>
        </section>

        <section class="about" id="about">
            <h2>About Me</h2>
            <p>I'm a passionate front-end developer learning to build modern, responsive websites. I focus on writing clean HTML, crafting beautiful CSS, and I'm currently expanding into JavaScript and React. I love turning designs into real, working web pages.</p>
        </section>

What does this code do?

  • The hero section is the first thing visitors see. It has your name as an <h1>, your role, and a call-to-action button that links to your projects.
  • The about section uses an <h2> heading and a paragraph to introduce who you are.
  • Each section has an id attribute that matches the nav links above, so clicking "About" scrolls straight here.
  • Save index.html and refresh your browser.
  • You should now see your name, "Front-End Developer", a "View My Work" link, and your about paragraph below the nav links.

Only seeing the nav but no hero content?

  • Make sure you pasted the code after the closing </header> tag, not inside the header.
  • Check that you included the opening <main> tag on the first line of this block.
  • My hero section content is not showing up.
  • Add the skills section directly below the closing </section> tag of the about section:
        <section class="skills" id="skills">
            <h2>My Skills</h2>
            <div class="skills-container">
                <div class="skill-item">HTML</div>
                <div class="skill-item">CSS</div>
                <div class="skill-item">JavaScript</div>
                <div class="skill-item">React</div>
                <div class="skill-item">Git</div>
                <div class="skill-item">VS Code</div>
            </div>
        </section>

What does this code do?

Each skill lives in its own <div class="skill-item"> inside a skills-container wrapper. This structure lets you style them as a row of boxes later with CSS Flexbox.

  • Add the projects section directly below the closing </section> tag of the skills section:
        <section class="projects" id="projects">
            <h2>My Projects</h2>
            <div class="projects-container">
                <div class="project-card">
                    <h3>Portfolio Website</h3>
                    <p>A responsive personal portfolio built with HTML and CSS. Features Flexbox layout and mobile-first design.</p>
                    <a href="#" class="project-link">View Project</a>
                </div>
                <div class="project-card">
                    <h3>Landing Page</h3>
                    <p>A product landing page with a hero section, feature grid, and contact form. Fully responsive.</p>
                    <a href="#" class="project-link">View Project</a>
                </div>
                <div class="project-card">
                    <h3>Blog Layout</h3>
                    <p>A clean blog layout with sidebar navigation, article cards, and category filtering.</p>
                    <a href="#" class="project-link">View Project</a>
                </div>
            </div>
        </section>

What does this code do?

  • Each project lives in its own project-card div with a title, description, and link.
  • The projects-container wrapper groups all three cards so you can lay them out side-by-side with Flexbox in the next step.
  • The href="#" placeholder links can be swapped for real URLs once you deploy these projects.
  • Save index.html and refresh your browser.
  • You should see six skill names and three project titles with descriptions appearing below your about paragraph.

Skills or projects not showing up?

  • Check that both sections are placed after the about section's closing </section> tag but still inside the <main> element.
  • Look for any missing closing tags. Each </div> must match an opening <div>.
  • My skills or projects section content is missing.
  • Add the contact section and footer directly below the closing </section> tag of the projects section:
        <section class="contact" id="contact">
            <h2>Get In Touch</h2>
            <p>I'm always open to new opportunities and collaborations.</p>
            <p class="contact-email">hello@yourname.com</p>
            <div class="contact-links">
                <a href="#" class="btn">LinkedIn</a>
                <a href="#" class="btn">GitHub</a>
            </div>
        </section>
    </main>

    <footer>
        <p>Built with HTML and CSS | 2026</p>
    </footer>

What does this code do?

  • The contact section gives visitors your email and links to your professional profiles.
  • The closing </main> tag marks the end of your primary content area.
  • The <footer> sits outside <main> because it is supplementary information, not primary content.
  • Save index.html and refresh your browser.
  • You should now see contact information, LinkedIn and GitHub links, and a footer line at the very bottom.

Footer not appearing at the bottom?

  • Make sure the </main> closing tag appears before the <footer> opening tag.
  • Check that the <footer> code is still inside the <body> tags.
  • My footer is not showing up at the bottom of the page.
Verify the complete page structure

Before you run any prediction, think about what you expect to see. You have added a header with navigation, five content sections, and a footer. None of it has styling beyond the Inter font.

  • What do you think the page looks like right now? Plain black text on a white background, stacked top to bottom, or something else?
  • Refresh your browser one more time and compare what you see against your prediction.

You should see all your content displayed from top to bottom: navigation links, your name and title, the about paragraph, skill names, project titles with descriptions, contact information, and the footer. It is unstyled (plain black text on white) but complete.

Why does it look so plain?

Your browser applies only its default styles (Times New Roman-like serif for most text, blue underlines on links). The only custom styling active is the Inter font from your style.css. This is exactly right. You now have a solid content foundation that any screen reader can parse and any search engine can index.

✔️ Awesome, I've got everything!

Great. Double check you have saved index.html and move on to the next step.

ⓧ I'd like to double check the full code

Your index.html is longer than a quick glance, so confirm each section is present in this order:

  • The <head> section with Google Fonts links and the stylesheet link (unchanged from Step 1).
  • A <header> containing a <nav class="navbar"> with a logo div and four nav links.
  • A <main> element containing five sections: hero, about, skills, projects, and contact.
  • The hero section with an <h1>, a subtitle paragraph, and a "View My Work" link.
  • The skills section with six skill-item divs inside a skills-container.
  • The projects section with three project-card divs inside a projects-container.
  • The contact section with an email paragraph and two button links.
  • A <footer> after the closing </main> tag.

If anything is missing, scroll up to the corresponding chunk and re-paste it into the correct position in your file.

Your raw content is on the page. Next up, you will transform this plain text into a professional-looking desktop layout with colors, spacing, and Flexbox.

Style the Page for Desktop

Your portfolio has all the content it needs, but right now it looks like a plain text document from 1995. No recruiter would take a second look at unstyled black-on-white text.

In this step, you will add typography, colors, spacing, and Flexbox layout to transform raw HTML into something you would actually send to a hiring manager. You will target desktop screens first.

In this step, get ready to:
  • Add a CSS reset and base typography styles.
  • Style the navigation, hero, and content sections with colors and spacing.
  • Use Flexbox to lay out skills and project cards side by side.
Add base styles, navigation, and hero

Every browser adds its own default margins and padding to elements. A CSS reset removes those defaults so your layout starts from a clean slate.

  • In VS Code, open style.css and replace everything in the file with this code:
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Inter', sans-serif;
    line-height: 1.6;
    color: #333333;
}

What does this code do?

  • The * selector targets every element on the page, stripping away default margins and padding.
  • The box-sizing: border-box rule makes padding count inside an element's width instead of adding to it. This prevents layout surprises.
  • The body gets line-height: 1.6 for comfortable reading spacing and a dark gray text color instead of harsh black.
  • Save style.css and refresh your browser.
  • You should see the text spacing change slightly and the color soften from pure black to dark gray. The default margins around the page disappear.

Now the navigation bar needs its own styling. It should be a dark strip across the top of the page with the logo on the left and links on the right.

  • Add the following code below the body rule in style.css:
/* Navigation */
.navbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem 2rem;
    background-color: #1a1a2e;
}

.logo {
    color: #ffffff;
    font-size: 1.5rem;
    font-weight: 700;
}

.nav-links a {
    color: #ffffff;
    text-decoration: none;
    margin-left: 2rem;
    font-weight: 400;
}

.nav-links a:hover {
    color: #0066ff;
}

What does this code do?

  • The display: flex on .navbar turns it into a Flexbox container. justify-content: space-between pushes the logo and links to opposite ends.
  • The dark navy background (#1a1a2e) with white text creates a strong visual header.
  • The :hover rule changes link color to blue when the cursor moves over them.
  • Save style.css and refresh your browser.
  • You should see a dark navy navigation bar across the top with "Portfolio" on the left and your links on the right in white.

Don't see the dark nav bar?

  • Make sure the class name .navbar in your CSS matches class="navbar" in your HTML exactly. CSS class names are case-sensitive.
  • Check that your code goes below the closing } of the body rule, not inside it.
  • Why isn't my navigation bar showing a dark background?

The hero section is the first thing visitors see. It deserves the same dark treatment as the nav, with your name displayed large and centered.

  • Add the following code below the navigation styles in style.css:
/* Hero Section */
.hero {
    background-color: #1a1a2e;
    color: #ffffff;
    text-align: center;
    padding: 6rem 2rem;
}

.hero h1 {
    font-size: 3rem;
    font-weight: 700;
    margin-bottom: 0.5rem;
}

.hero-subtitle {
    font-size: 1.25rem;
    margin-bottom: 2rem;
    color: #cccccc;
}

What does this code do?

  • The hero gets the same dark background as the nav, making them flow together visually.
  • The padding: 6rem 2rem gives generous vertical space (6rem top and bottom) so your name feels prominent.
  • The subtitle uses a lighter gray (#cccccc) to create visual hierarchy between your name and your role.
  • Save style.css and refresh your browser.
  • The top of your page should now be a large dark section with your name displayed big and centered, your subtitle underneath in lighter text, and the "View My Work" link below that (still unstyled as a plain link for now).
Style the skills and projects sections

The about section needs comfortable reading width. The skills and projects sections will use Flexbox to arrange items in rows.

  • Add the following code below the hero styles in style.css:
/* About Section */
.about {
    padding: 4rem 2rem;
    max-width: 800px;
    margin: 0 auto;
    text-align: center;
}

.about h2 {
    font-size: 2rem;
    margin-bottom: 1rem;
}

What does this code do?

  • The max-width: 800px keeps the text from stretching too wide on large monitors. Lines that are too long are hard to read.
  • The margin: 0 auto centers the section horizontally within the page.
  • Save and refresh. The about paragraph should now be centered with comfortable reading width instead of stretching edge to edge.

Now for the skills section. This is where Flexbox really shines. You will arrange skill items as a horizontal row that wraps onto new lines if needed.

  • Add the following code below the about styles in style.css:
/* Skills Section */
.skills {
    padding: 4rem 2rem;
    background-color: #f8f9fa;
    text-align: center;
}

.skills h2 {
    font-size: 2rem;
    margin-bottom: 2rem;
}

.skills-container {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem;
    max-width: 800px;
    margin: 0 auto;
}

.skill-item {
    background-color: #ffffff;
    border: 2px solid #0066ff;
    color: #0066ff;
    padding: 0.75rem 1.5rem;
    border-radius: 25px;
    font-weight: 600;
}

What does this code do?

  • The .skills-container uses display: flex to place items in a row. flex-wrap: wrap lets items wrap to the next line if the row gets full.
  • The gap: 1rem adds consistent spacing between items without needing margins on individual elements.
  • Each .skill-item gets a pill shape with border-radius: 25px and a blue border that makes the skills pop visually.
  • Save style.css and refresh your browser.
  • Your skills should now appear as blue-bordered pill-shaped boxes arranged in a horizontal row on a light gray background.

Skills stacking vertically instead of in a row?

  • Check that display: flex is on .skills-container (the parent div), not on .skill-item. Flexbox arranges the children of the element it is applied to.
  • Make sure skills-container in your CSS matches the class name in your HTML exactly.
  • Why are my Flexbox items not lining up in a row?

Next, the projects section. Each project card will sit side by side in a row, sharing space equally.

  • Add the following code below the skills styles in style.css:
/* Projects Section */
.projects {
    padding: 4rem 2rem;
    text-align: center;
}

.projects h2 {
    font-size: 2rem;
    margin-bottom: 2rem;
}

.projects-container {
    display: flex;
    gap: 2rem;
    max-width: 1000px;
    margin: 0 auto;
}

.project-card {
    flex: 1;
    border: 1px solid #e0e0e0;
    border-radius: 10px;
    padding: 2rem;
    text-align: left;
}

What does flex: 1 do?

When you give each .project-card the rule flex: 1, you are telling each card to grow equally and share the available space. Three cards with flex: 1 each take up one-third of the row.

The gap: 2rem on the container adds breathing room between cards without needing separate margin rules.

  • Save and refresh. Your three project cards should now sit side by side in a neat row with rounded borders.

The card boxes are in place, but the text inside them needs styling too.

  • Add the following code below the .project-card rule in style.css:
.project-card h3 {
    font-size: 1.25rem;
    margin-bottom: 0.75rem;
}

.project-card p {
    margin-bottom: 1rem;
    color: #666666;
}

.project-link {
    color: #0066ff;
    text-decoration: none;
    font-weight: 600;
}

.project-link:hover {
    text-decoration: underline;
}

What does this code do?

  • The paragraph text inside cards gets a lighter gray (#666666) to create hierarchy between headings and descriptions.
  • The .project-link removes the default underline and uses the accent blue color. The underline reappears only on hover as a subtle interaction signal.
  • Save style.css and refresh your browser.
  • Each project card should now show a bold title, lighter description text, and a blue "View Project" link. Hover over a link to see the underline appear.
Style the contact section and buttons

The hero's "View My Work" link still looks like plain text. A styled button makes it a clear call to action. The contact section and footer also need their finishing styles.

  • In style.css, find the /* About Section */ comment and add the following code directly above it:
/* Button */
.btn {
    display: inline-block;
    background-color: #0066ff;
    color: #ffffff;
    padding: 0.75rem 1.5rem;
    border-radius: 5px;
    text-decoration: none;
    font-weight: 600;
}

.btn:hover {
    background-color: #0052cc;
}

What does this code do?

  • The .btn class turns any link into a solid blue button with white text, rounded corners, and no underline.
  • The display: inline-block allows padding to work properly on the anchor tag (links are inline by default and ignore vertical padding).
  • The hover state darkens the blue slightly (#0052cc) to give a click feedback signal.
  • Save and refresh. The "View My Work" link in the hero should now appear as a solid blue button. The LinkedIn and GitHub links in the contact section also become blue buttons.

The contact section and footer are the last pieces. They complete the page's visual flow.

  • Add the following code at the very bottom of style.css (below the .project-link:hover rule):
/* Contact Section */
.contact {
    padding: 4rem 2rem;
    text-align: center;
    background-color: #f8f9fa;
}

.contact h2 {
    font-size: 2rem;
    margin-bottom: 1rem;
}

.contact-email {
    font-size: 1.25rem;
    font-weight: 600;
    color: #0066ff;
    margin: 1rem 0;
}

.contact-links {
    display: flex;
    justify-content: center;
    gap: 1rem;
    margin-top: 1.5rem;
}

/* Footer */
footer {
    background-color: #1a1a2e;
    color: #ffffff;
    text-align: center;
    padding: 1.5rem;
}

What does this code do?

  • The contact section gets the same light gray background as the skills section (#f8f9fa). Alternating white and gray backgrounds creates visual rhythm between sections.
  • The .contact-links uses Flexbox to center the LinkedIn and GitHub buttons side by side with a gap.
  • The footer matches the dark nav/hero color, bookending the page with a consistent dark frame.
  • Save style.css and refresh your browser.
  • The contact section should now show your email in blue, the LinkedIn and GitHub buttons centered side by side, and a dark footer at the very bottom.

Buttons not appearing side by side?

  • Confirm display: flex is on .contact-links (the wrapper div), not on the individual .btn elements inside it.
  • Check your HTML has class="contact-links" on the div wrapping the LinkedIn and GitHub links.
  • Why are my contact buttons stacking instead of sitting side by side?

Before you scroll through the full page, what do you expect to see when you look at it top to bottom? Think about the layout of each section.

Scroll through your page from top to bottom. You should see: a dark navigation bar, a large dark hero with your name and a blue button, a centered about paragraph, skills as blue-bordered pills in a row, three project cards side by side with styled text, a contact section with blue email and centered buttons, and a dark footer.

✔️ Awesome, I've got everything!

Great. Double check you have saved style.css and the page looks polished at full desktop width.

ⓧ I'd like to double check the full code

Your style.css should contain these sections in order. Scroll through your file and confirm each one is present:

  • CSS reset (* selector) and body styles at the top.
  • Navigation styles (.navbar, .logo, .nav-links a).
  • Hero section styles (.hero, .hero h1, .hero-subtitle).
  • Button styles (.btn and .btn:hover).
  • About section (.about with max-width: 800px).
  • Skills section (.skills-container with display: flex and .skill-item with pill styling).
  • Projects section (.projects-container with display: flex, .project-card with flex: 1, plus card content styles).
  • Contact section (.contact, .contact-email, .contact-links) and footer.

Your portfolio now looks professional on a desktop screen. The layout uses a consistent color scheme, clean typography from Google Fonts, and Flexbox to arrange content in polished rows. Next up, you will find out what happens when you shrink this page down to phone width.

Make It Responsive

Your portfolio looks professional on a wide desktop screen. The Flexbox layouts, consistent colors, and clean typography all work beautifully.

But what happens when someone views it on a phone? Over 60% of recruiters check portfolios on mobile devices. If your layout breaks at small screen widths, you lose that opportunity.

In this step, get ready to:
  • Observe how the desktop layout breaks on mobile-width screens.
  • Add a CSS media query that adjusts layout and spacing for small screens.
  • Test responsiveness using browser resize and DevTools mobile emulation.
See how the page breaks on mobile

Your page currently has no instructions for how to behave on a small screen. Every element uses the same sizing and direction regardless of how wide the browser window is.

  • Switch to your browser where the portfolio is open.
  • Before you resize, predict what you think will happen to the navigation links, project cards, and hero text when the window is phone-width (around 375px wide).
  • Grab the right edge of your browser window and drag it narrow until it is about phone-width.

You should see the layout falling apart. The navigation links crowd together or overflow. The three project cards are crushed into unreadable slivers side by side. The hero heading is far too large for the narrow space.

Why does this happen?

Your Flexbox containers are set to display items in a row. On desktop, there is plenty of room. On a narrow screen, Flexbox still tries to fit everything side by side, crushing each item to its minimum width.

CSS media queries solve this by letting you write rules that only activate below a certain screen width. You are about to add one.

  • Drag your browser window back to full desktop width so the page looks correct again.
Add the responsive media query

A media query tells the browser to apply certain styles only when the screen is below a specified width. You will add one that targets screens narrower than 768px.

  • Switch back to VS Code and open style.css.
  • Scroll to the very bottom of the file, below the footer styles.
  • Add the following responsive styles by pasting this code at the end of the file:
/* Responsive Design */
@media (max-width: 768px) {
    .navbar {
        flex-direction: column;
        gap: 1rem;
    }

    .nav-links a {
        margin-left: 1rem;
    }

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

    .hero {
        padding: 4rem 1.5rem;
    }

    .projects-container {
        flex-direction: column;
    }

    .about,
    .skills,
    .projects,
    .contact {
        padding: 3rem 1.5rem;
    }
}

What does this code do?

  • @media (max-width: 768px) wraps all the rules inside so they only apply when the browser window is 768px wide or narrower.
  • .navbar switches from a horizontal row to a vertical column, so the logo and links stack on top of each other.
  • .hero h1 shrinks from 3rem to 2rem so the heading fits on a small screen without overflowing.
  • .projects-container switches to a vertical column so project cards stack one per row instead of being crushed side by side.
  • The padding on all content sections is reduced so you do not waste precious screen space on a phone.
  • Save style.css.
  • Switch to your browser and refresh the page.
  • Drag the browser window narrow again. The navigation should now stack vertically, the project cards should sit one per row at full width, and the hero text should be a comfortable size.
  • Drag the window back to full width. Everything returns to the side-by-side desktop layout.

Layout still breaking on narrow screens?

  • Make sure the media query is at the very bottom of style.css, after all other rules. CSS reads top to bottom, so later rules override earlier ones.
  • Check that the opening @media (max-width: 768px) { has a matching closing } at the very end of the file. A missing brace silently breaks every rule inside.
  • Confirm your browser window is actually narrower than 768px. Drag it as narrow as it will go to be sure.

Still stuck? Help me fix my media query so my portfolio stacks on mobile.

Test with DevTools mobile emulation

Dragging the browser window gives you a rough idea of how the page responds. DevTools mobile emulation simulates an actual phone screen, giving you a more accurate preview.

  • Press F12 to open DevTools in your browser.
  • Click the Toggle device toolbar button (it looks like a phone and tablet icon) at the top of the DevTools panel. You can also press Cmd+Shift+M (macOS) or Ctrl+Shift+M (Windows).
  • Select a phone model from the device dropdown at the top (such as iPhone SE or Pixel 5).

Before you look at the result, predict: do you think the skills section will need any changes, or should it already wrap correctly?

The skills wrap neatly into multiple rows on their own. Your flex-wrap: wrap on the skills container handles this gracefully without any extra media query rules. The navigation stacks vertically, the hero heading is readable, project cards sit one per row at full width, and nothing overflows the screen.

  • Click the Toggle device toolbar button again to exit mobile emulation.
  • Resize your browser window between wide and narrow a few times. The layout should transition smoothly between desktop and mobile at the 768px breakpoint.

Why does flex-wrap handle skills but not projects?

The .skills-container uses flex-wrap: wrap, which lets items flow onto new lines when space runs out. Each skill item has a fixed size, so they wrap naturally.

The .projects-container uses flex: 1 on its children, which forces them to share available width equally. Without wrapping, they get crushed. Switching to flex-direction: column in the media query makes them stack instead.

✔️ Awesome, I've got everything!

Great. Double check you have saved style.css with the media query at the bottom.

ⓧ I'd like to double check the full code

Your index.html has not changed in this step. For style.css, scroll through your file and confirm these sections appear in this order:

  • The universal reset (* { margin: 0; ... }) and body styles at the top.
  • Navigation styles (.navbar, .logo, .nav-links a).
  • Hero section styles (.hero, .hero h1, .hero-subtitle).
  • Button styles (.btn).
  • About, Skills, Projects, Contact, and Footer section styles.
  • The responsive media query (@media (max-width: 768px) { ... }) at the very bottom, containing rules for .navbar, .nav-links a, .hero h1, .hero, .projects-container, and combined padding for .about, .skills, .projects, .contact.

Your portfolio now adapts beautifully to any screen size. Next up, you will tackle the Secret Mission and add hover animations plus CSS custom properties so you can retheme the entire site by changing just a few values.

Secret mission

Add Hover Animations and CSS Custom Properties

Your portfolio looks professional, but it feels static. In this secret mission, you will add smooth hover animations that make your project cards and skill items react to the cursor. You will also refactor every color into CSS custom properties so you can retheme the entire site by changing just a few values at the top of your stylesheet.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally, so there are no ongoing costs. Your files live on your computer and nothing is running in the background.

Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Resources you used:

  • The portfolio folder on your Desktop containing index.html and style.css.

Keep everything running

No action needed. Choose this if you are still actively building or want to keep improving your portfolio.

  • Your portfolio folder stays on your Desktop.
  • Continue customizing the content with your real name, projects, and contact info.
  • Consider hosting it for free on GitHub Pages or Netlify to get a live URL you can share with recruiters.

Pause - I'll come back to this later

Since this is a local project with no running processes, there is nothing to pause. Your files will be waiting for you whenever you return.

  • Your portfolio folder remains on your Desktop until you decide to work on it again.
  • No background processes or servers are running.

Delete - I don't want to use this again

Remove all project files from your computer.

  • Delete the portfolio folder from your Desktop by running this command in your terminal:
rm -rf ~/Desktop/portfolio

On Windows, run this instead:

rmdir /s /q "$HOME\Desktop\portfolio"
  • Confirm the folder is gone by running:
ls ~/Desktop

You should no longer see portfolio in the output.

Nice Work!

Nice Work!

You just built a professional portfolio resume page from scratch using nothing but HTML and CSS. This is a real, shareable piece of work that proves you can structure content, style it for desktop, and make it responsive for any screen size.

You've learned how to:

  • Build a complete single-page portfolio with semantic HTML (header, nav, main, sections, footer).
  • Style a page with CSS using Flexbox for layout, Google Fonts for typography, and a consistent color scheme.
  • Make a layout fully responsive with media queries so it works on mobile, tablet, and desktop.
  • Secret Mission: Added smooth hover animations and refactored all colors into CSS custom properties for instant site-wide theming.

Ready to quiz yourself?