Build a Cloud Engineer Portfolio
Build and deploy a responsive cloud engineering portfolio to GitHub Pages.
Introduction
30 Second Summary
When you're applying for cloud engineering roles, having a portfolio website gives employers a direct way to see your projects and skills. It shows you can build and ship something real.
In this project, you will build a cloud engineer portfolio website from scratch using HTML, CSS, and JavaScript. You will deploy it live to GitHub Pages so you have a shareable URL to put on your resume and job applications.
What You'll Build
A responsive portfolio site featuring a hero introduction, a cloud projects showcase with tech stack badges, a skills and certifications section, and a contact section.
By the end of this project, you'll have:
- A responsive portfolio website built from scratch with a hero section, project cards, skills grid, and contact links.
- A working Git workflow for version controlling your code and pushing it to GitHub.
- A live site deployed to GitHub Pages with a shareable URL for your resume and job applications.
- Secret Mission: Add a dark mode toggle that switches your entire site between light and dark themes.
Are there any prerequisites?
No prerequisites needed. This guide walks you through setting up everything from scratch, including installing Git and creating a GitHub account.
Set Up Git and GitHub
Your portfolio website needs a home online where employers can find it. To get it there, you need two tools: Git for tracking changes to your code, and GitHub for hosting your project online.
In this step, you'll install Git, create a GitHub account, and set up a repository to hold your portfolio files.
In this step, get ready to:
- Install Git on your computer.
- Create a GitHub account and configure Git.
- Create and clone your project repository.
Install Git on Windows
Git is a version control tool that records every change you make to your files. It works like a save-point system for your code, so you can always go back to a previous version if something breaks.
- Press the Windows key to open your search bar.
- Type PowerShell and press Enter to open it.
- Install Git by running this command:
winget install --id Git.Git -e --source winget
What does this command do?
This command uses winget, a built-in Windows package manager, to install Git from the command line.
The -e flag tells winget to match the exact package name, so it installs the right program. The --source winget flag tells it where to find the package.
Is winget not available?
If your terminal doesn't recognize the winget command, you can install Git manually instead.
- Download the installer from git-scm.com/install/windows.
- Run the setup wizard and accept the default settings on each screen.
Help me install Git on Windows
- After the installation finishes, close PowerShell completely and reopen it. This refreshes the terminal so it recognizes the new git command.
- Verify Git is installed by running this command:
git --version
✔️ I see a version number
You should see output like git version 2.54.0 (your number may be slightly different). Git is installed and ready to go.
ⓧ Command not found
If your terminal says the git command was not found, try these fixes:
- Make sure you closed and reopened PowerShell after the installation finished. The old terminal session does not know about newly installed programs.
- If the winget install did not complete successfully, download the installer from git-scm.com/install/windows and run the setup wizard with default settings. Close and reopen PowerShell after installing, then run git --version again.
Help me troubleshoot my Git installation on Windows
Create a GitHub account and configure Git
GitHub is the online platform where your code will live. It also powers GitHub Pages, the free hosting service you'll use to deploy your portfolio website later in this project.
- Go to github.com.
- Click Sign up.
- Follow the prompts to create your account.
- Check your email inbox and verify your email address when prompted.
Now you need to tell Git who you are. Git attaches your name and email to every change you make, so your teammates (and future employers) can see who wrote what.
- Switch back to PowerShell and configure your Git identity by running these commands:
git config --global user.name "[[YOUR_GIT_NAME="Your Name"]]"
git config --global user.email "[[YOUR_GIT_EMAIL="your-email@example.com"]]"
What do these commands do?
The --global flag means these settings apply to every Git project on your computer. You only need to run them once.
Use the same email address you signed up with on GitHub. This links your local Git changes to your GitHub profile.
These commands do not produce any output. That's normal. Your identity is now saved in Git's global configuration.
Create a repository and clone it locally
A repository is a project folder that Git tracks. You'll create one on GitHub first, then download a copy to your computer so you can work on it locally.
- On GitHub, click the + icon in the top-right corner of the page.
- Select New repository.
- Enter cloud-portfolio in the Repository name field.
- Select Public for the repository visibility.
- Check the Add a README file checkbox.
- Click Create repository.
Why make the repository public?
A public repository lets anyone view your code and, more importantly, lets GitHub Pages host your portfolio website for free. Employers can also see your code directly, which demonstrates your skills.
Now you'll copy this repository to your computer so you can add files to it.
- On your new repository page, click the green Code button.
- Make sure the HTTPS tab is selected, then click the copy icon to copy the URL.
- Move to your Desktop by running this command:
cd ~/Desktop
- Clone your repository and move into the project folder by running these commands:
git clone [[YOUR_REPO_URL="the HTTPS URL you just copied"]]
cd cloud-portfolio
What does git clone do?
The git clone command downloads a full copy of your GitHub repository to your computer. It creates a folder called cloud-portfolio on your Desktop containing the README.md file that GitHub generated.
- Confirm the folder was created by running:
ls
You should see README.md listed in the output. This file was auto-generated by GitHub when you created the repository.
Now open this folder in your code editor so you can start adding files.
- In your code editor, click File in the top menu bar.
- Click Open Folder.
- Navigate to your Desktop, select the cloud-portfolio folder, and click Open.
You should see the cloud-portfolio folder name in your code editor's sidebar, with README.md listed inside it.
Don't see the cloud-portfolio folder on your Desktop?
- Make sure you ran cd ~/Desktop before the git clone command. Without it, the folder may have been created in a different location.
- Check that you copied the correct HTTPS URL from the green Code button on your GitHub repository page.
Help me find my cloned repository
Your development environment is all set. Next, you'll start building the HTML structure for your portfolio website.
Build the HTML Structure
Your development environment is ready to go. Now it's time to build the actual portfolio page that employers will see.
Every website starts with HTML, the language that defines the structure and content of a web page. In this step, you'll create the full skeleton of your portfolio: a navigation bar, a hero introduction, a projects showcase, a skills section, and a contact area.
In this step, get ready to:
- Create the document structure with a header and hero section.
- Add a projects section with three cloud project cards.
- Add skills, contact, and footer sections to complete the page.
Create the document structure with header and hero
Every HTML page needs a basic skeleton: a DOCTYPE declaration, a <head> section with metadata, and a <body> where all the visible content lives.
- In your code editor, right-click the cloud-portfolio folder in the sidebar and select New File.
- Name the file index.html and press Enter.
- Copy the following code into index.html to set up the HTML skeleton and <head> section:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Character encoding and responsive viewport -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Your Name | Cloud Engineer Portfolio</title>
<!-- Link to the stylesheet you'll create in the next step -->
<link rel="stylesheet" href="style.css">
</head>
<body>
</body>
</html>
What does this code do?
The <!DOCTYPE html> declaration tells the browser this is a modern HTML5 document. The <meta charset="UTF-8"> tag ensures special characters display correctly.
The viewport meta tag makes your site responsive on mobile devices. The <link> tag connects to a CSS stylesheet you'll create in a later step.
- Save index.html.
- Open the cloud-portfolio folder in Finder (macOS) or File Explorer (Windows) and double-click index.html to open it in your browser.
- You should see a blank page, but check the browser tab. It should display Your Name | Cloud Engineer Portfolio as the page title.
See a blank tab title?
Make sure you saved the file with the .html extension, not .txt. Some editors add .txt by default. Also check that your <title> tag is inside the <head> section.
Still stuck? Why isn't my HTML page title showing in the browser tab?
- Now add the header with navigation inside the <body> tag. Copy the following code between the opening <body> and closing </body> tags:
<!-- Fixed navigation bar -->
<header class="header">
<nav class="nav">
<a href="#" class="nav-logo">CloudPortfolio</a>
<ul class="nav-links">
<li><a href="#projects">Projects</a></li>
<li><a href="#skills">Skills</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
<!-- Hamburger menu button for mobile screens -->
<button class="nav-toggle" aria-label="Toggle navigation">
<span class="hamburger"></span>
</button>
</nav>
</header>
What does this code do?
The <header> and <nav> elements create a navigation bar at the top of your page. The nav-links list contains anchor links that will scroll to different sections of your portfolio.
The nav-toggle button is a hamburger menu icon that will only appear on mobile screens. You'll wire up the toggle behavior with JavaScript in a later step.
- Save index.html and refresh your browser.
- You should see CloudPortfolio, Projects, Skills, and Contact as plain text links at the top of the page.
Don't see the navigation text?
Check that you pasted the code between the <body> and </body> tags. Code placed outside the body will not render on the page.
Need help? My HTML navigation links aren't showing up in the browser.
- Now add the hero section below the closing </header> tag. Copy the following code after </header> and before </body>:
<!-- Main content area -->
<main>
<!-- Hero introduction section -->
<section class="hero">
<div class="hero-content">
<h1>Hi, I'm <span class="highlight">Your Name</span></h1>
<p class="hero-subtitle">Cloud Engineer | AWS | Azure | Terraform</p>
<p class="hero-description">I build and manage scalable, secure cloud infrastructure. Explore my projects below.</p>
<a href="#projects" class="btn">View My Projects</a>
</div>
</section>
</main>
What does this code do?
The <main> element wraps all the primary content of your page. The hero section is the first thing visitors see. It displays your name, a subtitle listing your cloud focus areas, and a call-to-action button.
The highlight class on the <span> wrapping your name will let you style it with a different color later.
- Save index.html and refresh your browser.
- You should see your name heading, the subtitle, a short description, and a View My Projects link below the navigation text.
Only seeing the navigation?
Make sure the hero code is placed after the closing </header> tag, not inside the header. Also check that you have both an opening <main> and closing </main> tag wrapping the hero section.
Need help? My hero section isn't appearing below the navigation.
Add the projects section
The projects section is where you showcase your cloud engineering work. Each project gets its own card with a title, description, and tech stack tags.
- In index.html, find the closing </section> tag after the hero content.
- Copy the following code below that </section> tag, but before the closing </main> tag:
<!-- Projects showcase section -->
<section id="projects" class="projects">
<h2 class="section-title">Cloud Projects</h2>
<div class="projects-grid">
<!-- Project card 1 -->
<div class="project-card">
<div class="project-icon">☁</div>
<h3>AWS VPC Network</h3>
<p>Designed a multi-tier VPC with public and private subnets, NAT gateways, and security groups for a web application.</p>
<div class="project-tags">
<span class="tag">AWS</span>
<span class="tag">VPC</span>
<span class="tag">Networking</span>
</div>
</div>
<!-- Project card 2 -->
<div class="project-card">
<div class="project-icon">⚙</div>
<h3>CI/CD Pipeline</h3>
<p>Built an automated deployment pipeline using infrastructure as code to provision and update cloud resources on every commit.</p>
<div class="project-tags">
<span class="tag">Terraform</span>
<span class="tag">GitHub Actions</span>
<span class="tag">IaC</span>
</div>
</div>
<!-- Project card 3 -->
<div class="project-card">
<div class="project-icon">📊</div>
<h3>Cloud Monitoring Dashboard</h3>
<p>Set up centralized logging and monitoring with custom dashboards and automated alerting for production workloads.</p>
<div class="project-tags">
<span class="tag">CloudWatch</span>
<span class="tag">Lambda</span>
<span class="tag">SNS</span>
</div>
</div>
</div>
</section>
What does this code do?
The id="projects" attribute on the section matches the #projects link in your navigation. Clicking that nav link will scroll the page down to this section.
Each project card contains an icon (using HTML character codes), a title, a description, and tech stack tags. These are placeholder projects you can replace with your own cloud work later.
- Save index.html and refresh your browser.
- You should see Cloud Projects as a heading followed by three project titles (AWS VPC Network, CI/CD Pipeline, Cloud Monitoring Dashboard) with their descriptions and tech tags.
Missing project cards?
Check that you pasted the code between the hero's closing </section> and the closing </main> tag. If you pasted it after </main>, the structure will still render but won't be semantically correct.
Need help? My projects section isn't showing up correctly.
Add the skills and contact sections
The remaining sections round out your portfolio with your technical skills, certifications, and contact information.
- In index.html, find the closing </section> tag after the projects grid.
- Copy the following skills section below it, still inside the </main> tag:
<!-- Skills and certifications section -->
<section id="skills" class="skills">
<h2 class="section-title">Skills & Certifications</h2>
<div class="skills-grid">
<div class="skill-category">
<h3>Cloud Platforms</h3>
<ul>
<li>Amazon Web Services (AWS)</li>
<li>Microsoft Azure</li>
<li>Google Cloud Platform</li>
</ul>
</div>
<div class="skill-category">
<h3>DevOps & IaC</h3>
<ul>
<li>Terraform</li>
<li>Docker</li>
<li>GitHub Actions</li>
</ul>
</div>
<div class="skill-category">
<h3>Networking & Security</h3>
<ul>
<li>VPC / Subnets</li>
<li>IAM & Security Groups</li>
<li>DNS & Load Balancing</li>
</ul>
</div>
<div class="skill-category">
<h3>Certifications</h3>
<ul>
<li>AWS Solutions Architect</li>
<li>AWS Cloud Practitioner</li>
<li>HashiCorp Terraform Associate</li>
</ul>
</div>
</div>
</section>
What does this code do?
The skills section organizes your expertise into four categories: Cloud Platforms, DevOps, Networking, and Certifications. Each category is a skill-category div containing a heading and an unordered list.
The & you see in the headings is the HTML entity for the ampersand character (&). HTML uses these entities for special characters.
- Save index.html and refresh your browser.
- You should see Skills & Certifications followed by four groups of skill lists.
Skills section not appearing?
Make sure you pasted the code after the projects section's closing </section> tag. Count your closing tags to ensure the projects section is properly closed before the skills section begins.
Need help? My skills section isn't rendering in the browser.
- Now add the contact section, footer, and script tag. Find the closing </section> tag after the skills grid and copy the following code below it:
<!-- Contact section -->
<section id="contact" class="contact">
<h2 class="section-title">Get In Touch</h2>
<p class="contact-description">Interested in working together or have a question? Reach out through any of the channels below.</p>
<div class="contact-links">
<a href="mailto:your-email@example.com" class="contact-link">Email</a>
<a href="https://linkedin.com/in/your-profile" class="contact-link" target="_blank" rel="noopener noreferrer">LinkedIn</a>
<a href="https://github.com/your-username" class="contact-link" target="_blank" rel="noopener noreferrer">GitHub</a>
</div>
</section>
</main>
<!-- Page footer -->
<footer class="footer">
<p>Built by Your Name | Cloud Engineer Portfolio</p>
</footer>
<!-- JavaScript file for interactivity -->
<script src="script.js"></script>
What does this code do?
The contact section provides three links for visitors to reach you: Email, LinkedIn, and GitHub. The target="_blank" attribute opens LinkedIn and GitHub links in a new tab.
The footer sits outside <main> because it's a page-level element, not primary content. The <script> tag at the bottom links to a JavaScript file you'll create in a later step. Placing it before the closing </body> ensures the page content loads before the script runs.
Replace the closing </main> tag
Notice that this code block includes </main> at the top. When you paste this code, delete the existing </main> that was already in your file so you don't end up with two of them.
- Save index.html and refresh your browser.
- Scroll to the bottom of the page. You should see Get In Touch with three links (Email, LinkedIn, GitHub) and a footer credit line at the very bottom.
Page looks broken or sections are missing?
The most common issue is duplicate or missing closing tags. Make sure you have exactly one </main> tag in your file, and that it appears after the contact section but before the footer.
Need help? My page layout looks broken after adding the contact and footer sections.
✔️ Awesome, I've got everything!
Great. Double check you've saved index.html and move on to styling.
ⓧ I'd like to double check the full code
Here is the complete index.html file. Compare your code against it and fix any differences:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Your Name | Cloud Engineer Portfolio</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header class="header">
<nav class="nav">
<a href="#" class="nav-logo">CloudPortfolio</a>
<ul class="nav-links">
<li><a href="#projects">Projects</a></li>
<li><a href="#skills">Skills</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
<button class="nav-toggle" aria-label="Toggle navigation">
<span class="hamburger"></span>
</button>
</nav>
</header>
<main>
<section class="hero">
<div class="hero-content">
<h1>Hi, I'm <span class="highlight">Your Name</span></h1>
<p class="hero-subtitle">Cloud Engineer | AWS | Azure | Terraform</p>
<p class="hero-description">I build and manage scalable, secure cloud infrastructure. Explore my projects below.</p>
<a href="#projects" class="btn">View My Projects</a>
</div>
</section>
<section id="projects" class="projects">
<h2 class="section-title">Cloud Projects</h2>
<div class="projects-grid">
<div class="project-card">
<div class="project-icon">☁</div>
<h3>AWS VPC Network</h3>
<p>Designed a multi-tier VPC with public and private subnets, NAT gateways, and security groups for a web application.</p>
<div class="project-tags">
<span class="tag">AWS</span>
<span class="tag">VPC</span>
<span class="tag">Networking</span>
</div>
</div>
<div class="project-card">
<div class="project-icon">⚙</div>
<h3>CI/CD Pipeline</h3>
<p>Built an automated deployment pipeline using infrastructure as code to provision and update cloud resources on every commit.</p>
<div class="project-tags">
<span class="tag">Terraform</span>
<span class="tag">GitHub Actions</span>
<span class="tag">IaC</span>
</div>
</div>
<div class="project-card">
<div class="project-icon">📊</div>
<h3>Cloud Monitoring Dashboard</h3>
<p>Set up centralized logging and monitoring with custom dashboards and automated alerting for production workloads.</p>
<div class="project-tags">
<span class="tag">CloudWatch</span>
<span class="tag">Lambda</span>
<span class="tag">SNS</span>
</div>
</div>
</div>
</section>
<section id="skills" class="skills">
<h2 class="section-title">Skills & Certifications</h2>
<div class="skills-grid">
<div class="skill-category">
<h3>Cloud Platforms</h3>
<ul>
<li>Amazon Web Services (AWS)</li>
<li>Microsoft Azure</li>
<li>Google Cloud Platform</li>
</ul>
</div>
<div class="skill-category">
<h3>DevOps & IaC</h3>
<ul>
<li>Terraform</li>
<li>Docker</li>
<li>GitHub Actions</li>
</ul>
</div>
<div class="skill-category">
<h3>Networking & Security</h3>
<ul>
<li>VPC / Subnets</li>
<li>IAM & Security Groups</li>
<li>DNS & Load Balancing</li>
</ul>
</div>
<div class="skill-category">
<h3>Certifications</h3>
<ul>
<li>AWS Solutions Architect</li>
<li>AWS Cloud Practitioner</li>
<li>HashiCorp Terraform Associate</li>
</ul>
</div>
</div>
</section>
<section id="contact" class="contact">
<h2 class="section-title">Get In Touch</h2>
<p class="contact-description">Interested in working together or have a question? Reach out through any of the channels below.</p>
<div class="contact-links">
<a href="mailto:your-email@example.com" class="contact-link">Email</a>
<a href="https://linkedin.com/in/your-profile" class="contact-link" target="_blank" rel="noopener noreferrer">LinkedIn</a>
<a href="https://github.com/your-username" class="contact-link" target="_blank" rel="noopener noreferrer">GitHub</a>
</div>
</section>
</main>
<footer class="footer">
<p>Built by Your Name | Cloud Engineer Portfolio</p>
</footer>
<script src="script.js"></script>
</body>
</html>
Your portfolio's HTML structure is complete. It looks plain right now because there's no styling yet. Next up, you'll bring this page to life with CSS by adding colors, layout, and responsive design.
Style Your Portfolio with CSS
Your HTML structure is complete, but right now it looks like a plain text document. A professional portfolio needs a polished visual design to make a strong first impression on employers.
In this step, you will create a CSS stylesheet that transforms your raw HTML into a modern, responsive portfolio. You will use CSS custom properties for consistent theming, CSS Grid for layout, and media queries to make everything look great on mobile.
In this step, get ready to:
- Create base styles with CSS variables, a universal reset, and a fixed navigation header.
- Style the project cards and skills sections with responsive CSS Grid layouts.
- Add contact, footer, and responsive media query styles for mobile devices.
Create base styles and header/hero design
CSS custom properties (also called CSS variables) let you define your color palette once and reuse those values everywhere. If you want to change your color scheme later, you only update the values in one place.
- In your code editor, right-click the cloud-portfolio folder in the sidebar and select New File.
- Name the file style.css.
- Add the CSS variables, universal reset, and body styles by copying the following code into style.css:
/* Define your color palette and font as reusable variables */
:root {
--color-primary: #0f4c75;
--color-secondary: #1b9aaa;
--color-accent: #3282b8;
--color-bg: #ffffff;
--color-bg-alt: #f4f9fc;
--color-text: #1a1a2e;
--color-text-light: #555555;
--color-border: #e0e0e0;
--font-main: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
/* Remove default browser spacing so layout starts clean */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Enable smooth scrolling for anchor links */
html {
scroll-behavior: smooth;
}
/* Set the base font, text color, and background for the entire page */
body {
font-family: var(--font-main);
color: var(--color-text);
background-color: var(--color-bg);
line-height: 1.6;
}
What does this code do?
- :root defines CSS variables that you reference throughout the stylesheet with var(--name). Changing a value here updates it everywhere at once.
- The universal reset (* { margin: 0; padding: 0; }) strips out default browser spacing so every element starts from a clean slate.
- scroll-behavior: smooth makes anchor link navigation glide smoothly instead of jumping instantly.
- Save style.css.
- Open index.html in your browser (or refresh it if it is already open). You should see the font change to a clean sans-serif and the default spacing between elements disappear.
Page still looks the same?
- Make sure style.css is saved in the same folder as index.html. The <link> tag in your HTML expects to find it right next to index.html.
- Check for typos in the filename. It must be exactly style.css (lowercase, no spaces).
- Try a hard refresh: Cmd+Shift+R (macOS) or Ctrl+Shift+R (Windows). Browsers sometimes cache old styles.
Why isn't my CSS file being applied to my HTML page?
- Add the header and navigation styles below the body rule in style.css:
/* Header - stays fixed at the top of the page */
.header {
position: fixed;
top: 0;
left: 0;
width: 100%;
background-color: var(--color-bg);
border-bottom: 1px solid var(--color-border);
z-index: 100;
}
/* Nav - spreads logo and links across the header */
.nav {
max-width: 1100px;
margin: 0 auto;
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.nav-logo {
font-size: 1.4rem;
font-weight: 700;
color: var(--color-primary);
text-decoration: none;
}
.nav-links {
display: flex;
list-style: none;
gap: 2rem;
}
.nav-links a {
text-decoration: none;
color: var(--color-text);
font-weight: 500;
transition: color 0.3s;
}
.nav-links a:hover {
color: var(--color-secondary);
}
/* Hidden by default - shown on mobile via media query */
.nav-toggle {
display: none;
background: none;
border: none;
cursor: pointer;
padding: 0.5rem;
}
/* Three-line hamburger icon built with CSS */
.hamburger {
display: block;
width: 24px;
height: 2px;
background-color: var(--color-text);
position: relative;
}
.hamburger::before,
.hamburger::after {
content: '';
position: absolute;
width: 24px;
height: 2px;
background-color: var(--color-text);
left: 0;
}
.hamburger::before {
top: -7px;
}
.hamburger::after {
top: 7px;
}
What does this code do?
- position: fixed keeps the header pinned to the top of the screen as the user scrolls down the page.
- Flexbox (display: flex) arranges the logo and links side by side with justify-content: space-between pushing them to opposite ends.
- The hamburger menu button is hidden with display: none on desktop. A media query later in the file will reveal it on smaller screens.
- The three horizontal lines of the hamburger icon are built entirely with CSS. The middle line is the .hamburger span itself, and the top and bottom lines use ::before and ::after pseudo-elements.
- Save style.css and refresh your browser.
- You should see a fixed navigation bar at the top of the page with the CloudPortfolio logo on the left and three navigation links on the right. The nav links should change color when you hover over them.
Header not sticking to the top?
- Make sure position: fixed is inside the .header rule, not the .nav rule.
- Check that every CSS rule has matching opening and closing curly braces { }. A missing brace can break all the styles that follow it.
Why is my CSS header not staying fixed at the top of the page?
- Add the hero section and button styles below the hamburger rules in style.css:
/* Hero - full-height landing section with gradient background */
.hero {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 6rem 2rem 4rem;
background: linear-gradient(135deg, var(--color-bg-alt) 0%, var(--color-bg) 100%);
}
.hero-content {
max-width: 700px;
}
.hero h1 {
font-size: 2.8rem;
margin-bottom: 1rem;
color: var(--color-text);
}
.highlight {
color: var(--color-secondary);
}
.hero-subtitle {
font-size: 1.3rem;
color: var(--color-accent);
margin-bottom: 1rem;
font-weight: 600;
}
.hero-description {
font-size: 1.1rem;
color: var(--color-text-light);
margin-bottom: 2rem;
}
/* Call-to-action button */
.btn {
display: inline-block;
padding: 0.8rem 2rem;
background-color: var(--color-primary);
color: #ffffff;
text-decoration: none;
border-radius: 6px;
font-weight: 600;
transition: background-color 0.3s;
}
.btn:hover {
background-color: var(--color-accent);
}
What does this code do?
- min-height: 100vh makes the hero section fill the entire browser window height. This creates a landing-page effect where the hero is the first thing visitors see.
- The linear-gradient background adds subtle visual depth without being distracting. It blends the alternate background color into white at a 135-degree angle.
- padding: 6rem 2rem 4rem adds extra space at the top so the hero content does not hide behind the fixed header.
- Save style.css and refresh your browser.
- You should see a full-height hero section with your name in large text, a teal-colored subtitle, and a dark blue View My Projects button. The button should change color when you hover over it.
Hero text hidden behind the header?
- Check that the .hero padding starts with 6rem at the top. This pushes the content down below the fixed header.
- Make sure the .header has z-index: 100 so it stays above the hero content.
Why is my hero section overlapping with or hidden behind the fixed header?
Add project card and skills styles
- Add the section title, projects grid, and project card styles below the .btn:hover rule in style.css:
/* Shared heading style for all sections */
.section-title {
font-size: 2rem;
text-align: center;
margin-bottom: 2.5rem;
color: var(--color-primary);
}
/* Projects section */
.projects {
padding: 5rem 2rem;
background-color: var(--color-bg);
}
/* Responsive grid that auto-wraps cards based on available space */
.projects-grid {
max-width: 1100px;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
/* Each card lifts up on hover for a subtle interactive feel */
.project-card {
background-color: var(--color-bg-alt);
border: 1px solid var(--color-border);
border-radius: 10px;
padding: 2rem;
transition: transform 0.3s, box-shadow 0.3s;
}
.project-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
.project-icon {
font-size: 2.5rem;
margin-bottom: 1rem;
}
.project-card h3 {
font-size: 1.3rem;
margin-bottom: 0.8rem;
color: var(--color-primary);
}
.project-card p {
color: var(--color-text-light);
margin-bottom: 1.2rem;
font-size: 0.95rem;
}
/* Flex container for pill-shaped tech stack badges */
.project-tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.tag {
background-color: var(--color-primary);
color: #ffffff;
padding: 0.3rem 0.8rem;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 500;
}
What does this code do?
- repeat(auto-fit, minmax(300px, 1fr)) creates a responsive grid that automatically wraps cards to new rows when the screen gets narrower. Each card is at least 300px wide.
- transform: translateY(-5px) lifts cards slightly on hover, combined with a shadow effect. This gives a sense of interactivity without any JavaScript.
- The .tag class creates pill-shaped badges with border-radius: 20px. These display the tech stack for each project.
- Save style.css and refresh your browser.
- Scroll down past the hero. You should see three project cards arranged in a row, each with an icon, title, description, and colored tech stack badges. Hover over a card to see it lift up with a shadow.
Cards stacking vertically instead of in a row?
- Make sure display: grid is inside the .projects-grid rule. Without it, the cards default to stacking vertically.
- If your browser window is narrower than 900px, the cards will naturally wrap into a single column. Try making your browser window wider.
Why are my CSS Grid project cards not displaying side by side?
- Add the skills section styles below the .tag rule in style.css:
/* Skills section with alternating background */
.skills {
padding: 5rem 2rem;
background-color: var(--color-bg-alt);
}
/* Narrower columns than projects grid to fit four categories */
.skills-grid {
max-width: 1100px;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 2rem;
}
.skill-category {
background-color: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: 10px;
padding: 1.5rem;
}
.skill-category h3 {
font-size: 1.1rem;
margin-bottom: 1rem;
color: var(--color-secondary);
}
.skill-category ul {
list-style: none;
}
.skill-category li {
padding: 0.4rem 0;
color: var(--color-text-light);
font-size: 0.95rem;
}
/* Add a checkmark before each skill item */
.skill-category li::before {
content: '\2713 ';
color: var(--color-secondary);
font-weight: 700;
margin-right: 0.5rem;
}
What does this code do?
- minmax(220px, 1fr) creates narrower columns than the projects grid, letting four skill category cards fit across the page.
- The ::before pseudo-element adds a teal checkmark before each list item without needing to change the HTML.
- background-color: var(--color-bg-alt) on the skills section creates a subtle alternating background that visually separates it from the projects section above.
- Save style.css and refresh your browser.
- Scroll down to the Skills section. You should see four category cards in a row, each with a teal heading and a list of skills prefixed by teal checkmarks. The section has a light blue-gray background.
Checkmarks not appearing?
- Check that list-style: none is on .skill-category ul and the ::before pseudo-element is on .skill-category li::before. These are two different selectors.
- Make sure the content value uses a backslash: content: '\2713 '. The backslash is required for Unicode characters in CSS.
Why are my CSS pseudo-element checkmarks not showing up in the skills list?
Add contact, footer, and responsive styles
- Add the contact section and footer styles below the .skill-category li::before rule in style.css:
/* Contact section - centered text with outlined link buttons */
.contact {
padding: 5rem 2rem;
text-align: center;
background-color: var(--color-bg);
}
.contact-description {
color: var(--color-text-light);
max-width: 600px;
margin: 0 auto 2rem;
font-size: 1.05rem;
}
.contact-links {
display: flex;
justify-content: center;
gap: 1.5rem;
flex-wrap: wrap;
}
/* Outlined buttons that fill with color on hover */
.contact-link {
display: inline-block;
padding: 0.7rem 1.8rem;
border: 2px solid var(--color-primary);
color: var(--color-primary);
text-decoration: none;
border-radius: 6px;
font-weight: 600;
transition: background-color 0.3s, color 0.3s;
}
.contact-link:hover {
background-color: var(--color-primary);
color: #ffffff;
}
/* Footer */
.footer {
text-align: center;
padding: 2rem;
background-color: var(--color-primary);
color: #ffffff;
font-size: 0.9rem;
}
What does this code do?
- The contact links use an outlined style by default (just a border, no fill). On hover, they fill with the primary color and the text turns white. This creates an inviting interaction.
- max-width: 600px on the description keeps the text from stretching too wide on large screens, making it easier to read.
- The footer uses the primary dark blue color as its background, creating a strong visual anchor at the bottom of the page.
- Save style.css and refresh your browser.
- Scroll to the bottom of the page. You should see a centered contact section with three outlined buttons (Email, LinkedIn, GitHub) that fill with dark blue when you hover over them. Below that, a dark blue footer displays the credit line in white text.
Contact buttons not changing on hover?
- Make sure both the .contact-link and .contact-link:hover rules are present. The hover rule must be separate from the base rule.
- Check that the transition property lists both background-color and color separated by a comma. Without the transition, the hover effect will snap instead of animating smoothly.
Why is my CSS hover transition not working on the contact buttons?
The desktop design is complete. Now you need to make it look good on phones and tablets too. Media queries let you apply different styles based on the screen width.
- Add the responsive media queries at the very bottom of style.css:
/* Responsive - tablet and mobile (768px and below) */
@media (max-width: 768px) {
/* Show the hamburger button on small screens */
.nav-toggle {
display: block;
}
/* Hide nav links by default, show as vertical list when active */
.nav-links {
display: none;
position: absolute;
top: 100%;
left: 0;
width: 100%;
background-color: var(--color-bg);
flex-direction: column;
padding: 1rem 2rem;
gap: 1rem;
border-bottom: 1px solid var(--color-border);
}
/* JavaScript will toggle this class to show/hide the menu */
.nav-links.active {
display: flex;
}
.hero h1 {
font-size: 2rem;
}
.hero-subtitle {
font-size: 1.1rem;
}
/* Stack project cards in a single column */
.projects-grid {
grid-template-columns: 1fr;
}
/* Two-column skills grid on tablets */
.skills-grid {
grid-template-columns: 1fr 1fr;
}
}
/* Extra small screens (480px and below) */
@media (max-width: 480px) {
/* Single column skills grid on phones */
.skills-grid {
grid-template-columns: 1fr;
}
}
What does this code do?
- At 768px and below, the nav links hide and the hamburger button appears. The .active class (which you will wire up with JavaScript in the next step) controls whether the mobile menu is visible.
- The projects grid switches to a single column (1fr) so cards stack vertically on narrow screens.
- At 480px, the skills grid also drops to a single column. This two-tier breakpoint ensures the layout adapts gracefully from desktop to tablet to phone.
- Save style.css and refresh your browser.
- Resize your browser window to a narrow width (or press F12 to open developer tools and toggle the device toolbar). You should see the nav links disappear and a three-line hamburger icon appear in the header. The project cards should stack in a single column.
Why doesn't the hamburger menu open yet?
The hamburger button is visible on small screens, but clicking it does nothing yet. That is expected. The menu needs JavaScript to toggle the .active class on the nav links, which you will add in the next step.
Hamburger icon not appearing on small screens?
- Make sure the @media (max-width: 768px) block is at the bottom of your CSS file, after all other rules. Media queries need to come last so they can override earlier styles.
- Check that the media query has its own opening and closing curly braces { } wrapping all the rules inside it.
Why is my hamburger menu not showing up when I resize the browser to mobile width?
✔️ 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 with yours and fix any differences.
:root {
--color-primary: #0f4c75;
--color-secondary: #1b9aaa;
--color-accent: #3282b8;
--color-bg: #ffffff;
--color-bg-alt: #f4f9fc;
--color-text: #1a1a2e;
--color-text-light: #555555;
--color-border: #e0e0e0;
--font-main: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
font-family: var(--font-main);
color: var(--color-text);
background-color: var(--color-bg);
line-height: 1.6;
}
.header {
position: fixed;
top: 0;
left: 0;
width: 100%;
background-color: var(--color-bg);
border-bottom: 1px solid var(--color-border);
z-index: 100;
}
.nav {
max-width: 1100px;
margin: 0 auto;
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.nav-logo {
font-size: 1.4rem;
font-weight: 700;
color: var(--color-primary);
text-decoration: none;
}
.nav-links {
display: flex;
list-style: none;
gap: 2rem;
}
.nav-links a {
text-decoration: none;
color: var(--color-text);
font-weight: 500;
transition: color 0.3s;
}
.nav-links a:hover {
color: var(--color-secondary);
}
.nav-toggle {
display: none;
background: none;
border: none;
cursor: pointer;
padding: 0.5rem;
}
.hamburger {
display: block;
width: 24px;
height: 2px;
background-color: var(--color-text);
position: relative;
}
.hamburger::before,
.hamburger::after {
content: '';
position: absolute;
width: 24px;
height: 2px;
background-color: var(--color-text);
left: 0;
}
.hamburger::before {
top: -7px;
}
.hamburger::after {
top: 7px;
}
.hero {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 6rem 2rem 4rem;
background: linear-gradient(135deg, var(--color-bg-alt) 0%, var(--color-bg) 100%);
}
.hero-content {
max-width: 700px;
}
.hero h1 {
font-size: 2.8rem;
margin-bottom: 1rem;
color: var(--color-text);
}
.highlight {
color: var(--color-secondary);
}
.hero-subtitle {
font-size: 1.3rem;
color: var(--color-accent);
margin-bottom: 1rem;
font-weight: 600;
}
.hero-description {
font-size: 1.1rem;
color: var(--color-text-light);
margin-bottom: 2rem;
}
.btn {
display: inline-block;
padding: 0.8rem 2rem;
background-color: var(--color-primary);
color: #ffffff;
text-decoration: none;
border-radius: 6px;
font-weight: 600;
transition: background-color 0.3s;
}
.btn:hover {
background-color: var(--color-accent);
}
.section-title {
font-size: 2rem;
text-align: center;
margin-bottom: 2.5rem;
color: var(--color-primary);
}
.projects {
padding: 5rem 2rem;
background-color: var(--color-bg);
}
.projects-grid {
max-width: 1100px;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
.project-card {
background-color: var(--color-bg-alt);
border: 1px solid var(--color-border);
border-radius: 10px;
padding: 2rem;
transition: transform 0.3s, box-shadow 0.3s;
}
.project-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
.project-icon {
font-size: 2.5rem;
margin-bottom: 1rem;
}
.project-card h3 {
font-size: 1.3rem;
margin-bottom: 0.8rem;
color: var(--color-primary);
}
.project-card p {
color: var(--color-text-light);
margin-bottom: 1.2rem;
font-size: 0.95rem;
}
.project-tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.tag {
background-color: var(--color-primary);
color: #ffffff;
padding: 0.3rem 0.8rem;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 500;
}
.skills {
padding: 5rem 2rem;
background-color: var(--color-bg-alt);
}
.skills-grid {
max-width: 1100px;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 2rem;
}
.skill-category {
background-color: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: 10px;
padding: 1.5rem;
}
.skill-category h3 {
font-size: 1.1rem;
margin-bottom: 1rem;
color: var(--color-secondary);
}
.skill-category ul {
list-style: none;
}
.skill-category li {
padding: 0.4rem 0;
color: var(--color-text-light);
font-size: 0.95rem;
}
.skill-category li::before {
content: '\2713 ';
color: var(--color-secondary);
font-weight: 700;
margin-right: 0.5rem;
}
.contact {
padding: 5rem 2rem;
text-align: center;
background-color: var(--color-bg);
}
.contact-description {
color: var(--color-text-light);
max-width: 600px;
margin: 0 auto 2rem;
font-size: 1.05rem;
}
.contact-links {
display: flex;
justify-content: center;
gap: 1.5rem;
flex-wrap: wrap;
}
.contact-link {
display: inline-block;
padding: 0.7rem 1.8rem;
border: 2px solid var(--color-primary);
color: var(--color-primary);
text-decoration: none;
border-radius: 6px;
font-weight: 600;
transition: background-color 0.3s, color 0.3s;
}
.contact-link:hover {
background-color: var(--color-primary);
color: #ffffff;
}
.footer {
text-align: center;
padding: 2rem;
background-color: var(--color-primary);
color: #ffffff;
font-size: 0.9rem;
}
@media (max-width: 768px) {
.nav-toggle {
display: block;
}
.nav-links {
display: none;
position: absolute;
top: 100%;
left: 0;
width: 100%;
background-color: var(--color-bg);
flex-direction: column;
padding: 1rem 2rem;
gap: 1rem;
border-bottom: 1px solid var(--color-border);
}
.nav-links.active {
display: flex;
}
.hero h1 {
font-size: 2rem;
}
.hero-subtitle {
font-size: 1.1rem;
}
.projects-grid {
grid-template-columns: 1fr;
}
.skills-grid {
grid-template-columns: 1fr 1fr;
}
}
@media (max-width: 480px) {
.skills-grid {
grid-template-columns: 1fr;
}
}
Your portfolio looks polished and professional. Next up, you will add JavaScript to make the hamburger menu work on mobile screens.
Add JavaScript Interactivity
Your portfolio looks polished with a fixed header, styled project cards, and responsive layouts. There's one problem though: on mobile screens, the hamburger menu button doesn't do anything yet.
In this step, you'll write JavaScript to make the hamburger menu toggle the navigation links open and closed. You'll also make the menu close automatically when a visitor clicks a link.
In this step, get ready to:
- Create script.js with mobile navigation toggle logic.
- Test the hamburger menu and smooth-scroll navigation in your browser.
Create the mobile navigation toggle
Your index.html already has a <script src="script.js"></script> tag at the bottom. Once you create the matching file, the browser will load and run your JavaScript automatically.
- In your code editor, create a new file called script.js inside the cloud-portfolio folder.
- Add the hamburger menu toggle by pasting this code into script.js:
document.addEventListener('DOMContentLoaded', function () {
// Select the hamburger button and the navigation links list
var navToggle = document.querySelector('.nav-toggle');
var navLinks = document.querySelector('.nav-links');
// Toggle the mobile menu open or closed on hamburger click
navToggle.addEventListener('click', function () {
navLinks.classList.toggle('active');
});
});
What does this code do?
- document.addEventListener('DOMContentLoaded', ...) waits for the HTML to fully load before running any JavaScript. This prevents errors from trying to select elements that don't exist yet.
- document.querySelector('.nav-toggle') finds the hamburger button in your HTML by its class name.
- classList.toggle('active') adds the active class if it's missing, or removes it if it's already there. Your CSS uses .nav-links.active to show the mobile menu, so toggling this class switches the menu on and off.
- Save script.js.
- You won't see a change on desktop yet. The next chunk adds link-closing behavior, and then you'll test both together on mobile.
Seeing errors in the console?
- Make sure script.js is saved directly inside the cloud-portfolio folder, not inside a subfolder.
- Check that the file name is exactly script.js. The index.html file references this exact name in its <script> tag.
Why isn't my script.js file being loaded by the browser?
- In script.js, find the closing }); of the navToggle.addEventListener block.
- Add the link-closing behavior below it, still inside the DOMContentLoaded function:
// Select all navigation links
var links = document.querySelectorAll('.nav-links a');
// Close the mobile menu when any nav link is clicked
links.forEach(function (link) {
link.addEventListener('click', function () {
navLinks.classList.remove('active');
});
});
What does this code do?
- document.querySelectorAll('.nav-links a') selects every anchor tag inside the navigation list, giving you all three links (Projects, Skills, Contact).
- forEach loops through each link and attaches its own click listener.
- classList.remove('active') closes the mobile menu whenever a link is clicked, so the visitor can see the section they navigated to.
- Save script.js.
- You won't see a visible change on desktop. The next substep walks you through testing on mobile.
Not sure where to add the code?
The new code goes between the closing }); of the toggle listener and the final }); that closes the DOMContentLoaded callback. If you're unsure, use the double-check tab below to compare your full file.
I'm not sure where to place the new code inside script.js. Can you help?
✔️ Awesome, I've got everything!
Great. Make sure you've saved script.js before moving on to testing.
ⓧ I'd like to double check the full code
Here's the complete script.js file. Compare it with yours and make sure every line matches.
document.addEventListener('DOMContentLoaded', function () {
var navToggle = document.querySelector('.nav-toggle');
var navLinks = document.querySelector('.nav-links');
navToggle.addEventListener('click', function () {
navLinks.classList.toggle('active');
});
var links = document.querySelectorAll('.nav-links a');
links.forEach(function (link) {
link.addEventListener('click', function () {
navLinks.classList.remove('active');
});
});
});
Test the mobile navigation
Your JavaScript is ready. Let's test it by simulating a mobile screen in your browser's developer tools.
- Refresh index.html in your browser.
- Press F12 to open your browser's developer tools.
- Click the device toolbar toggle button (it looks like a phone and tablet icon near the top-left of the DevTools panel) to switch to mobile view.
- Click the hamburger menu icon (three horizontal lines) in the top-right of the header.
The navigation links (Projects, Skills, Contact) should appear in a vertical list below the header.
- Click the hamburger icon again to verify the menu closes.
- Click the hamburger icon one more time to reopen the menu.
- Click one of the navigation links, for example Projects.
The menu should close, and the page should smooth-scroll down to the Projects section.
Why does smooth scrolling work?
You set scroll-behavior: smooth on the html element in your CSS. The browser handles the smooth animation natively when any anchor link (like #projects) is clicked. No extra JavaScript is needed for this.
Hamburger menu not working?
- Open the browser console (press F12, then click the Console tab). Look for any red error messages.
- Make sure you are in mobile view. The hamburger button is hidden on desktop screens by default.
- Verify that .nav-toggle in your JavaScript matches class="nav-toggle" in your index.html. Class names are case-sensitive.
- Check that all your code is inside the DOMContentLoaded callback. Code outside it may run before the page finishes loading.
My hamburger menu isn't toggling the navigation. Can you help me debug?
Your portfolio now has a working mobile menu and smooth-scroll navigation. Next up, you'll deploy it live to GitHub Pages so you have a shareable URL to put on your resume.
Deploy to GitHub Pages
Your portfolio is complete and working beautifully on your local machine. There is just one problem: only you can see it.
To share your portfolio with employers, you need to put it on the internet. In this step, you'll use Git to upload your code to GitHub, then turn on GitHub Pages to publish your repository as a live website.
In this step, get ready to:
- Stage, commit, and push your code to GitHub.
- Enable GitHub Pages on your repository.
- View your live portfolio at a public URL.
Stage, commit, and push your code
Git tracks changes in three stages. First, you stage the files you want to include. Then, you commit those staged files as a snapshot with a message. Finally, you push the commit to GitHub so your code is stored online.
- Switch back to your terminal.
- The git push command may open a browser window asking you to sign in to GitHub. If this happens, sign in with the account you created earlier.
- Stage, commit, and push your files to GitHub by running these commands:
git add .
git commit -m "Add portfolio website"
git push
What do these commands do?
- git add . stages all new and changed files in the current folder. The . means "everything in this directory."
- git commit -m "Add portfolio website" saves a snapshot of the staged files with a descriptive message.
- git push uploads the commit to your GitHub repository so it is available online.
- You should see output that ends with main -> main, confirming your code was pushed to the main branch.
Push failed?
- Make sure your terminal is inside the cloud-portfolio folder. Run pwd (macOS/Linux) or cd (Windows) to check your current directory.
- If you see an authentication error, make sure you signed in to the correct GitHub account when the browser window appeared.
- If the browser sign-in window did not appear, close your terminal, reopen it, navigate back to the cloud-portfolio folder, and try git push again.
Still stuck? Ask for help.
Enable GitHub Pages
Your code is on GitHub, but it is not a website yet. GitHub Pages is a free hosting service that turns your repository into a live site.
- Open your browser and go to your repository on GitHub.
- Click Settings in the top menu bar of your repository.
- In the left sidebar, under Code and automation, click Pages.
- Under Build and deployment, find the Source dropdown and select Deploy from a branch.
- Under Branch, select main from the branch dropdown.
- Leave the folder set to / (root).
- Click Save.
What is GitHub Pages?
GitHub Pages is a free hosting service that publishes your repository's files as a website. When you select main as the branch and / as the folder, GitHub serves your index.html file directly from the root of your repository.
Any time you push new code to the main branch, GitHub Pages automatically rebuilds and updates your live site.
After clicking Save, the Pages settings page should now show your branch set to main and the folder set to / (root).
Don't see the Branch dropdown?
Make sure the Source is set to Deploy from a branch first. The branch dropdown only appears after selecting this option.
Need a hand?
View your live portfolio
GitHub Pages needs a minute or two to build and deploy your site for the first time. Once it is ready, your portfolio will be live at a public URL that anyone can visit.
- Wait 1-2 minutes for the deployment to complete.
- Open a new browser tab and visit your portfolio URL:
https://[[GITHUB_USERNAME="your-username"]].github.io/cloud-portfolio/
- Verify all sections display correctly: hero, projects, skills, and contact.
- Click the navigation links to make sure they smooth-scroll to each section.
- Resize your browser window to test that the responsive layout still works on smaller screens.
What if I see a 404 page?
It can take up to 10 minutes for changes to publish after the first deployment. If you see a 404 error, wait a few minutes and refresh the page.
Double check that your repository contains a file named exactly index.html in the root folder (not inside a subfolder). GitHub Pages looks for this file as the entry point for your site.
Site not loading after 10 minutes?
- Go back to your repository's Settings > Pages and confirm the branch is set to main and the folder is / (root).
- Make sure your repository is set to Public. GitHub Pages requires a public repository on the free plan.
- Check that your git push completed successfully. Go to your repository's main page on GitHub and confirm you can see index.html, style.css, and script.js listed in the file tree.
Still not working? Ask for help.
You should see your full portfolio site live in the browser. It looks exactly like the local version, but now anyone with the link can view it.
Secret mission
Add a Dark Mode Toggle
Your portfolio looks great, but what if visitors prefer a darker color scheme? In this bonus challenge, you will add a dark mode toggle button that switches the entire site between light and dark themes with a single click.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely for free. GitHub Pages hosting is free for public repositories, and all your code lives locally and on GitHub at no cost.
Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- Local cloud-portfolio folder on your Desktop containing index.html, style.css, script.js, and README.md.
- GitHub cloud-portfolio repository with GitHub Pages site.
- Git installed on your machine.
- GitHub account.
Keep everything running
No action needed. Choose this option if you want to keep your portfolio live and continue updating it.
- Your portfolio stays live at your GitHub Pages URL for free.
- Your local cloud-portfolio folder stays on your Desktop for future edits.
- Git stays installed on your machine for future projects.
- Your GitHub account stays active. You can use it for future repositories and projects.
Pause - I'll come back to this later
Since GitHub Pages is free, there are no costs to pause. You can tidy up your local workspace while keeping your live site running.
- Close the cloud-portfolio folder in your code editor to free up your workspace.
- Your GitHub Pages site stays live at no cost. You can come back and edit your code anytime.
- When you are ready to resume, open the cloud-portfolio folder on your Desktop in your code editor.
Delete - I don't want to use this again
Remove all project resources and start fresh. This deletes your local files, your GitHub repository, and your live GitHub Pages site.
Delete the local project folder:
- Your terminal is currently inside the cloud-portfolio folder. Navigate out of it first by running:
cd ~/Desktop
- On macOS or Linux, delete the folder by running:
rm -rf cloud-portfolio
- On Windows, delete the folder by running:
rmdir /s /q cloud-portfolio
Delete the GitHub repository:
- Go to your cloud-portfolio repository on GitHub.
- Click Settings in the top menu bar.
- Scroll down to the Danger Zone section at the bottom of the page.
- Click Delete this repository and follow the confirmation prompts.
- This also removes your GitHub Pages site. The URL will stop working.
Uninstall Git (optional):
- If you installed Git using winget on Windows, uninstall it by running:
winget uninstall --id Git.Git
- If you installed Git using the downloaded installer, remove it through Settings, then Apps, then Installed apps. Find Git in the list and click Uninstall.
Keep your GitHub account:
- Your GitHub account is free and useful for future projects. There is no reason to delete it unless you are certain you will not use it again.
Nice Work!
Nice Work!
You just built a professional cloud engineer portfolio from scratch and deployed it live to the internet. You now have a real URL to share on your resume, LinkedIn, and job applications.
You learned how to:
- Build a complete portfolio website using HTML, CSS, and JavaScript, with a responsive layout using CSS Grid, custom properties, and media queries.
- Use Git fundamentals to configure, clone, stage, commit, and push code to a GitHub repository.
- Deploy a live website to GitHub Pages with a shareable URL you can put on your resume and job applications.
- Secret Mission: Added a dark mode toggle using CSS variable overriding and JavaScript class toggling.
Ready to quiz yourself?