Build a Design Portfolio Website
Build and deploy a responsive design portfolio site to GitHub Pages.
Introduction
30 Second Summary
You have design work you are proud of, but it lives on your hard drive where no one can see it. A portfolio website changes that by giving you a permanent, shareable link to show your work to clients and employers.
In this project, you will build a live portfolio website from scratch using HTML and CSS, then deploy it to GitHub Pages so anyone with the link can view your design projects.
What You'll Build
A minimal, modern design portfolio website with clean typography, a responsive project grid, and subtle hover interactions, deployed live to your own URL.
By the end of this project, you'll have:
- A complete HTML file with semantic structure and a CSS stylesheet using custom properties and CSS Grid.
- A two-column responsive project grid that showcases your design work and adapts to any screen size.
- A live, shareable website at your own github.io URL that anyone can visit.
- Secret Mission: Add a dark mode toggle that switches your portfolio between light and dark themes using CSS custom properties and a touch of JavaScript.
Are there any prerequisites?
No prior coding experience is required. This guide walks you through installing every tool you need, including Git and setting up a GitHub account. You just need a computer with VS Code installed and a few design project images ready to showcase.
Set Up Your Tools
Before you can build and deploy your portfolio, you need two things: a way to track your code changes and a place to host your website.
In this step, you will install Git for version control, create a GitHub account for hosting, and set up your project folder in VS Code.
In this step, get ready to:
- Install and configure Git on your computer.
- Create a GitHub account.
- Set up your project folder with starter files.
Install and configure Git
Git is a version control tool that tracks every change you make to your code. You will use it to push your portfolio files to GitHub for hosting.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Terminal (macOS) or Command Prompt (Windows) and press Enter to open it.
- Check if Git is installed by running this command:
git --version
Look at what appears in your terminal and pick the tab that matches.
✔️ I see a version number
Git is already installed. Skip ahead to the git config step below.
ⓧ I see a dialog to install (macOS)
macOS detected that Git is not installed and is prompting you to install the Xcode Command Line Tools.
- Click Install in the dialog that appeared.
- Wait for the installation to finish. This can take a few minutes.
- Once complete, run git --version again to confirm it now shows a version number.
ⓧ Command not found (Windows)
Git is not installed yet. You need to download it from the official website.
- Open your browser and go to https://git-scm.com/download/win. The download starts automatically.
- Run the downloaded installer.
- Accept the default options at each step and click Next until the install completes.
- Close and reopen Command Prompt, then run git --version to confirm it shows a version number.
- Configure Git with your name by running this command:
git config --global user.name "[[YOURNAME="your full name"]]"
- Configure Git with your email by running this command:
git config --global user.email "[[YOUREMAIL="your email address"]]"
What do these commands do?
These commands save your name and email into Git's global settings. Every time you commit code, Git attaches this information so collaborators know who made each change.
Getting a permission error?
Make sure you include the --global flag. Without it, Git tries to write to a project-specific config that may not exist yet.
Help me troubleshoot this git config error.
Create a GitHub account
GitHub is where your portfolio files will live online. GitHub Pages turns any repository into a free website at a URL based on your username.
- Open your browser and go to github.com.
- Click Sign up and follow the prompts to create a free account.
- Choose a username you are happy with. This username becomes part of your portfolio URL (username.github.io).
Pick a professional username
Your GitHub username appears in your portfolio URL, so choose something clean and recognizable. Your real name or a short handle works well.
Create your project folder and files
Every website needs a home on your computer. You will create a folder on your Desktop to keep things easy to find, then open it in VS Code.
- Switch back to your terminal and move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder by running this command:
mkdir portfolio
- Confirm the folder exists by running:
ls
You should see portfolio listed in the output.
Now open this folder in VS Code.
- Switch back to VS Code.
- Click File in the top menu bar.
- Click Open Folder.
- Navigate to your Desktop, select the portfolio folder, and click Open.
The VS Code Explorer sidebar now shows your empty portfolio folder. Time to create your starter files.
- In the Explorer sidebar on the left, hover over the folder name to reveal the icon buttons.
- Click the New File button (the page icon with a plus sign).
- Type index.html and press Enter.
- Click the New File button again, type style.css, and press Enter.
- Click the New File button one more time, type .nojekyll, and press Enter.
What is the .nojekyll file?
GitHub Pages uses a build tool called Jekyll by default. The empty .nojekyll file tells GitHub to skip that processing and serve your HTML files exactly as they are.
Your Explorer sidebar should now show three files: index.html, style.css, and .nojekyll.
Don't see .nojekyll in the sidebar?
Files starting with a dot are sometimes hidden by default. In VS Code, they should appear automatically. Make sure you typed the leading dot when naming the file.
Help me find my .nojekyll file in VS Code.
Your workspace is ready. Next up, you will build the HTML structure that gives your portfolio its shape.
Build Your HTML Structure
Your project folder is set up and ready for code. Now you need to build the skeleton of your portfolio page.
Every web page starts with an HTML file that defines the structure and content of the page. In this step, you will write the full HTML structure for your portfolio, including navigation, a hero introduction, a project gallery, an about section, and a contact footer.
In this step, get ready to:
- Write the document structure and head with metadata, fonts, and stylesheet links.
- Build the page body with navigation, hero, project grid, and about sections.
- Add a contact footer and preview the page in your browser.
Set up the document structure and head
The <head> section of an HTML file contains metadata that the browser needs before it renders anything visible. This includes the page title, character encoding, a link to your font, and a link to your stylesheet.
- Click on index.html in the VS Code sidebar to open it in the editor.
- Paste the following code into the empty file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Your Name - Design Portfolio</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@300;400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
<body>
</body>
</html>
What does this code do?
- <!DOCTYPE html> tells the browser this is a modern HTML5 document.
- The viewport meta tag makes the page scale properly on mobile devices.
- The preconnect links speed up loading the Inter font from Google Fonts by starting the connection early.
- The last <link> connects your style.css file so styles will apply once you write them in the next step.
- Save index.html by pressing Cmd+S (macOS) or Ctrl+S (Windows).
- Open the file in your browser by dragging index.html from your portfolio folder on your Desktop into an open browser window.
- Check the browser tab title. It should display Your Name - Design Portfolio.
Seeing a blank page with no tab title?
- Make sure you saved the file after pasting the code. Unsaved changes will not appear in the browser.
- Check that you dragged index.html (not style.css or .nojekyll) into the browser.
Help me figure out why my HTML file is not showing the correct tab title.
Build the navigation and hero section
The first things a visitor sees are your name in the navigation bar and a large hero greeting. These sections sit at the top of the <body> and introduce you immediately.
- In index.html, place your cursor on the blank line between the opening <body> and closing </body> tags.
- Paste the following code:
<nav class="nav">
<a href="#" class="nav-logo">Your Name</a>
<ul class="nav-links">
<li><a href="#projects">Projects</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
<header class="hero">
<p class="hero-greeting">Hello, I'm</p>
<h1 class="hero-name">Your Name</h1>
<p class="hero-tagline">A designer creating clean, thoughtful experiences.</p>
</header>
What does this code do?
- The <nav> contains your name as a logo link and three navigation links that will jump to different sections of the page.
- The <header> with class hero creates the large introductory area. The <h1> is the most important heading on the page, which search engines use to understand your site.
- The href="#projects" links point to element IDs you will add next. Clicking them will scroll the page to the matching section.
- Save index.html and refresh your browser.
- You should see your navigation links (Projects, About, Contact) and the hero text (Hello, I'm / Your Name / A designer creating clean, thoughtful experiences.) in plain unstyled text.
Not seeing the navigation or hero text?
- Confirm you pasted the code between the <body> and </body> tags, not inside the <head>.
- Check that you saved the file before refreshing the browser.
Help me troubleshoot why my navigation and hero content are not showing up in the browser.
Add the project grid and about section
The project grid is the heart of your portfolio. It displays your design work in a structured layout that will become a two-column gallery once styled.
- In index.html, place your cursor directly below the closing </header> tag.
- Paste the following code for the projects section:
<section id="projects" class="projects">
<h2 class="section-title">Selected Projects</h2>
<div class="projects-grid">
<article class="project-card">
<div class="project-image">
<img src="images/project-1.jpg" alt="Project 1">
</div>
<div class="project-info">
<h3>Project Title One</h3>
<p>Brief description of this design project and your role.</p>
</div>
</article>
<article class="project-card">
<div class="project-image">
<img src="images/project-2.jpg" alt="Project 2">
</div>
<div class="project-info">
<h3>Project Title Two</h3>
<p>Brief description of this design project and your role.</p>
</div>
</article>
<article class="project-card">
<div class="project-image">
<img src="images/project-3.jpg" alt="Project 3">
</div>
<div class="project-info">
<h3>Project Title Three</h3>
<p>Brief description of this design project and your role.</p>
</div>
</article>
<article class="project-card">
<div class="project-image">
<img src="images/project-4.jpg" alt="Project 4">
</div>
<div class="project-info">
<h3>Project Title Four</h3>
<p>Brief description of this design project and your role.</p>
</div>
</article>
</div>
</section>
What does this code do?
- The id="projects" matches the href="#projects" link in the nav, so clicking the link scrolls here.
- Each <article> represents one project card with an image placeholder and text info.
- The projects-grid wrapper will become a CSS Grid container when you add styles in the next step.
- Save index.html and refresh your browser.
- You should see "Selected Projects" followed by four project titles and descriptions listed below the hero text. The images will appear as broken image icons since the images folder does not exist yet.
Now add the about section directly below the projects section.
- Place your cursor below the closing </section> tag of the projects section.
- Paste the following code:
<section id="about" class="about">
<h2 class="section-title">About Me</h2>
<div class="about-content">
<p>Write a short paragraph about yourself, your design philosophy, and what drives your creative work. Keep it personal and authentic.</p>
<p>Mention the types of design you specialize in and what you are passionate about.</p>
</div>
</section>
What does this code do?
The about section gives visitors a personal connection to you beyond your work. The about-content wrapper will receive a max-width style later so the text stays readable and does not stretch across wide screens.
You will not see a visible change yet for this chunk. The next section adds the footer and then you will verify everything together.
Add the contact footer and preview your page
The footer gives visitors a clear way to reach you. A simple email link is all you need to start.
- Place your cursor below the closing </section> tag of the about section.
- Paste the following code:
<footer id="contact" class="contact">
<h2 class="section-title">Get In Touch</h2>
<p class="contact-text">Interested in working together? Reach out.</p>
<a href="mailto:your-email@example.com" class="contact-link">your-email@example.com</a>
</footer>
What does this code do?
- The <footer> element semantically marks this as the bottom of the page.
- The mailto: link opens the visitor's email app pre-filled with your address when clicked.
- The id="contact" matches the navigation link so visitors can jump straight here from the top of the page.
- Save index.html and refresh your browser.
- You should see all your content displayed as plain unstyled text: navigation links at the top, your name and tagline, four project titles, an about paragraph, and "Get In Touch" with your email link at the bottom.
Missing sections or jumbled text?
- Check that each section is placed sequentially inside <body> and not accidentally nested inside another section.
- Make sure every opening tag has a matching closing tag. Look for missing </section> or </div> tags.
- Confirm you placed the about section and footer below the projects section, not inside it.
Help me figure out why my HTML page sections are not displaying correctly.
A faster way to preview
Instead of dragging the file each time, you can install the Live Server extension in VS Code. Right-click index.html in the Explorer sidebar and select Open with Live Server. The browser will auto-refresh every time you save.
✔️ Awesome, I've got everything!
Great. Double check you have saved index.html before moving on.
ⓧ I'd like to double check the full code
Here is the complete index.html file at this point:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Your Name - Design Portfolio</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@300;400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
<body>
<nav class="nav">
<a href="#" class="nav-logo">Your Name</a>
<ul class="nav-links">
<li><a href="#projects">Projects</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
<header class="hero">
<p class="hero-greeting">Hello, I'm</p>
<h1 class="hero-name">Your Name</h1>
<p class="hero-tagline">A designer creating clean, thoughtful experiences.</p>
</header>
<section id="projects" class="projects">
<h2 class="section-title">Selected Projects</h2>
<div class="projects-grid">
<article class="project-card">
<div class="project-image">
<img src="images/project-1.jpg" alt="Project 1">
</div>
<div class="project-info">
<h3>Project Title One</h3>
<p>Brief description of this design project and your role.</p>
</div>
</article>
<article class="project-card">
<div class="project-image">
<img src="images/project-2.jpg" alt="Project 2">
</div>
<div class="project-info">
<h3>Project Title Two</h3>
<p>Brief description of this design project and your role.</p>
</div>
</article>
<article class="project-card">
<div class="project-image">
<img src="images/project-3.jpg" alt="Project 3">
</div>
<div class="project-info">
<h3>Project Title Three</h3>
<p>Brief description of this design project and your role.</p>
</div>
</article>
<article class="project-card">
<div class="project-image">
<img src="images/project-4.jpg" alt="Project 4">
</div>
<div class="project-info">
<h3>Project Title Four</h3>
<p>Brief description of this design project and your role.</p>
</div>
</article>
</div>
</section>
<section id="about" class="about">
<h2 class="section-title">About Me</h2>
<div class="about-content">
<p>Write a short paragraph about yourself, your design philosophy, and what drives your creative work. Keep it personal and authentic.</p>
<p>Mention the types of design you specialize in and what you are passionate about.</p>
</div>
</section>
<footer id="contact" class="contact">
<h2 class="section-title">Get In Touch</h2>
<p class="contact-text">Interested in working together? Reach out.</p>
<a href="mailto:your-email@example.com" class="contact-link">your-email@example.com</a>
</footer>
</body>
</html>
Your HTML skeleton is complete. It does not look pretty yet, but all the content is in place and structured with semantic elements. Next up, you will add CSS styles to transform this plain text into a clean, modern portfolio design.
Style Your Portfolio with CSS
Your HTML structure is in place, but right now it looks like a plain text document from the 1990s. That is because HTML only defines what content appears on the page. It does not control how that content looks.
CSS is the language that transforms raw HTML into a visual design. In this step, you will write a complete stylesheet that gives your portfolio clean typography, generous whitespace, a two-column project grid, and a responsive layout that adapts to mobile screens.
In this step, get ready to:
- Define a color palette and global resets using CSS custom properties.
- Style the navigation, hero section, and project grid with hover effects.
- Add responsive styles so your portfolio works on mobile screens.
Define your color palette and global resets
CSS custom properties let you define reusable values (like colors and spacing) in one place. If you decide to change your accent color later, you only update a single line instead of hunting through the entire file.
- In VS Code, click on style.css in the Explorer sidebar to open it.
- Add your custom properties, global reset, and body styles by copying this code:
:root {
--color-bg: #ffffff;
--color-text: #1a1a1a;
--color-text-secondary: #6b7280;
--color-accent: #2563eb;
--color-border: #e5e7eb;
--color-card-bg: #f9fafb;
--font-family: 'Inter', sans-serif;
--max-width: 1100px;
--spacing-section: 120px;
}
/* Remove default browser spacing */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Apply the Inter font and base colors to the page */
body {
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
line-height: 1.6;
}
What does this code do?
The :root block defines your design tokens. Every color, font, and spacing value lives here so you can update the entire look of your site from one place.
The * selector resets all elements to zero margin and padding. This prevents browsers from adding unpredictable spacing. The box-sizing: border-box rule makes width calculations include padding and borders, which prevents layout surprises.
- Save style.css and refresh your browser.
- You should see the text change to the Inter font, and all the default browser margins disappear. The content now sits flush against the edges.
Still seeing the old browser font?
- Check that your index.html has the Google Fonts <link> tag in the <head> section. Without it, the Inter font cannot load.
- Make sure the <link rel="stylesheet" href="style.css"> line in your HTML points to style.css (not styles.css or another name).
- help me debug why my CSS is not loading
Style the navigation, hero, and section titles
With your foundation in place, you can now style the major visual sections. The navigation uses flexbox to space items evenly. The hero section uses large, bold typography to draw attention to your name.
- Add the navigation, hero, and section title styles below the body rule by copying this code:
/* Navigation */
.nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24px 40px;
max-width: var(--max-width);
margin: 0 auto;
}
.nav-logo {
font-weight: 600;
font-size: 1.1rem;
text-decoration: none;
color: var(--color-text);
}
.nav-links {
display: flex;
list-style: none;
gap: 32px;
}
.nav-links a {
text-decoration: none;
color: var(--color-text-secondary);
font-size: 0.9rem;
font-weight: 400;
transition: color 0.2s ease;
}
.nav-links a:hover {
color: var(--color-text);
}
/* Hero */
.hero {
max-width: var(--max-width);
margin: 0 auto;
padding: 100px 40px var(--spacing-section);
}
.hero-greeting {
font-size: 1rem;
color: var(--color-text-secondary);
margin-bottom: 12px;
}
.hero-name {
font-size: 4rem;
font-weight: 700;
line-height: 1.1;
margin-bottom: 20px;
}
.hero-tagline {
font-size: 1.25rem;
color: var(--color-text-secondary);
max-width: 500px;
}
/* Sections */
.section-title {
font-size: 0.85rem;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 1.5px;
color: var(--color-text-secondary);
margin-bottom: 48px;
}
What does this code do?
- The .nav uses display: flex with justify-content: space-between to push your name to the left and links to the right.
- The .hero-name at 4rem creates a dramatic, large heading that anchors the page.
- The .section-title uses uppercase and letter-spacing to create a subtle label style. This is a common pattern in modern portfolio design.
- The max-width: var(--max-width) with margin: 0 auto pattern centers content and prevents it from stretching too wide on large screens.
- Save style.css and refresh your browser.
- You should see a clean navigation bar at the top with your name on the left and links on the right. Below it, your name appears in large bold text with a lighter tagline underneath.
Navigation links stacking vertically instead of horizontally?
- Confirm that .nav-links in your CSS has display: flex. Without it, the list items stack in their default block layout.
- Check that the class name in your CSS (.nav-links) matches the class in your HTML (class="nav-links"). CSS class names are case-sensitive.
- help me fix my navigation layout
Now add the styles for your project grid, about section, and contact footer. This is where CSS Grid comes in. It creates a two-column layout for your project cards with just one line of code.
- Add the projects, about, and contact styles below the .section-title rule by copying this code:
/* Projects */
.projects {
max-width: var(--max-width);
margin: 0 auto;
padding: 0 40px var(--spacing-section);
}
.projects-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 32px;
}
.project-card {
border-radius: 12px;
overflow: hidden;
background-color: var(--color-card-bg);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.project-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.08);
}
.project-image {
width: 100%;
aspect-ratio: 4 / 3;
overflow: hidden;
}
.project-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.project-card:hover .project-image img {
transform: scale(1.03);
}
.project-info {
padding: 24px;
}
.project-info h3 {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: 8px;
}
.project-info p {
font-size: 0.9rem;
color: var(--color-text-secondary);
}
/* About */
.about {
max-width: var(--max-width);
margin: 0 auto;
padding: 0 40px var(--spacing-section);
}
.about-content {
max-width: 600px;
}
.about-content p {
font-size: 1.05rem;
color: var(--color-text-secondary);
margin-bottom: 16px;
line-height: 1.8;
}
/* Contact */
.contact {
max-width: var(--max-width);
margin: 0 auto;
padding: 0 40px var(--spacing-section);
}
.contact-text {
font-size: 1.05rem;
color: var(--color-text-secondary);
margin-bottom: 16px;
}
.contact-link {
font-size: 1.25rem;
color: var(--color-accent);
text-decoration: none;
font-weight: 500;
transition: opacity 0.2s ease;
}
.contact-link:hover {
opacity: 0.7;
}
What does this code do?
- The grid-template-columns: repeat(2, 1fr) creates two equal-width columns. Each project card automatically fills into the next available grid slot.
- The hover effects on .project-card use translateY(-4px) to lift the card slightly and add a soft shadow. This gives visitors a tactile feel when browsing your projects.
- The aspect-ratio: 4 / 3 on .project-image ensures all image containers share the same proportions, keeping the grid visually consistent even if your source images vary in size.
- Save style.css and refresh your browser.
- You should see your four project cards arranged in a two-column grid with rounded corners and a subtle grey background. Hover over a card to see it lift up with a shadow. The about and contact sections should have clean spacing below.
Project cards not appearing in two columns?
- Make sure your CSS targets .projects-grid (not .project-grid). The class name in your HTML uses the plural form.
- Check that display: grid is present on the .projects-grid rule. Without it, grid-template-columns has no effect.
- help me debug my CSS Grid layout
Add responsive styles for mobile screens
Your portfolio looks great on a wide screen, but try resizing your browser window narrower. The two-column grid gets cramped. A media query lets you define different styles that only activate below a certain screen width.
- Add the responsive styles at the very bottom of style.css (after the .contact-link:hover rule) by copying this code:
/* Responsive */
@media (max-width: 768px) {
.nav {
padding: 20px 24px;
}
.nav-links {
gap: 20px;
}
.hero {
padding: 60px 24px 80px;
}
.hero-name {
font-size: 2.5rem;
}
.projects {
padding: 0 24px 80px;
}
.projects-grid {
grid-template-columns: 1fr;
}
.about {
padding: 0 24px 80px;
}
.contact {
padding: 0 24px 80px;
}
}
What does this code do?
The @media (max-width: 768px) block activates only when the browser window is 768 pixels wide or narrower (roughly a tablet or phone).
- The grid-template-columns: 1fr switches the project grid from two columns to a single column so cards stack vertically.
- The .hero-name shrinks from 4rem to 2.5rem so the heading does not overflow on small screens.
- Padding values are reduced across all sections to give mobile users more content area.
- Save style.css and refresh your browser.
- Drag the edge of your browser window to make it narrower. Once it passes below 768 pixels wide, you should see the project grid collapse to a single column and the hero text shrink.
Responsive styles not kicking in?
- Make sure your index.html contains the viewport meta tag: <meta name="viewport" content="width=device-width, initial-scale=1.0">. Without it, mobile browsers zoom out instead of applying your media query.
- Confirm the @media block is at the bottom of your file, after all other rules. If a later rule overrides it, the responsive styles get cancelled out.
- help me debug my responsive media query
✔️ Awesome, I've got everything!
Great. Double check you have saved style.css before moving on.
ⓧ I'd like to double check the full code
Here is the complete style.css file. Compare it against yours to spot any differences.
:root {
--color-bg: #ffffff;
--color-text: #1a1a1a;
--color-text-secondary: #6b7280;
--color-accent: #2563eb;
--color-border: #e5e7eb;
--color-card-bg: #f9fafb;
--font-family: 'Inter', sans-serif;
--max-width: 1100px;
--spacing-section: 120px;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
line-height: 1.6;
}
/* Navigation */
.nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24px 40px;
max-width: var(--max-width);
margin: 0 auto;
}
.nav-logo {
font-weight: 600;
font-size: 1.1rem;
text-decoration: none;
color: var(--color-text);
}
.nav-links {
display: flex;
list-style: none;
gap: 32px;
}
.nav-links a {
text-decoration: none;
color: var(--color-text-secondary);
font-size: 0.9rem;
font-weight: 400;
transition: color 0.2s ease;
}
.nav-links a:hover {
color: var(--color-text);
}
/* Hero */
.hero {
max-width: var(--max-width);
margin: 0 auto;
padding: 100px 40px var(--spacing-section);
}
.hero-greeting {
font-size: 1rem;
color: var(--color-text-secondary);
margin-bottom: 12px;
}
.hero-name {
font-size: 4rem;
font-weight: 700;
line-height: 1.1;
margin-bottom: 20px;
}
.hero-tagline {
font-size: 1.25rem;
color: var(--color-text-secondary);
max-width: 500px;
}
/* Sections */
.section-title {
font-size: 0.85rem;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 1.5px;
color: var(--color-text-secondary);
margin-bottom: 48px;
}
/* Projects */
.projects {
max-width: var(--max-width);
margin: 0 auto;
padding: 0 40px var(--spacing-section);
}
.projects-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 32px;
}
.project-card {
border-radius: 12px;
overflow: hidden;
background-color: var(--color-card-bg);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.project-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.08);
}
.project-image {
width: 100%;
aspect-ratio: 4 / 3;
overflow: hidden;
}
.project-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.project-card:hover .project-image img {
transform: scale(1.03);
}
.project-info {
padding: 24px;
}
.project-info h3 {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: 8px;
}
.project-info p {
font-size: 0.9rem;
color: var(--color-text-secondary);
}
/* About */
.about {
max-width: var(--max-width);
margin: 0 auto;
padding: 0 40px var(--spacing-section);
}
.about-content {
max-width: 600px;
}
.about-content p {
font-size: 1.05rem;
color: var(--color-text-secondary);
margin-bottom: 16px;
line-height: 1.8;
}
/* Contact */
.contact {
max-width: var(--max-width);
margin: 0 auto;
padding: 0 40px var(--spacing-section);
}
.contact-text {
font-size: 1.05rem;
color: var(--color-text-secondary);
margin-bottom: 16px;
}
.contact-link {
font-size: 1.25rem;
color: var(--color-accent);
text-decoration: none;
font-weight: 500;
transition: opacity 0.2s ease;
}
.contact-link:hover {
opacity: 0.7;
}
/* Responsive */
@media (max-width: 768px) {
.nav {
padding: 20px 24px;
}
.nav-links {
gap: 20px;
}
.hero {
padding: 60px 24px 80px;
}
.hero-name {
font-size: 2.5rem;
}
.projects {
padding: 0 24px 80px;
}
.projects-grid {
grid-template-columns: 1fr;
}
.about {
padding: 0 24px 80px;
}
.contact {
padding: 0 24px 80px;
}
}
Your portfolio now has a professional, responsive design. Next up, you will swap in your real project images and personal information to make it truly yours.
Add Your Design Projects
Your portfolio has a clean layout and professional styling. However, it's still full of placeholder text and broken image icons.
In this step, you'll replace all the placeholder content with your real design projects, your actual name, and a personal description. This is where your portfolio becomes yours.
In this step, get ready to:
- Add your design project images to the portfolio folder.
- Update the HTML with your real name, tagline, project details, and about text.
- Review and adjust how your images display in the grid.
Create your images folder
Your HTML already references images inside a folder called images. You need to create that folder and add your actual project images to it.
- Open the VS Code terminal by pressing Cmd+` (macOS) or Ctrl+` (Windows).
- Create the images folder by running this command:
mkdir images
- Confirm the folder was created by running:
ls
You should see images listed alongside index.html, style.css, and .nojekyll.
- Now open your portfolio folder in Finder (macOS) or File Explorer (Windows).
- Copy your design project images (screenshots, mockups, or exports from your design work) into the images folder.
- Rename the files to project-1.jpg, project-2.jpg, project-3.jpg, and project-4.jpg.
Why these specific file names?
Your HTML already has <img> tags pointing to images/project-1.jpg through images/project-4.jpg. By naming your files to match, the images will appear automatically without changing any code.
Don't have four projects yet?
Use any images you like as placeholders for now. Screenshots of apps you admire, photos of sketches, or solid-color rectangles all work. You can swap them out later.
Don't see the images folder in VS Code?
Click the refresh icon at the top of the Explorer sidebar in VS Code. Sometimes the file tree needs a moment to pick up changes made outside the editor.
Also make sure you created the folder inside portfolio (the folder open in VS Code), not somewhere else on your computer.
Help me find my images folder in VS Code.
Update the placeholder content in your HTML
Your HTML currently has generic placeholder text throughout. Time to replace it with your real information.
- Switch back to index.html in VS Code.
- Find the navigation logo. It currently says:
<a href="#" class="nav-logo">Your Name</a>
- Replace Your Name with your actual name.
- Next, find the hero section. It currently looks like this:
<h1 class="hero-name">Your Name</h1>
<p class="hero-tagline">A designer creating clean, thoughtful experiences.</p>
- Replace Your Name in the <h1> with your actual name.
- Replace the tagline text with a short sentence describing what you do (e.g. "A UX designer focused on healthcare apps" or "Crafting brand identities for startups").
- Now scroll down to the project cards. Find the first card's info section:
<div class="project-info">
<h3>Project Title One</h3>
<p>Brief description of this design project and your role.</p>
</div>
- Replace Project Title One with the actual title of the design project shown in project-1.jpg.
- Replace the description paragraph with a one-sentence summary of that project and your role in it.
- Repeat for each of the four project cards (Project Title Two, Project Title Three, Project Title Four).
- Scroll down to the about section and find this paragraph:
<p>Write a short paragraph about yourself, your design philosophy, and what drives your creative work. Keep it personal and authentic.</p>
<p>Mention the types of design you specialize in and what you are passionate about.</p>
- Replace the first <p> with a short paragraph about yourself and your design philosophy.
- Replace the second <p> with a sentence about the types of design you specialize in.
- Finally, find the contact link at the bottom:
<a href="mailto:your-email@example.com" class="contact-link">your-email@example.com</a>
- Replace both instances of your-email@example.com with your real email address.
- Save index.html.
What about the page title?
You can also update the <title> tag in the <head> section from Your Name - Design Portfolio to your actual name. This is what appears in the browser tab.
Review your images in the grid
- Refresh your browser to see the updated portfolio.
You should see your actual project images filling the card grid, your name in the navigation and hero, and your personal text in the about section.
What if images look stretched or cropped?
Your CSS uses aspect-ratio: 4 / 3 on the image containers and object-fit: cover on the images. This means images are cropped to fill the 4:3 space without distortion.
If important parts of your image are being cropped out, the best fix is to crop your source images to a 4:3 ratio before adding them. This gives you full control over what's visible.
Images not showing up?
Make sure your image files are inside the images folder (not directly in portfolio). The file names must match exactly, including the extension. If your files are .png instead of .jpg, either rename the files or update the src attribute in your HTML to match (e.g. images/project-1.png).
Help me figure out why my images aren't displaying.
Your portfolio now shows your real work and tells your story. Next up, you'll push it live to the internet so anyone with a link can see it.
Deploy to GitHub Pages
Your portfolio looks polished on your local machine, but right now you are the only person who can see it.
In this step, you will push your code to GitHub and turn on GitHub Pages, a free hosting service that publishes your site at a clean URL anyone can visit.
In this step, get ready to:
- Create a GitHub repository for your portfolio site.
- Push your local files to the repository using Git.
- Enable GitHub Pages so your site is live on the internet.
Create your GitHub repository
GitHub Pages serves your website from a repository with a special name that matches your username.
- Open github.com in your browser and sign in.
- Click the + button in the top-right corner of the page.
- Select New repository.
- In the Repository name field, type your-username.github.io (replacing your-username with your actual GitHub username).
- Set the visibility to Public.
- Leave all other options unchecked. Do NOT initialize with a README.
- Click Create repository.
Why does the repository name matter?
GitHub Pages uses the repository name to decide your site's URL. A repository named your-username.github.io automatically gets published at https://your-username.github.io.
The repository must be Public on a free GitHub account for Pages to work.
Push your code to GitHub
Now you will connect your local portfolio folder to the remote repository and upload all your files.
- In the VS Code terminal (the same one from earlier), initialize a Git repository and push your code by running these commands:
git init
git add .
git commit -m "Initial portfolio"
git branch -M main
git remote add origin https://github.com/[[YOUR_USERNAME="your GitHub username"]]/[[YOUR_USERNAME="your GitHub username"]].github.io.git
git push -u origin main
What do these commands do?
- git init turns your folder into a Git repository that can track changes.
- git add . stages every file in the folder (HTML, CSS, images, and .nojekyll) for the next commit.
- git commit -m "Initial portfolio" saves a snapshot of your project with a descriptive message.
- git branch -M main renames the default branch to main.
- git remote add origin links your local repo to the GitHub repository you just created.
- git push -u origin main uploads everything to GitHub.
What about authentication?
When you run git push for the first time, VS Code will open a browser window asking you to sign in to GitHub. Follow the prompts and authorize VS Code to access your account.
After you approve, the push will complete automatically in your terminal.
- Confirm the push succeeded by looking for a message that ends with main -> main in your terminal output.
- Refresh your repository page on github.com. You should see your index.html, style.css, .nojekyll, and images folder listed.
Push failed or permission denied?
- Make sure you replaced both instances of your username in the git remote add origin command with your actual GitHub username.
- If the browser sign-in window did not appear, try closing and reopening VS Code, then run git push -u origin main again.
- If you see an error about the remote already existing, run git remote remove origin first, then re-run the git remote add origin command with the correct URL.
Help me fix a git push error for my portfolio repository.
Enable GitHub Pages
Your code is on GitHub, but the site is not live yet. You need to tell GitHub to publish it as a website.
- On your repository page on github.com, click Settings in the top tab bar.
- In the left sidebar, scroll down to the Code and automation section.
- Click Pages.
- Under Build and deployment, set Source to Deploy from a branch.
- Select the main branch and / (root) folder.
- Click Save.
How long until my site is live?
It can take up to 10 minutes for changes to publish after you push to GitHub. In practice, most sites appear within 1-2 minutes.
- Wait 1-2 minutes, then open a new browser tab.
- Visit https://your-username.github.io (replacing your-username with your actual GitHub username).
- Your portfolio should appear exactly as it looked on your local machine.
Seeing a 404 page?
- Double check that your repository name matches the pattern your-username.github.io exactly. A typo in the repo name means GitHub Pages will not activate automatically.
- Confirm that your repository contains an index.html file at the root level (not inside a subfolder).
- Wait a few more minutes. GitHub can take up to 10 minutes to deploy your site for the first time.
Help me troubleshoot why my GitHub Pages site is showing a 404.
Your portfolio is live on the internet. Anyone with the link can now see your design work. Next up, you will take it a step further with a dark mode toggle that gives visitors a choice between light and dark themes.
Secret mission
Add a Dark Mode Toggle
Your portfolio looks great in light mode. But what about visitors who prefer a darker interface? Add a toggle button that lets anyone switch between light and dark themes with a single click, using the CSS custom properties you already have in place.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally and on GitHub Pages (which is free), so there are no ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- Local portfolio folder containing index.html, style.css, .nojekyll, and the images/ folder.
- GitHub repository your-username.github.io with GitHub Pages enabled.
- GitHub account (if you created one for this project).
Keep everything running
No action needed. Choose this if you are still actively building or want your portfolio live at your GitHub Pages URL.
- Your site stays live at your-username.github.io for free.
- Your local files remain on your Desktop for future edits.
- Git stays installed on your machine (useful for future projects).
Pause - I'll come back to this later
Your GitHub repository and live site cost nothing to keep running. The only action here is to close VS Code to free up memory.
- Close VS Code if you are done editing for now.
- Your site stays live at no cost. Come back anytime, open the portfolio folder in VS Code, make changes, and push again.
Delete - I don't want to use this again
Remove all project resources and take your site offline.
- Delete your local project folder. On macOS/Linux, run:
rm -rf ~/Desktop/portfolio
On Windows, run:
Remove-Item -Recurse -Force ~\Desktop\portfolio
- Delete your GitHub repository. Go to your repository page on github.com, click Settings, scroll to the bottom to the Danger Zone section, and click Delete this repository. Confirm by typing the repository name when prompted. This takes your site offline.
- Delete your GitHub account (only if you created it solely for this project). Go to github.com, click your profile picture, then Settings, then Account in the left sidebar, then scroll down and click Delete your account. Follow the confirmation prompts.
Nice Work!
Nice Work!
You just built and deployed a professional design portfolio website from scratch. Anyone with your link can now browse your work in a clean, modern layout.
You've learned how to:
- Build a complete portfolio website using semantic HTML and modern CSS with custom properties, CSS Grid, and responsive design.
- Showcase real design projects in a responsive project grid with hover interactions and clean typography.
- Deploy a live website to GitHub Pages using Git for version control, giving you a shareable URL.
- Secret Mission: Added a dark mode toggle using JavaScript and CSS custom properties to switch between light and dark themes.
Ready to quiz yourself?