Build Your Developer Portfolio
Build a responsive developer portfolio and publish it with GitHub Pages.
Introduction
30 Second Summary
Hiring managers often meet your work through a link before they meet you. A clear online home helps them understand your direction within seconds.
In this project, you will build a one-page developer portfolio that presents your introduction, skills, projects, and contact details. The finished site will be responsive, keyboard-friendly, and public through GitHub Pages.
What You'll Build
Share your finished portfolio link to show a polished page that introduces you, highlights your growing project collection, and works smoothly on desktop or mobile.
By the end of this project, you'll have:
- A clear developer introduction where visitors can scan your goals, current skills, learning focus, and contact details.
- A responsive and keyboard-friendly experience that adapts to narrow screens and keeps navigation visible for keyboard users.
- A public portfolio URL backed by Git so you can share your work and track every future improvement.
- Secret Mission: Add a light and dark theme button that remembers each visitor's choice.
Are there any prerequisites?
You need a Linux computer with Visual Studio Code installed. You also need a GitHub account plus basic file navigation skills.
Before We Start
Your portfolio becomes the public home for every project you build next. This is your moment to decide which junior developer role you are working toward and which quality you want your work to communicate.
Set Up Your Portfolio Workspace
Your future portfolio needs a dependable home before you add any real content. A visible starter page proves that the workspace can show your changes.
Visual Studio Code keeps the project files together. Git records every improvement from the first version onward.
In this step, get ready to:
- Verify or install Git on Linux.
- Configure the author identity attached to your commits.
- Build a Git-backed myportfolio workspace that previews a starter page.
Verify Git and set your commit identity
Visual Studio Code uses your installed copy of Git for source control. The first check tells you whether that connection can work.
- Start Visual Studio Code from your Linux application launcher.
- Create an integrated terminal from the top menu.
Before you run the check, what do you expect Git to report?
- Check whether Git is installed by running this command:
git --version
What does this command check?
The command asks Git to print its installed version. A version number confirms that Visual Studio Code can use the Git installation on your computer.
✔️ I see a version number
That check passed. Git is ready to track your portfolio files.
ⓧ Git is not installed
Git is installed through your Linux distribution's package manager. Use an administrator session because the installation changes system packages.
Debian or Ubuntu
- Install Git on Debian or Ubuntu by running this command:
apt-get install git
What does this command do?
The package manager downloads Git for Debian or Ubuntu. It also installs the package for system-wide use.
Fedora
- Install Git on Fedora by running this command:
dnf install git
What does this command do?
The package manager downloads Git for Fedora. It also installs the package for system-wide use.
Arch Linux
- Install Git on Arch Linux by running this command:
pacman -S git
What does this command do?
The package manager downloads Git for Arch Linux. It also installs the package for system-wide use.
- Confirm that the installation succeeded by running the version check again:
git --version
What should you see?
The terminal should now print a Git version number. That output confirms the command is available in your terminal.
Git still unavailable?
Close the current terminal after the installation. Create a new integrated terminal so it can detect the newly installed command.
If the installation reports a permissions problem, rerun it from a Linux administrator session.
Help me troubleshoot my Git installation.
Every Git commit records an author name plus an email address. Your email can be the address attached to your GitHub account or its no-reply address.
- Replace <your-name> with the name you want attached to your commits.
- Replace <your-email> with your GitHub email or GitHub-provided no-reply address.
- Configure both identity values by running the edited commands:
git config --global user.name "<your-name>"
git config --global user.email "<your-email>"
What do these commands configure?
The first command sets the author name recorded in future commits. The second command sets the matching author email.
The global setting applies this identity to repositories created with your Linux account. You only need to configure it once.
Your terminal returns to a blank prompt when Git accepts both settings. Your commit identity is now ready for this portfolio.
Identity commands not accepted?
Check that each value remains inside quotation marks. Replace both angle-bracket placeholders before running the commands.
Help me troubleshoot my Git identity.
Create and initialize the workspace
A Git repository stores its tracking data in a hidden .git folder. Starting on the main branch gives your project a clear first line of history.
- Select File from the Visual Studio Code top menu.
- Choose Open Folder... to display the folder picker.
The folder picker now lets you choose exactly where the portfolio workspace will live.
- Select your Desktop folder.
- Confirm the folder selection.
The Explorer sidebar now shows your Desktop. This location keeps the new myportfolio folder easy to find.
- Choose the trust option if Visual Studio Code asks about Workspace Trust.
- Create a new integrated terminal from the top menu.
- Create the myportfolio folder with a main Git branch by running these commands:
mkdir myportfolio
cd myportfolio
git init -b main
What do these commands create?
- The first command creates the myportfolio folder.
- The second command moves the terminal into that folder.
- The final command creates the hidden .git tracking data with main as the first branch.
The terminal confirms that it initialized a Git repository on main. Your portfolio now has a version-controlled home.
- Select File from the Visual Studio Code top menu.
- Choose Open Folder... to return to the folder picker.
The folder picker lets you switch Visual Studio Code from the Desktop to the new project workspace.
- Select the myportfolio folder on your Desktop.
- Confirm the folder selection.
Visual Studio Code now shows myportfolio at the top of the Explorer sidebar.
- Choose the trust option if Visual Studio Code asks about Workspace Trust.
Repository initialization failed?
Check that the terminal entered myportfolio before the initialization command ran. A folder with the same name may already exist on your Desktop.
Help me initialize my portfolio repository.
Create and preview the starter page
A minimal HTML document gives the browser something visible to render. The linked CSS file gives the next design step a ready-made home.
- Create index.html inside myportfolio using the Explorer sidebar's new-file control.
- Create styles.css inside myportfolio using the same control.
The Explorer sidebar should now list both files. Keep styles.css empty at this checkpoint.
- Select index.html in the Explorer sidebar.
- Add the starter document by pasting this code into the editor:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>My Portfolio</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>Portfolio workspace ready</h1>
</body>
</html>
What does this code do?
- The document declaration tells the browser to use modern HTML rules.
- The head stores the page title plus browser display settings.
- The stylesheet link connects styles.css to the page.
- The heading creates the visible confirmation message inside the browser.
- Save index.html using Visual Studio Code's save control.
Before you preview the page, what message do you expect the browser to render from the heading?
- Right-click index.html in the Explorer sidebar.
- Select Open in Integrated Browser.
You should see Portfolio workspace ready in a browser tab inside Visual Studio Code. That visible heading proves your editor and preview loop are working.
Starter message missing?
Confirm that you previewed index.html from the myportfolio Explorer sidebar. Save the file again if the browser shows an older version.
Check that the heading text sits between the opening and closing h1 tags.
Help me fix my starter page preview.
✔️ Awesome, I've got everything!
Your starter page and empty stylesheet now match the workspace needed for the next step.
ⓧ I'd like to double check the full code
- Compare your complete index.html file with this reference:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>My Portfolio</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>Portfolio workspace ready</h1>
</body>
</html>
What should match?
Your file should contain the same document structure. The visible heading should use the exact starter message shown in the reference.
The styles.css file should be completely empty at this checkpoint.
Your portfolio workspace is ready to record every improvement. Next up, you will replace the starter heading with the full semantic structure of your portfolio.
Build the Portfolio Structure
Your local Git repository now gives every portfolio change a safe history. The starter heading also proves that your integrated preview works.
A portfolio needs clear content before visual design can make it polished. Semantic HTML creates that usable structure first.
You will build the complete page with plain browser styling. This makes the limits of an empty CSS file easy to see.
In this step, get ready to:
- Build the semantic shell for the page.
- Write the visitor-facing introduction.
- Add proof of work plus a contact path.
Create the page landmarks and navigation
Page landmarks give browsers a map of the content. Internal links use section IDs to move visitors directly to the matching part of that map.
- Switch back to the index.html editor tab.
- Find the line containing <title>My Portfolio</title>.
- Replace that line with the page description plus the new title by pasting this code:
<meta
name="description"
content="Portfolio for an aspiring front-end developer building accessible web experiences."
/>
<title>Your Name | Front-End Developer</title>
What does this code do?
- The description metadata summarizes the portfolio for services that inspect the page.
- The title element gives the browser tab a specific page name.
- Save index.html.
- Switch back to the integrated browser from earlier.
- Use the browser tab's refresh control.
You should see Your Name | Front-End Developer as the browser tab title.
Still seeing the old tab title?
Confirm that you replaced the original title element inside head. Check that the file has been saved before refreshing the preview.
Help me check why my HTML page title is not updating.
The page body now needs landmarks for navigation plus a destination for its main content. The footer gives the document a clear ending.
- Switch back to the index.html editor tab.
- Find the opening <body> tag.
- Select everything from that opening tag through the closing </body> tag.
- Replace the selected body with the semantic shell by pasting this code:
<body>
<a class="skip-link" href="#main-content">Skip to main content</a>
<header class="site-header">
<nav class="nav container" aria-label="Primary navigation">
<a class="logo" href="#top">YN</a>
<ul class="nav-list">
<li><a href="#about">About</a></li>
<li><a href="#projects">Projects</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
</header>
<main id="main-content">
</main>
<footer class="site-footer">
<div class="container">
<p>Built by Your Name while learning front-end development.</p>
</div>
</footer>
</body>
How does the page shell work?
- The skip link points to #main-content so visitors can move directly to the page's primary content.
- The header contains the primary navigation.
- The navigation links point to section IDs that you will add next.
- The main landmark holds the portfolio content.
- The footer closes the page with a short ownership line.
- Save index.html.
- Switch back to the integrated browser.
- Refresh the page.
You should see a skip link plus the initials YN. You should also see the About, Projects, and Contact navigation links above the footer.
Navigation missing from the preview?
Check that the new markup sits between the opening <body> tag and the closing </body> tag. Confirm that each opening element has its matching closing element.
Help me find the broken element in my semantic page shell.
Build the hero and About content
The hero gives visitors the quickest summary of who you are. The About section adds your learning focus plus the skills you are building.
- Switch back to the index.html editor tab.
- Find the closing </main> tag.
- Place your cursor on the empty line immediately above that tag.
- Add the hero section by pasting this code:
<section class="hero" id="top">
<div class="container hero-content">
<p class="eyebrow">Hello, I'm</p>
<h1>Your Name</h1>
<p class="hero-copy">
An aspiring front-end developer building clear, accessible, and
responsive experiences for the web.
</p>
<a class="button" href="#projects">View my work</a>
</div>
</section>
What does the hero communicate?
- The top ID gives the logo link a destination at the start of the content.
- The main heading provides the portfolio owner's name.
- The summary states the developer role plus the qualities behind the work.
- The call-to-action link points directly to #projects.
- Save index.html.
- Switch back to the integrated browser.
- Refresh the page.
You should see the greeting plus the Your Name heading. You should also see the developer summary plus a View my work link.
Hero appearing below the footer?
Move the complete hero section above the closing </main> tag. Content placed after that tag sits outside the main landmark.
Help me place my hero section inside the main landmark.
Visitors now know the role behind the portfolio. The next section shows how that goal is turning into practical skills.
- Switch back to the index.html editor tab.
- Find the closing tag for the hero section.
- Place your cursor immediately after that closing tag.
- Add the About section by pasting this code:
<section class="section container" id="about">
<p class="section-label">About</p>
<h2>Learning by building useful things</h2>
<p class="section-copy">
I am developing practical web skills through focused projects. My
current goal is to create interfaces that are easy to understand,
comfortable to use, and ready for real people.
</p>
<h3>Current skills</h3>
<ul class="skills-list" aria-label="Current skills">
<li>HTML</li>
<li>CSS</li>
<li>Git</li>
<li>Responsive design</li>
</ul>
</section>
Why use a section and a list?
- The about ID connects this section to the About navigation link.
- The heading describes the section's learning theme.
- The paragraph explains the current development goal.
- The list groups the current skills into separate items.
- Save index.html.
- Switch back to the integrated browser.
- Refresh the page.
You should see an About heading plus a learning summary. The Current skills list should show HTML, CSS, Git, and Responsive design as separate items.
About link not moving to the section?
Confirm that the navigation link uses href="#about". Check that the section uses the matching id="about" value.
Help me match my About link to its section ID.
Add project proof and a contact path
Project cards turn your learning claims into visible examples. The first card presents this portfolio as current work.
- Switch back to the index.html editor tab.
- Find the closing tag for the about section.
- Place your cursor immediately after that closing tag.
- Add the Projects section plus the first project card by pasting this code:
<section class="section section-tinted" id="projects">
<div class="container">
<p class="section-label">Projects</p>
<h2>What I am building</h2>
<div class="projects-grid">
<article class="project-card">
<p class="project-status">Current project</p>
<h3>Developer Portfolio</h3>
<p>
A responsive personal site built with semantic HTML, modern
CSS, accessibility checks, Git, and GitHub Pages.
</p>
<ul class="tag-list" aria-label="Technologies used">
<li>HTML</li>
<li>CSS</li>
<li>GitHub Pages</li>
</ul>
</article>
</div>
</div>
</section>
How is a project card structured?
- The projects ID connects the section to two internal links.
- The article element wraps one self-contained project entry.
- The status distinguishes current work from future work.
- The technology list makes the tools easy to scan.
- Save index.html.
- Switch back to the integrated browser.
- Refresh the page.
You should see a Projects heading followed by a Developer Portfolio card. The card should list HTML, CSS, and GitHub Pages.
Project card missing its technology list?
Check that the tag-list sits inside the Developer Portfolio article. Confirm that every list item has a closing tag.
Help me repair the markup in my first project card.
One card shows what you are building now. A second card gives visitors a clear picture of where your roadmap goes next.
- Switch back to the index.html editor tab.
- Find the closing </article> tag for the Developer Portfolio card.
- Place your cursor immediately after that closing tag.
- Add the second project card by pasting this code:
<article class="project-card">
<p class="project-status">Coming next</p>
<h3>Responsive Landing Page</h3>
<p>
A product page that will explore flexible layouts, reusable
components, and mobile-first design decisions.
</p>
<ul class="tag-list" aria-label="Planned technologies">
<li>Flexbox</li>
<li>Grid</li>
<li>Accessibility</li>
</ul>
</article>
What does the second card add?
- The Coming next status separates planned work from the current project.
- The description previews the layout skills behind the future page.
- The planned technology list names Flexbox, Grid, and Accessibility.
- Save index.html.
- Switch back to the integrated browser.
- Refresh the page.
You should now see two separate project cards. The Responsive Landing Page card should appear after the Developer Portfolio card.
Second card appearing outside Projects?
Place the second article before the closing tag for projects-grid. Both project articles must share the same grid container.
Help me place both project cards inside the same grid container.
The final content section gives visitors a route to the code behind your work. The public profile link uses a clearly marked placeholder for now.
- Switch back to the index.html editor tab.
- Find the closing tag for the projects section.
- Place your cursor immediately after that closing tag.
- Add the Contact section by pasting this code:
<section class="section container" id="contact">
<div class="contact-panel">
<div>
<p class="section-label">Contact</p>
<h2>Let's connect</h2>
<p>
Follow my progress and explore the code behind each project on
GitHub.
</p>
</div>
<a class="button button-secondary" href="https://github.com/your-username">
Visit my GitHub
</a>
</div>
</section>
How does the contact section work?
- The contact ID gives the Contact navigation link a destination.
- The panel explains where visitors can follow your progress.
- The profile link uses the https://github.com/your-username placeholder until you personalize the page later.
- The link sends visitors to your public GitHub profile after you replace the placeholder.
- Save index.html.
- Switch back to the integrated browser.
- Refresh the page.
You should see a Contact heading plus a Visit my GitHub link. The footer should remain at the bottom of the document.
Contact section appearing after the footer?
Move the complete Contact section above the closing </main> tag. Keep the footer after that closing tag.
Help me restore the correct order of my Contact section plus footer.
Your finished structure should now match the complete file below. Use the second tab if you want to compare every element.
✔️ Awesome, I've got everything!
Your saved file now contains every portfolio section from this step.
ⓧ I'd like to double check the full code
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="description"
content="Portfolio for an aspiring front-end developer building accessible web experiences."
/>
<title>Your Name | Front-End Developer</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<a class="skip-link" href="#main-content">Skip to main content</a>
<header class="site-header">
<nav class="nav container" aria-label="Primary navigation">
<a class="logo" href="#top">YN</a>
<ul class="nav-list">
<li><a href="#about">About</a></li>
<li><a href="#projects">Projects</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
</header>
<main id="main-content">
<section class="hero" id="top">
<div class="container hero-content">
<p class="eyebrow">Hello, I'm</p>
<h1>Your Name</h1>
<p class="hero-copy">
An aspiring front-end developer building clear, accessible, and
responsive experiences for the web.
</p>
<a class="button" href="#projects">View my work</a>
</div>
</section>
<section class="section container" id="about">
<p class="section-label">About</p>
<h2>Learning by building useful things</h2>
<p class="section-copy">
I am developing practical web skills through focused projects. My
current goal is to create interfaces that are easy to understand,
comfortable to use, and ready for real people.
</p>
<h3>Current skills</h3>
<ul class="skills-list" aria-label="Current skills">
<li>HTML</li>
<li>CSS</li>
<li>Git</li>
<li>Responsive design</li>
</ul>
</section>
<section class="section section-tinted" id="projects">
<div class="container">
<p class="section-label">Projects</p>
<h2>What I am building</h2>
<div class="projects-grid">
<article class="project-card">
<p class="project-status">Current project</p>
<h3>Developer Portfolio</h3>
<p>
A responsive personal site built with semantic HTML, modern
CSS, accessibility checks, Git, and GitHub Pages.
</p>
<ul class="tag-list" aria-label="Technologies used">
<li>HTML</li>
<li>CSS</li>
<li>GitHub Pages</li>
</ul>
</article>
<article class="project-card">
<p class="project-status">Coming next</p>
<h3>Responsive Landing Page</h3>
<p>
A product page that will explore flexible layouts, reusable
components, and mobile-first design decisions.
</p>
<ul class="tag-list" aria-label="Planned technologies">
<li>Flexbox</li>
<li>Grid</li>
<li>Accessibility</li>
</ul>
</article>
</div>
</div>
</section>
<section class="section container" id="contact">
<div class="contact-panel">
<div>
<p class="section-label">Contact</p>
<h2>Let's connect</h2>
<p>
Follow my progress and explore the code behind each project on
GitHub.
</p>
</div>
<a class="button button-secondary" href="https://github.com/your-username">
Visit my GitHub
</a>
</div>
</section>
</main>
<footer class="site-footer">
<div class="container">
<p>Built by Your Name while learning front-end development.</p>
</div>
</footer>
</body>
</html>
Before you test the complete page, which internal link do you expect to move directly past the navigation?
- Refresh the integrated browser.
- Select the About navigation link.
- Select the Projects navigation link.
- Select the Contact navigation link.
Each navigation link should move the matching About, Projects, or Contact section into view.
- Select the View my work link.
- Select the YN logo link.
- Select the Skip to main content link.
View my work should move to Projects. The logo should return to the hero before the skip link moves to the main content.
You should now see visible hero, About, skills, Projects, Contact, and footer content in plain browser styling. That plain result proves the semantic structure works before design is added.
Internal link landing in the wrong place?
Compare each link's href value with its destination ID. The values must match exactly after the # character.
Help me match every internal portfolio link to the correct section ID.
Your portfolio now has meaningful content plus working navigation. Next, you will turn this plain document into a polished desktop design.
Turn the Structure into a Polished Design
Your semantic HTML gives each portfolio section a clear purpose. Default browser styling still leaves every section competing for attention.
CSS adds the visual hierarchy that helps visitors scan your work. This step builds the desktop design before a narrow-width check puts it under pressure.
In this step, get ready to:
- Create a reusable visual system for color, typography, spacing, and layout.
- Style the navigation, hero, buttons, cards, contact panel, and footer.
- Stress-test the two-column project grid at a narrow width.
Build the page's visual foundation
CSS variables store the colors and effects used throughout the page. The global rules then give every section a consistent starting point.
- Switch back to styles.css in the Visual Studio Code editor.
- Add the color system and global page foundation by pasting this code at the top of the empty file:
:root {
--background: #f8fafc;
--surface: #ffffff;
--surface-tinted: #eef2ff;
--text: #172033;
--muted: #526077;
--accent: #6d28d9;
--accent-dark: #4c1d95;
--border: #dbe3ee;
--header-background: rgb(248 250 252 / 94%);
--shadow: 0 18px 45px rgb(23 32 51 / 12%);
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
background: var(--background);
color: var(--text);
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
line-height: 1.6;
}
How does the visual system work?
- The variables in :root hold reusable colors, borders, and shadows for the whole portfolio.
- The universal selector makes element dimensions include their padding and borders.
- The body rule applies the page background, text color, system font, and line spacing.
- Save styles.css.
- Switch back to the integrated browser from earlier.
- Refresh the portfolio preview.
You should see the default page margin disappear. The portfolio now uses a pale background with dark system-font text.
Still seeing the original page spacing?
Confirm that the new rules are inside styles.css. Check that every opening brace has a matching closing brace.
If the preview still looks unchanged, help me check why my global CSS rules are not appearing.
- Switch back to styles.css.
- Add the link reset and large heading styles below the body rule by pasting:
a {
color: inherit;
}
h1,
h2,
h3,
p {
margin-top: 0;
}
h1 {
max-width: 12ch;
margin-bottom: 1rem;
font-size: clamp(3rem, 9vw, 6.5rem);
line-height: 0.95;
letter-spacing: -0.06em;
}
h2 {
max-width: 18ch;
margin-bottom: 1rem;
font-size: clamp(2rem, 5vw, 3.4rem);
line-height: 1.05;
letter-spacing: -0.04em;
}
What shapes the heading hierarchy?
- The grouped rule removes the browser's default top margin from headings and paragraphs.
- The clamp() values let the main headings grow with the viewport while keeping sensible limits.
- The width and letter-spacing rules give the headings a compact editorial shape.
- Save styles.css.
- Switch back to the integrated browser.
- Refresh the portfolio preview.
You should see a much larger name in the hero. The section headings now create a clear visual hierarchy.
Headings still look small?
Check that the h1 and h2 rules sit outside the body rule. A missing closing brace can hide both selectors.
If the sizes still do not change, help me debug my portfolio heading styles.
- Switch back to styles.css.
- Add the remaining heading, section, container, and hidden skip-link rules below the h2 rule by pasting:
h3 {
font-size: 1.25rem;
}
section {
scroll-margin-top: 6rem;
}
.container {
width: calc(100% - 2rem);
max-width: 1100px;
margin-inline: auto;
}
.skip-link {
position: fixed;
top: 1rem;
left: 1rem;
z-index: 20;
padding: 0.75rem 1rem;
border-radius: 0.5rem;
background: var(--text);
color: var(--surface);
transform: translateY(-160%);
}
What does this layout foundation do?
- The .container rule centers content within a maximum width while preserving space at both edges.
- The section offset leaves room for the sticky header when visitors follow an internal link.
- The skip link stays above the viewport until its keyboard focus behavior is added in the next step.
- Save styles.css.
- Switch back to the integrated browser.
- Refresh the portfolio preview.
You should see the content centered with even space along both edges. The skip link should no longer occupy space at the top of the page.
Content touching the browser edge?
Confirm that .container starts with a full stop. Check that the width calculation includes spaces around the minus sign.
If the content remains full width, help me debug my centered CSS container.
- Switch back to styles.css.
- Build the sticky header and circular logo below the .skip-link rule by pasting:
.site-header {
position: sticky;
top: 0;
z-index: 10;
border-bottom: 1px solid var(--border);
background: var(--header-background);
backdrop-filter: blur(12px);
}
.nav {
display: flex;
min-height: 4.5rem;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
.logo {
display: grid;
width: 2.75rem;
height: 2.75rem;
place-items: center;
border-radius: 50%;
background: var(--accent);
color: #ffffff;
font-weight: 800;
text-decoration: none;
}
How does the header stay useful?
- The sticky position keeps the header at the top while the portfolio scrolls.
- The navigation uses Flexbox to place the logo opposite the link list.
- The logo uses Grid alignment to center its initials inside a purple circle.
- Save styles.css.
- Switch back to the integrated browser.
- Refresh the portfolio preview.
- Scroll down the portfolio.
You should see a circular purple logo beside the navigation. The translucent header should remain at the top as you scroll.
Header scrolling out of view?
Check that position: sticky appears inside .site-header. Confirm that the same rule includes a top position.
If the header still moves away, help me debug my sticky portfolio header.
- Switch back to styles.css.
- Style the navigation list and hero layout below the .logo rule by pasting:
.nav-list {
display: flex;
gap: 1.5rem;
margin: 0;
padding: 0;
list-style: none;
}
.nav-list a {
color: var(--muted);
font-weight: 700;
text-decoration: none;
}
.nav-list a:hover {
color: var(--accent);
}
.hero {
display: grid;
min-height: 72vh;
place-items: center;
padding-block: 6rem;
}
How does this create a strong opening?
- The navigation list becomes a clean horizontal row without bullet markers.
- The link styles reduce visual noise until a visitor hovers over an item.
- The hero occupies most of the viewport and centers its content vertically.
- Save styles.css.
- Switch back to the integrated browser.
- Refresh the portfolio preview.
You should see the navigation links in a horizontal row. The hero now fills most of the opening screen.
Navigation still showing bullets?
Confirm that the class selector is .nav-list. Check that list-style: none appears inside that rule.
If the navigation remains vertical, help me debug my navigation list styles.
- Switch back to styles.css.
- Add the hero alignment, labels, and supporting copy below the .hero rule by pasting:
.hero-content {
display: grid;
justify-items: start;
}
.eyebrow,
.section-label,
.project-status {
margin-bottom: 0.75rem;
color: var(--accent);
font-size: 0.78rem;
font-weight: 800;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.hero-copy,
.section-copy {
max-width: 62ch;
color: var(--muted);
font-size: 1.1rem;
}
Why group these selectors?
- The eyebrow, section labels, and project status share one visual style because they perform the same labeling job.
- The hero and section copy share a readable line length with a muted color.
- Grouped selectors keep repeated design decisions in one place.
- Save styles.css.
- Switch back to the integrated browser.
- Refresh the portfolio preview.
You should see small purple labels above the major headings. The supporting paragraphs should appear muted with a comfortable line length.
Labels not turning purple?
Check that each selector in the grouped rule ends with a comma except .project-status. Confirm that the opening brace follows the final selector.
If only one label changes, help me repair my grouped CSS selectors.
- Switch back to styles.css.
- Style the primary and secondary buttons below the .section-copy rule by pasting:
.button {
display: inline-flex;
align-items: center;
justify-content: center;
margin-top: 1rem;
padding: 0.8rem 1.1rem;
border: 2px solid var(--accent);
border-radius: 0.65rem;
background: var(--accent);
color: #ffffff;
font-weight: 800;
text-decoration: none;
}
.button:hover {
border-color: var(--accent-dark);
background: var(--accent-dark);
}
.button-secondary {
background: transparent;
color: var(--accent);
}
How do the button styles differ?
- The shared .button rule gives both links a clear shape and strong label.
- The hover rule darkens the primary action when a pointer moves over it.
- The secondary modifier keeps the GitHub action transparent while preserving the shared border.
- Save styles.css.
- Switch back to the integrated browser.
- Refresh the portfolio preview.
You should see a solid purple button in the hero. The GitHub link should use a transparent secondary treatment.
Links still look like plain text?
Confirm that both portfolio links use the button class in index.html. Check that the CSS selector begins with a full stop.
If neither button changes, help me debug my portfolio button classes.
Style the portfolio sections and project cards
The portfolio now has a strong visual foundation. CSS Grid gives the project cards a structured desktop layout that visitors can scan quickly.
- Switch back to styles.css.
- Style the section spacing, tinted background, skill list, and technology tags below the .button-secondary rule by pasting:
.section {
padding-block: 5rem;
}
.section-tinted {
background: var(--surface-tinted);
}
.skills-list,
.tag-list {
display: flex;
flex-wrap: wrap;
gap: 0.65rem;
padding: 0;
list-style: none;
}
.skills-list li,
.tag-list li {
padding: 0.4rem 0.75rem;
border: 1px solid var(--border);
border-radius: 999px;
background: var(--surface);
color: var(--muted);
font-weight: 700;
}
What creates the section rhythm?
- Generous vertical padding separates each major part of the portfolio.
- The tinted projects section creates contrast without adding another strong color.
- The skill and technology items wrap into pill-shaped labels when space becomes limited.
- Save styles.css.
- Switch back to the integrated browser.
- Refresh the portfolio preview.
You should see wider spacing between sections. The skills and technology names should appear as bordered pills.
Lists still showing bullet markers?
Confirm that .skills-list and .tag-list are grouped before the opening brace. Check that the list items have matching class names in index.html.
If the pills remain unstyled, help me debug my skill and tag list CSS.
- Switch back to styles.css.
- Create the two-column CSS Grid and card styling below the skill and tag item rule by pasting:
.projects-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1.25rem;
margin-top: 2rem;
}
.project-card {
padding: 1.5rem;
border: 1px solid var(--border);
border-radius: 1rem;
background: var(--surface);
box-shadow: var(--shadow);
}
.project-card p:not(.project-status) {
color: var(--muted);
}
.tag-list li {
font-size: 0.82rem;
}
How does the project grid work?
- The repeat(2, minmax(0, 1fr)) value creates two equal columns.
- The minimum value of zero lets each card fit within its assigned column.
- The border, rounded corners, surface color, and shadow lift each project from the tinted section.
- Save styles.css.
- Switch back to the integrated browser.
- Refresh the portfolio preview.
You should see two equal project cards side by side. Each card should have a white surface with a soft border and shadow.
Project cards still stacked?
Confirm that the wrapper in index.html uses class="projects-grid". Check that the grid declaration is inside the matching CSS rule.
If the cards remain in one column, help me debug my two-column project grid.
- Switch back to styles.css.
- Finish the desktop design with the contact panel and footer rules below .tag-list li by pasting:
.contact-panel {
display: flex;
align-items: center;
justify-content: space-between;
gap: 2rem;
padding: 2rem;
border: 1px solid var(--border);
border-radius: 1rem;
background: var(--surface);
box-shadow: var(--shadow);
}
.site-footer {
padding-block: 2rem;
border-top: 1px solid var(--border);
color: var(--muted);
text-align: center;
}
.site-footer p {
margin-bottom: 0;
}
What completes the desktop layout?
- The contact panel places its message opposite the GitHub button on wide screens.
- The panel reuses the same surface, border, and shadow as the project cards.
- The centered footer closes the page with a quiet border and muted text.
- Save styles.css.
- Switch back to the integrated browser.
- Refresh the portfolio preview.
You should see the contact message beside its GitHub button. The footer should now have a top border with centered muted text.
Contact panel still arranged vertically?
Confirm that the wrapper uses class="contact-panel" in index.html. Check that display: flex appears inside the matching CSS rule.
If the panel remains unstyled, help me debug my contact panel layout.
✔️ Awesome, I've got everything!
Your complete desktop stylesheet is ready for the width test.
ⓧ I'd like to double check the full code
:root {
--background: #f8fafc;
--surface: #ffffff;
--surface-tinted: #eef2ff;
--text: #172033;
--muted: #526077;
--accent: #6d28d9;
--accent-dark: #4c1d95;
--border: #dbe3ee;
--header-background: rgb(248 250 252 / 94%);
--shadow: 0 18px 45px rgb(23 32 51 / 12%);
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
background: var(--background);
color: var(--text);
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
line-height: 1.6;
}
a {
color: inherit;
}
h1,
h2,
h3,
p {
margin-top: 0;
}
h1 {
max-width: 12ch;
margin-bottom: 1rem;
font-size: clamp(3rem, 9vw, 6.5rem);
line-height: 0.95;
letter-spacing: -0.06em;
}
h2 {
max-width: 18ch;
margin-bottom: 1rem;
font-size: clamp(2rem, 5vw, 3.4rem);
line-height: 1.05;
letter-spacing: -0.04em;
}
h3 {
font-size: 1.25rem;
}
section {
scroll-margin-top: 6rem;
}
.container {
width: calc(100% - 2rem);
max-width: 1100px;
margin-inline: auto;
}
.skip-link {
position: fixed;
top: 1rem;
left: 1rem;
z-index: 20;
padding: 0.75rem 1rem;
border-radius: 0.5rem;
background: var(--text);
color: var(--surface);
transform: translateY(-160%);
}
.site-header {
position: sticky;
top: 0;
z-index: 10;
border-bottom: 1px solid var(--border);
background: var(--header-background);
backdrop-filter: blur(12px);
}
.nav {
display: flex;
min-height: 4.5rem;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
.logo {
display: grid;
width: 2.75rem;
height: 2.75rem;
place-items: center;
border-radius: 50%;
background: var(--accent);
color: #ffffff;
font-weight: 800;
text-decoration: none;
}
.nav-list {
display: flex;
gap: 1.5rem;
margin: 0;
padding: 0;
list-style: none;
}
.nav-list a {
color: var(--muted);
font-weight: 700;
text-decoration: none;
}
.nav-list a:hover {
color: var(--accent);
}
.hero {
display: grid;
min-height: 72vh;
place-items: center;
padding-block: 6rem;
}
.hero-content {
display: grid;
justify-items: start;
}
.eyebrow,
.section-label,
.project-status {
margin-bottom: 0.75rem;
color: var(--accent);
font-size: 0.78rem;
font-weight: 800;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.hero-copy,
.section-copy {
max-width: 62ch;
color: var(--muted);
font-size: 1.1rem;
}
.button {
display: inline-flex;
align-items: center;
justify-content: center;
margin-top: 1rem;
padding: 0.8rem 1.1rem;
border: 2px solid var(--accent);
border-radius: 0.65rem;
background: var(--accent);
color: #ffffff;
font-weight: 800;
text-decoration: none;
}
.button:hover {
border-color: var(--accent-dark);
background: var(--accent-dark);
}
.button-secondary {
background: transparent;
color: var(--accent);
}
.section {
padding-block: 5rem;
}
.section-tinted {
background: var(--surface-tinted);
}
.skills-list,
.tag-list {
display: flex;
flex-wrap: wrap;
gap: 0.65rem;
padding: 0;
list-style: none;
}
.skills-list li,
.tag-list li {
padding: 0.4rem 0.75rem;
border: 1px solid var(--border);
border-radius: 999px;
background: var(--surface);
color: var(--muted);
font-weight: 700;
}
.projects-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1.25rem;
margin-top: 2rem;
}
.project-card {
padding: 1.5rem;
border: 1px solid var(--border);
border-radius: 1rem;
background: var(--surface);
box-shadow: var(--shadow);
}
.project-card p:not(.project-status) {
color: var(--muted);
}
.tag-list li {
font-size: 0.82rem;
}
.contact-panel {
display: flex;
align-items: center;
justify-content: space-between;
gap: 2rem;
padding: 2rem;
border: 1px solid var(--border);
border-radius: 1rem;
background: var(--surface);
box-shadow: var(--shadow);
}
.site-footer {
padding-block: 2rem;
border-top: 1px solid var(--border);
color: var(--muted);
text-align: center;
}
.site-footer p {
margin-bottom: 0;
}
How to use this reference
This is the complete styles.css file for the desktop design. Compare its selector order, braces, and values with your file.
Before your final check, which layout do you expect to hold up better when the available width shrinks?
- Widen the integrated browser preview until both project cards have comfortable space.
You should see a polished portfolio with a sticky header, high-contrast hero, skill pills, two project columns, and a clear contact panel.
- Narrow the integrated browser preview until it resembles a phone screen.
You should see the navigation wrap awkwardly. The two project cards should feel cramped inside their narrow columns.
This shortfall is intentional
The stylesheet currently asks the project grid to keep two equal columns at every width. Your narrow-width test has exposed the limits of that desktop-only decision.
Your desktop portfolio now has a complete visual system with clear hierarchy. Next, you will repair the narrow layout and make keyboard focus visible.
Fix the Mobile Layout and Keyboard Experience
Your polished desktop portfolio exposed a clear limitation in the previous step. Its two-column CSS Grid layout becomes cramped when the preview narrows.
This step uses responsive design to repair the mobile layout. You will also add keyboard accessibility styles so visitors can see which link or button has focus.
In this step, get ready to:
- Change the portfolio to a readable one-column layout below 700 pixels.
- Make the skip link and keyboard focus indicators visible.
- Add public portfolio details and test every layout and link.
Repair the mobile layout
A media query applies styles when the viewport meets a condition. At widths of 700 pixels or less, your query rearranges the parts that felt cramped during the previous test.
- In styles.css, scroll below the .site-footer p rule.
- Add the mobile layout rules by pasting this code at the end of styles.css:
@media (max-width: 700px) {
.nav {
min-height: auto;
align-items: flex-start;
padding-block: 0.85rem;
}
.nav-list {
flex-wrap: wrap;
justify-content: flex-end;
gap: 0.75rem 1rem;
}
.hero {
min-height: auto;
padding-block: 5rem 3.5rem;
}
.projects-grid {
grid-template-columns: 1fr;
}
.contact-panel {
align-items: flex-start;
flex-direction: column;
}
}
What Does This Code Do?
- The @media condition activates these rules when the viewport is 700 pixels wide or narrower.
- The navigation can wrap into the available space with smaller gaps.
- The hero uses less vertical space on a small screen.
- The project cards and contact panel stack into readable single-column layouts.
- Save styles.css.
- Switch back to the integrated browser from earlier.
- Narrow the preview to less than 700 pixels wide.
You should see the project cards form one column. The contact content should also stack vertically.
The navigation should wrap within the available width. The hero should take up less vertical space.
Still Seeing Two Project Columns?
Confirm that the media query sits after the existing desktop styles in styles.css. Later rules can override the original two-column setting.
Check that .projects-grid contains grid-template-columns: 1fr; inside the media query.
Ask for help with the mobile CSS rules.
Make keyboard focus visible
Keyboard users move through interactive elements with the Tab key. A visible focus state shows which element receives the next keyboard action.
Your skip link already points to #main-content. Its focus style moves it onscreen when a keyboard user reaches it.
- In styles.css, find the closing brace for the .skip-link rule.
- Place this focus rule immediately below the .skip-link rule:
.skip-link:focus-visible {
transform: translateY(0);
}
How the Skip Link Appears
The base .skip-link style positions the link above the visible page. The focus rule resets its transform so keyboard users can see and activate it.
- Save styles.css.
- Refresh the integrated browser preview.
- Press the Tab key until the skip link receives focus.
You should see the Skip to main content link move into the top-left corner of the page.
Skip Link Staying Hidden?
Check that the selector includes the colon in .skip-link:focus-visible. Confirm that the rule appears after the base .skip-link styles.
Ask for help with the skip link focus state.
- In styles.css, find the .site-footer p rule above the mobile media query.
- Add the shared focus outline immediately below that rule:
a:focus-visible,
button:focus-visible {
outline: 3px solid #f59e0b;
outline-offset: 4px;
}
Why Use Focus Visible?
The :focus-visible selector shows the outline when the browser determines that focus should be visible. The orange outline creates a clear cue without removing the browser's keyboard behavior.
- Save styles.css.
- Refresh the integrated browser preview.
- Press the Tab key repeatedly to move through the portfolio links.
You should see an orange outline around each focused navigation link. The same outline should appear around the portfolio buttons.
Focus Outline Missing?
Confirm that you are using the Tab key to move focus. Check that both selectors include :focus-visible.
Make sure the outline rule sits outside the media query. This keeps keyboard focus visible at every viewport width.
Ask for help with the keyboard outline.
Use these tabs to compare your complete stylesheet before moving to your public content.
✔️ Awesome, I've got everything!
Your responsive layout and keyboard focus styles are saved in styles.css.
ⓧ I'd like to double check the full code
Compare your stylesheet with this complete responsive version.
:root {
--background: #f8fafc;
--surface: #ffffff;
--surface-tinted: #eef2ff;
--text: #172033;
--muted: #526077;
--accent: #6d28d9;
--accent-dark: #4c1d95;
--border: #dbe3ee;
--header-background: rgb(248 250 252 / 94%);
--shadow: 0 18px 45px rgb(23 32 51 / 12%);
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
background: var(--background);
color: var(--text);
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
line-height: 1.6;
}
a {
color: inherit;
}
h1,
h2,
h3,
p {
margin-top: 0;
}
h1 {
max-width: 12ch;
margin-bottom: 1rem;
font-size: clamp(3rem, 9vw, 6.5rem);
line-height: 0.95;
letter-spacing: -0.06em;
}
h2 {
max-width: 18ch;
margin-bottom: 1rem;
font-size: clamp(2rem, 5vw, 3.4rem);
line-height: 1.05;
letter-spacing: -0.04em;
}
h3 {
font-size: 1.25rem;
}
section {
scroll-margin-top: 6rem;
}
.container {
width: calc(100% - 2rem);
max-width: 1100px;
margin-inline: auto;
}
.skip-link {
position: fixed;
top: 1rem;
left: 1rem;
z-index: 20;
padding: 0.75rem 1rem;
border-radius: 0.5rem;
background: var(--text);
color: var(--surface);
transform: translateY(-160%);
}
.skip-link:focus-visible {
transform: translateY(0);
}
.site-header {
position: sticky;
top: 0;
z-index: 10;
border-bottom: 1px solid var(--border);
background: var(--header-background);
backdrop-filter: blur(12px);
}
.nav {
display: flex;
min-height: 4.5rem;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
.logo {
display: grid;
width: 2.75rem;
height: 2.75rem;
place-items: center;
border-radius: 50%;
background: var(--accent);
color: #ffffff;
font-weight: 800;
text-decoration: none;
}
.nav-list {
display: flex;
gap: 1.5rem;
margin: 0;
padding: 0;
list-style: none;
}
.nav-list a {
color: var(--muted);
font-weight: 700;
text-decoration: none;
}
.nav-list a:hover {
color: var(--accent);
}
.hero {
display: grid;
min-height: 72vh;
place-items: center;
padding-block: 6rem;
}
.hero-content {
display: grid;
justify-items: start;
}
.eyebrow,
.section-label,
.project-status {
margin-bottom: 0.75rem;
color: var(--accent);
font-size: 0.78rem;
font-weight: 800;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.hero-copy,
.section-copy {
max-width: 62ch;
color: var(--muted);
font-size: 1.1rem;
}
.button {
display: inline-flex;
align-items: center;
justify-content: center;
margin-top: 1rem;
padding: 0.8rem 1.1rem;
border: 2px solid var(--accent);
border-radius: 0.65rem;
background: var(--accent);
color: #ffffff;
font-weight: 800;
text-decoration: none;
}
.button:hover {
border-color: var(--accent-dark);
background: var(--accent-dark);
}
.button-secondary {
background: transparent;
color: var(--accent);
}
.section {
padding-block: 5rem;
}
.section-tinted {
background: var(--surface-tinted);
}
.skills-list,
.tag-list {
display: flex;
flex-wrap: wrap;
gap: 0.65rem;
padding: 0;
list-style: none;
}
.skills-list li,
.tag-list li {
padding: 0.4rem 0.75rem;
border: 1px solid var(--border);
border-radius: 999px;
background: var(--surface);
color: var(--muted);
font-weight: 700;
}
.projects-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1.25rem;
margin-top: 2rem;
}
.project-card {
padding: 1.5rem;
border: 1px solid var(--border);
border-radius: 1rem;
background: var(--surface);
box-shadow: var(--shadow);
}
.project-card p:not(.project-status) {
color: var(--muted);
}
.tag-list li {
font-size: 0.82rem;
}
.contact-panel {
display: flex;
align-items: center;
justify-content: space-between;
gap: 2rem;
padding: 2rem;
border: 1px solid var(--border);
border-radius: 1rem;
background: var(--surface);
box-shadow: var(--shadow);
}
.site-footer {
padding-block: 2rem;
border-top: 1px solid var(--border);
color: var(--muted);
text-align: center;
}
.site-footer p {
margin-bottom: 0;
}
a:focus-visible,
button:focus-visible {
outline: 3px solid #f59e0b;
outline-offset: 4px;
}
@media (max-width: 700px) {
.nav {
min-height: auto;
align-items: flex-start;
padding-block: 0.85rem;
}
.nav-list {
flex-wrap: wrap;
justify-content: flex-end;
gap: 0.75rem 1rem;
}
.hero {
min-height: auto;
padding-block: 5rem 3.5rem;
}
.projects-grid {
grid-template-columns: 1fr;
}
.contact-panel {
align-items: flex-start;
flex-direction: column;
}
}
Personalize and test the portfolio
Your next step publishes this page through GitHub Pages. Public details replace the sample text so visitors understand who you are and what you are learning.
Publishing personal information can feel exposing. You control what appears, so include only details you are comfortable sharing publicly.
- In index.html, replace every Your Name placeholder with your public name.
- Replace YN with the initials you want in the circular logo.
- Replace the sample hero summary with a short description of the developer role you are working toward.
- Replace the sample about text with your current learning focus.
- Replace your-username in https://github.com/your-username with your GitHub username.
- Save index.html.
The full-file reference keeps the original placeholders. Preserve your personalized text while comparing the surrounding HTML structure.
✔️ Awesome, I've got everything!
Your public name, summary, learning focus, initials, and GitHub username now appear in index.html.
ⓧ I'd like to double check the full code
Compare the structure with this reference. Keep your own public details in place of its sample placeholders.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="description"
content="Portfolio for an aspiring front-end developer building accessible web experiences."
/>
<title>Your Name | Front-End Developer</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<a class="skip-link" href="#main-content">Skip to main content</a>
<header class="site-header">
<nav class="nav container" aria-label="Primary navigation">
<a class="logo" href="#top">YN</a>
<ul class="nav-list">
<li><a href="#about">About</a></li>
<li><a href="#projects">Projects</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
</header>
<main id="main-content">
<section class="hero" id="top">
<div class="container hero-content">
<p class="eyebrow">Hello, I'm</p>
<h1>Your Name</h1>
<p class="hero-copy">
An aspiring front-end developer building clear, accessible, and
responsive experiences for the web.
</p>
<a class="button" href="#projects">View my work</a>
</div>
</section>
<section class="section container" id="about">
<p class="section-label">About</p>
<h2>Learning by building useful things</h2>
<p class="section-copy">
I am developing practical web skills through focused projects. My
current goal is to create interfaces that are easy to understand,
comfortable to use, and ready for real people.
</p>
<h3>Current skills</h3>
<ul class="skills-list" aria-label="Current skills">
<li>HTML</li>
<li>CSS</li>
<li>Git</li>
<li>Responsive design</li>
</ul>
</section>
<section class="section section-tinted" id="projects">
<div class="container">
<p class="section-label">Projects</p>
<h2>What I am building</h2>
<div class="projects-grid">
<article class="project-card">
<p class="project-status">Current project</p>
<h3>Developer Portfolio</h3>
<p>
A responsive personal site built with semantic HTML, modern
CSS, accessibility checks, Git, and GitHub Pages.
</p>
<ul class="tag-list" aria-label="Technologies used">
<li>HTML</li>
<li>CSS</li>
<li>GitHub Pages</li>
</ul>
</article>
<article class="project-card">
<p class="project-status">Coming next</p>
<h3>Responsive Landing Page</h3>
<p>
A product page that will explore flexible layouts, reusable
components, and mobile-first design decisions.
</p>
<ul class="tag-list" aria-label="Planned technologies">
<li>Flexbox</li>
<li>Grid</li>
<li>Accessibility</li>
</ul>
</article>
</div>
</div>
</section>
<section class="section container" id="contact">
<div class="contact-panel">
<div>
<p class="section-label">Contact</p>
<h2>Let's connect</h2>
<p>
Follow my progress and explore the code behind each project on
GitHub.
</p>
</div>
<a class="button button-secondary" href="https://github.com/your-username">
Visit my GitHub
</a>
</div>
</section>
</main>
<footer class="site-footer">
<div class="container">
<p>Built by Your Name while learning front-end development.</p>
</div>
</footer>
</body>
</html>
Before your final check, what should stay readable as the preview moves from desktop width to less than 700 pixels?
- Refresh the integrated browser preview.
- Check the portfolio at a wide desktop width.
- Resize the preview to less than 700 pixels wide.
- Test each internal navigation link one at a time.
- Press the Tab key repeatedly to check the focus order.
- Activate the skip link to move focus to the main content.
- Open the Visit my GitHub link to confirm it reaches your public profile.
At desktop width, you should see the polished two-column project layout. Below 700 pixels, you should see one project column with stacked contact content.
Tab navigation should reveal the skip link first. Each navigation link and button should receive a visible orange outline.
That is the accessibility and responsive-design pass complete. Your portfolio now adapts to narrow screens while keeping every interactive element visible to keyboard users.
Your portfolio is responsive, personalized, and keyboard-friendly. Next up, you will commit this version and publish it with GitHub Pages.
Publish the Portfolio with GitHub Pages
Your portfolio now adapts to desktop and mobile screens. It also gives keyboard users a clear route through the page.
Only your local computer can display this version right now. A hiring manager needs a public address that works from any browser.
Git records the finished files in a commit. GitHub hosts that commit in a public repository.
GitHub Pages turns the repository into a public website. This gives your portfolio a repeatable publishing workflow.
In this step, get ready to:
- Save the responsive portfolio as a Git commit.
- Publish the repository publicly on GitHub.
- Deploy the portfolio through GitHub Pages.
Commit the responsive portfolio
A commit preserves the current version of your project as a named milestone. The Source Control view in Visual Studio Code creates that milestone inside your existing repository.
- Press Ctrl+Shift+G to return to the Source Control view.
- Select the plus icon beside index.html to stage the file.
- Select the plus icon beside styles.css to stage the file.
- Enter Build responsive portfolio in the commit message box.
- Select the checkmark icon at the top of Source Control to create the commit.
- Confirm that no changed files remain in the Source Control view.
The clean Source Control view shows that index.html and styles.css are stored in the commit. Your finished local version now has a recoverable milestone.
Publish the repository to GitHub
Publishing creates a remote copy of your repository on GitHub. It also connects your local main branch to that remote copy.
This next action makes your repository public. Your portfolio contains only the details you chose to share.
- Press Ctrl+Shift+P to open the Command Palette.
- Enter Publish to GitHub in the Command Palette.
- Select Publish to GitHub from the results.
- Complete the GitHub browser sign-in if prompted.
- Return to Visual Studio Code after GitHub confirms access.
- Enter myportfolio when Visual Studio Code asks for the repository name.
- Choose the public repository option.
- Wait for Visual Studio Code to confirm that publishing has finished.
The publishing confirmation means your commit has reached GitHub. Your local repository now has a remote destination.
- Return to the browser where you are signed in to GitHub.
- Select the myportfolio repository from your profile.
You should see main as the active branch. The file list should contain index.html and styles.css.
Repository not visible?
- Return to the browser authorization page to confirm that GitHub approved Visual Studio Code.
- Return to Source Control to confirm that the commit still has no uncommitted files.
- Repeat the publishing flow after confirming your internet connection.
Help me troubleshoot publishing my repository.
Deploy the site with GitHub Pages
GitHub Pages can publish the static files directly from a repository branch. Your index.html file already sits in the repository root.
- Select Settings in the myportfolio repository navigation.
- Select Pages in the repository settings sidebar.
- Set Source under Build and deployment to Deploy from a branch.
- Set the branch to main.
- Set the folder to /(root).
- Select Save.
GitHub Pages now starts a deployment from the committed files on main.
A quiet Pages screen is normal during the first deployment's 10-minute window.
- Wait for Visit site to appear in the GitHub Pages area.
Before you open the site, do you expect its layout to match your local preview?
- Select Visit site.
At a wide browser width, you should see the polished two-column portfolio from Visual Studio Code. The public page now matches your desktop preview.
- Record your published address here: https://<your-username>.github.io/myportfolio/.
- Narrow the published page below 700px.
You should see the project cards form one column. The navigation should wrap while the contact panel stacks vertically.
Site still unavailable?
- Confirm that Source shows Deploy from a branch.
- Confirm that the selected branch is main.
- Confirm that the selected folder is /(root).
- Allow the full 10 minutes before checking the deployment again.
Help me troubleshoot my GitHub Pages deployment.
You did it. Your responsive portfolio now has a public address that you can share with a hiring manager.
Secret mission
Add a Persistent Theme Switcher
Give visitors control over your portfolio's appearance with a light and dark theme button. Save their choice so the published site keeps the selected theme after a refresh.
Clean Up Your Resources
Clean Up Your Resources
GitHub Free keeps this public repository with its GitHub Pages deployment at $0. Decide whether to keep everything available, unpublish the site for later, or delete the project resources.
Resources you used:
- Public GitHub Pages deployment at https://<your-username>.github.io/myportfolio/.
- Public GitHub repository named myportfolio with committed files on main.
- Local myportfolio folder containing the Git repository plus index.html, styles.css, and script.js.
Keep everything running
No action is needed. Choose this option if you want visitors to keep using your published portfolio.
- The public portfolio remains available at https://<your-username>.github.io/myportfolio/.
- The public myportfolio repository remains available for future updates.
- The local myportfolio folder remains available for continued development.
Pause - I'll come back to this later
Unpublishing takes the portfolio offline while preserving both copies of your code.
- Return to the myportfolio repository on GitHub.
- Click Settings.
- Select Pages.
- Open the menu beside Your site is live at.
- Select Unpublish site.
- Visit https://<your-username>.github.io/myportfolio/ to confirm the portfolio is no longer published.
Your deployment is now paused. The GitHub repository remains available when you are ready to publish again.
Delete - I don't want to use this again
This option permanently removes the hosted deployment, public repository, and local workspace. Repository deletion is destructive.
The public deployment is the first resource to remove.
- Return to the myportfolio repository on GitHub.
- Click Settings.
- Select Pages.
- Open the menu beside Your site is live at.
- Select Unpublish site.
- Visit https://<your-username>.github.io/myportfolio/ to confirm the portfolio is no longer published.
The deployment is offline. The repository can now be removed.
- Return to the myportfolio repository on GitHub.
- Click Settings.
- Select General.
- Scroll to Danger Zone.
- Click Delete this repository.
- Complete GitHub's confirmation steps to remove the repository.
- Confirm myportfolio no longer appears in your GitHub repository list.
Your local folder is the final project resource.
- Locate the existing myportfolio folder with your Linux file manager.
- Delete the myportfolio folder.
- Confirm myportfolio no longer appears in its parent folder.
Cleanup complete. Your hosted deployment, public repository, and local workspace are removed.
Nice Work!
Nice Work!
You made it! Your responsive developer portfolio is now a public showcase for your skills and project work.
You've learned how to:
- Built a one-page developer portfolio with semantic HTML. Presented your introduction, skills, projects, and contact details in clear sections.
- Created a responsive design with CSS variables plus CSS Grid. Repaired the cramped mobile layout with a media query. Added skip navigation for keyboard users. Kept focus visible across links and buttons.
- Tracked every change with Git. Published a shareable website through GitHub Pages.
- Secret Mission: Built a persistent light and dark theme switcher with JavaScript. Saved each visitor's choice with localStorage.
Ready to quiz yourself?