Build a Portfolio with AWS Amplify

Build and publish a responsive portfolio with AWS Amplify Hosting.

Introduction

30 Second Summary

Your work is difficult to share when it sits in separate files on your computer. A visitor needs one clear place to understand who you are and what you can do.

In this project, you will build a responsive personal portfolio with HTML and CSS. You will publish it with Cloudflare Pages so anyone with its public address can open it.

What You'll Build

You will share a live portfolio that stays readable on a narrow screen while visitors move through your introduction, skills, projects, and contact details.

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

  • A personal home page that shows visitors your introduction, skills, and contact details at a glance.
  • A two-page navigation loop that takes visitors from Home to three project cards and back through working relative links.
  • A responsive public portfolio whose pages.dev address opens the same layout you tested locally.
  • Secret Mission: Add a dedicated About page and connect it to every navigation bar on the live site.

Are there any prerequisites?

No prior web development experience or Cloudflare account is required. You need a Windows device with Visual Studio Code.

Before We Start

A clear audience gives every portfolio decision a purpose. This short checkpoint helps you define who should visit your portfolio and what they should learn about you before the hands-on work begins.

Set Up Your Portfolio Workspace

A portfolio becomes easier to build when every file lives in one predictable place. A verified browser also gives each saved change a clear place to appear.

In this step, you'll confirm Microsoft Edge opens. You'll select Visual Studio Code as the workspace for your site.

In this step, get ready to:
  • Verify Microsoft Edge opens on your Windows device.
  • Create the free-portfolio workspace in Visual Studio Code.
  • Display the saved starter page in Microsoft Edge.
Prepare your local workspace

A local browser preview gives you immediate proof that your files are in the right place. Keeping those files in one workspace makes later edits easier to find.

  • Press the Windows key to open Windows search.

You'll see the Windows search box ready for an app name.

  • Type Microsoft Edge into the search box.

You'll either see Microsoft Edge in the results or confirm that it is unavailable.

  • Select Microsoft Edge from the search results.

✔️ Microsoft Edge opens

Microsoft Edge is ready to display the portfolio files you save locally.

ⓧ Microsoft Edge is unavailable

  • Visit the official Download Microsoft Edge page in an available browser.
  • Download the Windows browser installer offered on the page.
  • Run the downloaded installer.
  • Return to Windows search after the installation finishes.
  • Type Microsoft Edge into the search box.
  • Select Microsoft Edge from the search results.

Microsoft Edge still unavailable?

Check that the installer completed before searching again. If the installation stops or Microsoft Edge remains missing, get help with the Windows installation.

Visual Studio Code treats an opened folder as a workspace. Its Explorer keeps every portfolio file under the same folder name.

  • Press the Windows key to open Windows search.
  • Type Visual Studio Code into the search box.

You'll see Visual Studio Code in the search results.

  • Select Visual Studio Code from the search results.
  • Click File in the top menu.
  • Select Open Folder....

You'll see a folder picker where you can choose the location for your portfolio.

  • Create a folder named free-portfolio on your Desktop.
  • Select the free-portfolio folder as your workspace.

You'll see free-portfolio at the top of the Explorer sidebar.

Why use one workspace folder?

The free-portfolio folder becomes the shared starting point for every page. Relative links can connect files that sit beside one another.

Create the starter HTML page

HTML provides the structure a browser turns into a page. This starter document proves your editor can save a complete page inside the correct folder.

  • Select New File... in the Explorer sidebar.

You'll see a filename field inside the Explorer sidebar.

  • Enter index.html in the filename field.
  • Press Enter to create the file.

You'll see index.html listed in Explorer. The blank file opens in the editor.

  • Add the starter page by copying this code into index.html:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Portfolio Setup</title>
</head>
<body>
  <h1>Portfolio setup works</h1>
</body>
</html>

What does this page do?

  • The <!DOCTYPE html> declaration tells the browser to interpret the document as modern HTML.
  • The <head> stores information the browser needs before displaying the page.
  • The <title> element names the browser tab Portfolio Setup.
  • The <h1> element creates the large heading you will verify in Microsoft Edge.
  • Save index.html by pressing Ctrl+S.
  • Confirm the index.html tab no longer shows an unsaved-change indicator.

File name or code looks different?

  • Check that Explorer lists the file as index.html.
  • Compare every opening HTML tag with its matching closing tag.
  • Still stuck? Get help checking your starter HTML file.

✔️ Awesome, I've got everything!

Your saved index.html contains the complete starter page.

ⓧ I'd like to double check the full code

  • Compare your saved index.html with this complete version.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Portfolio Setup</title>
</head>
<body>
  <h1>Portfolio setup works</h1>
</body>
</html>
Open the page in Microsoft Edge

Local testing lets you inspect a saved website before publishing it. Microsoft Edge can read index.html directly from your free-portfolio folder.

  • Right-click index.html in the Visual Studio Code Explorer.
  • Use the menu option that shows index.html in Windows File Explorer.

Before you open the file, what heading do you expect Microsoft Edge to show?

  • Drag index.html from Windows File Explorer onto the Microsoft Edge window from earlier.

You have your first local page working. Microsoft Edge shows Portfolio setup works as its main heading.

Heading missing in Microsoft Edge?

  • Return to Visual Studio Code.
  • Confirm the heading in index.html says Portfolio setup works.
  • Save index.html by pressing Ctrl+S.
  • Drag the saved index.html file onto Microsoft Edge again.
  • Still stuck? Get help opening the saved page in Microsoft Edge.

Your workspace is ready for the real portfolio. Next, you'll replace this setup check with a visible introduction that starts turning the page into your own site.

Build Your Home Page

Your starter page proves that Microsoft Edge can load files from your workspace. A single heading cannot yet introduce you or show what you are learning.

You will use HTML to structure the home page. You will use CSS to turn that structure into a clear portfolio. The first version also includes a relative link that lets you test how one page points to another file.

In this step, get ready to:
  • Replace the starter page with your portfolio structure.
  • Create the initial visual design in a separate stylesheet.
  • Test the home page and its navigation in Microsoft Edge.
Build the portfolio structure

A home page needs clear regions for navigation, an introduction, skills, contact details, and a footer. These regions give visitors a predictable path through your portfolio.

  • Switch back to index.html in Visual Studio Code.
  • Select all of the existing code in index.html.
  • Replace the starter document with this page shell:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Your Name | Portfolio</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <header class="site-header">
    <nav class="nav shell" aria-label="Main navigation">
      <a class="brand" href="index.html">Your Name</a>
      <div class="nav-links">
        <a href="index.html" aria-current="page">Home</a>
        <a href="projects.html">Projects</a>
      </div>
    </nav>
  </header>

</body>
</html>

What does this structure do?

  • The stylesheet link connects index.html to styles.css.
  • The header gives visitors links to the Home and Projects pages.
  • The aria-current value identifies Home as the page currently being viewed.
  • Save index.html.
  • Return to the local preview in Microsoft Edge.
  • Reload the page.

You will see an unstyled header with your name plus Home and Projects links. The earlier setup heading is gone.

Still seeing the setup heading?

  • Check that you replaced the contents of the existing index.html file inside free-portfolio.
  • Confirm that index.html is saved before reloading the browser.
  • Still stuck? Help me find why Microsoft Edge still shows my old index.html content.

The header helps visitors move around the site. The hero section now needs to answer two questions quickly: who you are and what you are learning.

  • Find the closing </header> line in index.html.
  • Add this hero section directly below that line:
  <main>
    <section class="hero shell">
      <div>
        <p class="eyebrow">Hello, I am</p>
        <h1>Your Name</h1>
        <p class="lede">I am learning to build clear, useful websites and turn ideas into projects people can see and use.</p>
        <div class="actions">
          <a class="button" href="projects.html">View my projects</a>
          <a class="button secondary" href="#contact">Contact me</a>
        </div>
      </div>

      <aside class="panel" aria-labelledby="skills-title">
        <h2 id="skills-title">Skills I am building</h2>
        <ul class="skills-list">
          <li>HTML structure</li>
          <li>CSS layouts</li>
          <li>Responsive design</li>
          <li>Static-site deployment</li>
        </ul>
      </aside>
    </section>
  </main>

How does the hero work?

  • The hero introduces your name through the main page heading.
  • The actions provide direct paths to your projects and contact section.
  • The panel groups your developing skills beside the introduction.
  • Save index.html.
  • Reload the local preview in Microsoft Edge.

You will see your introduction, two links, and a skills list beneath the navigation. The content is still plain because the stylesheet has not been created.

Hero content missing?

  • Confirm that the hero code sits between </header> and </body>.
  • Check that every opening tag has its matching closing tag.
  • Still stuck? Help me debug my home-page HTML structure.

The Contact link uses #contact to point to a section on the same page. A matching id="contact" gives the browser an exact destination.

  • Find the closing </main> line in index.html.
  • Replace that line with the contact section and footer below:
    <section class="section shell" id="contact">
      <div class="contact">
        <p class="eyebrow">Let us connect</p>
        <h2>Contact</h2>
        <p>Replace this text with your preferred email address or professional contact details before sharing the site.</p>
      </div>
    </section>
  </main>

  <footer class="footer shell">
    <p>Built by Your Name with HTML and CSS.</p>
  </footer>

What completes the page?

  • The contact section provides the destination for the Contact me link.
  • The footer closes the page with a short ownership statement.
  • The shared shell class gives the navigation, sections, and footer one consistent content width.
  • Save index.html.
  • Reload the local preview in Microsoft Edge.
  • Select the Contact me link.

The browser will move down to the Contact section. This confirms that the matching fragment link works within the page.

Contact link not moving?

  • Check that the link uses href="#contact".
  • Confirm that the contact section uses id="contact".
  • Still stuck? Help me connect my Contact me link to the contact section.

✔️ Awesome, I've got everything!

Your home-page structure is complete. Double check that index.html is saved.

ⓧ I'd like to double check the full code

Compare your saved index.html with this complete version.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Your Name | Portfolio</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <header class="site-header">
    <nav class="nav shell" aria-label="Main navigation">
      <a class="brand" href="index.html">Your Name</a>
      <div class="nav-links">
        <a href="index.html" aria-current="page">Home</a>
        <a href="projects.html">Projects</a>
      </div>
    </nav>
  </header>

  <main>
    <section class="hero shell">
      <div>
        <p class="eyebrow">Hello, I am</p>
        <h1>Your Name</h1>
        <p class="lede">I am learning to build clear, useful websites and turn ideas into projects people can see and use.</p>
        <div class="actions">
          <a class="button" href="projects.html">View my projects</a>
          <a class="button secondary" href="#contact">Contact me</a>
        </div>
      </div>

      <aside class="panel" aria-labelledby="skills-title">
        <h2 id="skills-title">Skills I am building</h2>
        <ul class="skills-list">
          <li>HTML structure</li>
          <li>CSS layouts</li>
          <li>Responsive design</li>
          <li>Static-site deployment</li>
        </ul>
      </aside>
    </section>

    <section class="section shell" id="contact">
      <div class="contact">
        <p class="eyebrow">Let us connect</p>
        <h2>Contact</h2>
        <p>Replace this text with your preferred email address or professional contact details before sharing the site.</p>
      </div>
    </section>
  </main>

  <footer class="footer shell">
    <p>Built by Your Name with HTML and CSS.</p>
  </footer>
</body>
</html>

This complete file contains the navigation, hero, skills panel, contact section, and footer in their final order.

Style the page foundation

CSS custom properties store reusable design values such as colors and shadows. Changing one property later can update every rule that uses it.

  • Select New File... in the Explorer view.
  • Enter styles.css as the file name.
  • Add the design values and page defaults below:
:root {
  --background: #f7f8fc;
  --surface: #ffffff;
  --text: #172033;
  --muted: #5d6678;
  --accent: #5b45d6;
  --accent-dark: #4332ad;
  --border: #dfe3ec;
  --shadow: 0 16px 40px rgba(23, 32, 51, 0.1);
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  color: var(--text);
  background: var(--background);
  font-family: sans-serif;
  line-height: 1.6;
}

a {
  color: inherit;
}

What do these styles control?

  • The custom properties create a reusable palette for the page.
  • The universal sizing rule keeps element dimensions predictable.
  • The body rule applies the background, text color, font, and line spacing across the page.
  • Save styles.css.
  • Reload the local preview in Microsoft Edge.

You will see a pale background with darker text and more open line spacing. The Contact me link will now scroll smoothly.

Styles not appearing?

  • Confirm that styles.css sits beside index.html inside free-portfolio.
  • Check that the stylesheet link uses href="styles.css".
  • Still stuck? Help me connect styles.css to index.html.
  • Add the shared page width and navigation layout below the existing CSS:
.shell {
  width: min(1080px, calc(100% - 2rem));
  margin-inline: auto;
}

.site-header {
  background: rgba(255, 255, 255, 0.94);
  border-bottom: 1px solid var(--border);
}

.nav {
  min-height: 72px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.brand {
  color: var(--accent);
  font-size: 1.1rem;
  font-weight: 800;
  text-decoration: none;
}

.nav-links {
  display: flex;
  gap: 1rem;
}

How does the navigation align?

  • The shell class keeps content centered inside a maximum width.
  • The navigation uses a flexible row to separate the brand from the page links.
  • The gap values preserve space between nearby items.
  • Save styles.css.
  • Reload the local preview in Microsoft Edge.

You will see your name on the left side of a white header. The Home and Projects links will sit together on the right.

Navigation still stacked?

  • Check that the navigation element uses both nav and shell classes.
  • Confirm that the .nav rule includes display: flex.
  • Still stuck? Help me align my portfolio navigation.
  • Add the navigation link appearance below the current styles:
.nav-links a {
  color: var(--muted);
  font-weight: 700;
  text-decoration: none;
}

.nav-links a:hover,
.nav-links a[aria-current="page"] {
  color: var(--accent);
}

How does the current page stand out?

  • The default link style uses the muted color to keep the header calm.
  • The current-page selector uses aria-current="page" to color Home with the accent.
  • The hover selector gives each navigation link visual feedback.
  • Save styles.css.
  • Reload the local preview in Microsoft Edge.
  • Move your pointer over the Projects link.

Home will appear purple because it is the current page. Projects will change to the same purple when you hover over it.

Home link not highlighted?

  • Confirm that the Home link contains aria-current="page".
  • Check that the selector includes .nav-links a[aria-current="page"].
  • Still stuck? Help me debug the current-page navigation style.
Complete the component styles

The page foundation now controls its overall color and width. Component styles create the two-column hero, action buttons, skills panel, contact card, and footer.

  • Add the hero layout and introduction typography below the current CSS:
.hero {
  min-height: 70vh;
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  align-items: center;
  gap: 3rem;
  padding-block: 5rem;
}

.eyebrow {
  margin: 0 0 0.5rem;
  color: var(--accent);
  font-size: 0.85rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

h1,
h2,
p {
  margin-top: 0;
}

h1 {
  margin-bottom: 1rem;
  font-size: clamp(2.5rem, 7vw, 5rem);
  line-height: 1;
}

How does the hero gain hierarchy?

  • The grid gives the introduction more width than the skills panel.
  • The eyebrow style turns short labels into compact section markers.
  • The flexible heading size lets the main name grow with the browser width.
  • Save styles.css.
  • Reload the local preview in Microsoft Edge.

You will see the introduction and skills content in two columns. Your main name will appear much larger than the surrounding text.

Hero not using two columns?

  • Confirm that the main section uses class="hero shell".
  • Check that the .hero rule includes the grid display and column values.
  • Still stuck? Help me debug my two-column hero layout.
  • Add the introduction width and primary button styles below the hero rules:
.lede {
  max-width: 62ch;
  color: var(--muted);
  font-size: 1.15rem;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.75rem;
}

.button {
  display: inline-block;
  padding: 0.8rem 1.1rem;
  color: #ffffff;
  background: var(--accent);
  border: 2px solid var(--accent);
  border-radius: 0.65rem;
  font-weight: 800;
  text-decoration: none;
}

How do the actions become buttons?

  • The lede width keeps the introduction readable across the hero.
  • The actions container places nearby links in a flexible row.
  • The button class adds padding, color, a border, and rounded corners to each action link.
  • Save styles.css.
  • Reload the local preview in Microsoft Edge.

View my projects and Contact me will appear as purple buttons below the introduction. Their labels will remain readable against the accent color.

Links still look like plain text?

  • Confirm that both action links include the button class.
  • Check that the .button rule appears after the closing brace for .actions.
  • Still stuck? Help me style my portfolio action links as buttons.
  • Add the button states and raised panel appearance below the existing button rule:
.button:hover {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
}

.button.secondary {
  color: var(--accent);
  background: transparent;
}

.panel,
.contact {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 1rem;
  box-shadow: var(--shadow);
}

.panel {
  padding: 2rem;
}

How do the components separate visually?

  • The hover rule darkens the primary action when the pointer reaches it.
  • The secondary button keeps a transparent background to create a quieter action.
  • The panel and contact section share the same surface, border, corners, and shadow.
  • Save styles.css.
  • Reload the local preview in Microsoft Edge.
  • Move your pointer over View my projects.

The primary button will darken under your pointer. The skills panel will appear as a raised white card.

Panel still blends into the page?

  • Confirm that the skills element uses class="panel".
  • Check that the shared selector includes both .panel and .contact.
  • Still stuck? Help me debug the portfolio panel styles.
  • Add the final list, section, contact, and footer spacing below the panel styles:
.skills-list {
  margin: 0;
  padding-left: 1.2rem;
}

.section {
  padding-block: 4rem;
}

.contact {
  padding: 2rem;
}

.footer {
  padding-block: 2rem;
  color: var(--muted);
  border-top: 1px solid var(--border);
}

What finishes the layout?

  • The skills rule preserves readable list indentation inside the panel.
  • The section and contact rules create space around the final message.
  • The footer uses muted text and a top border to close the page.
  • Save styles.css.
  • Reload the local preview in Microsoft Edge.

You will see a styled introduction, a raised skills panel, a separate contact card, and a bordered footer. Your first visible portfolio page is working.

Bottom sections look cramped?

  • Confirm that the contact section includes both section and shell classes.
  • Check that the footer includes both footer and shell classes.
  • Still stuck? Help me fix the contact and footer spacing.

✔️ Awesome, I've got everything!

Your stylesheet is complete for this version of the home page. Double check that styles.css is saved.

ⓧ I'd like to double check the full code

Compare your saved styles.css with this complete version.

:root {
  --background: #f7f8fc;
  --surface: #ffffff;
  --text: #172033;
  --muted: #5d6678;
  --accent: #5b45d6;
  --accent-dark: #4332ad;
  --border: #dfe3ec;
  --shadow: 0 16px 40px rgba(23, 32, 51, 0.1);
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  color: var(--text);
  background: var(--background);
  font-family: sans-serif;
  line-height: 1.6;
}

a {
  color: inherit;
}

.shell {
  width: min(1080px, calc(100% - 2rem));
  margin-inline: auto;
}

.site-header {
  background: rgba(255, 255, 255, 0.94);
  border-bottom: 1px solid var(--border);
}

.nav {
  min-height: 72px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.brand {
  color: var(--accent);
  font-size: 1.1rem;
  font-weight: 800;
  text-decoration: none;
}

.nav-links {
  display: flex;
  gap: 1rem;
}

.nav-links a {
  color: var(--muted);
  font-weight: 700;
  text-decoration: none;
}

.nav-links a:hover,
.nav-links a[aria-current="page"] {
  color: var(--accent);
}

.hero {
  min-height: 70vh;
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  align-items: center;
  gap: 3rem;
  padding-block: 5rem;
}

.eyebrow {
  margin: 0 0 0.5rem;
  color: var(--accent);
  font-size: 0.85rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

h1,
h2,
p {
  margin-top: 0;
}

h1 {
  margin-bottom: 1rem;
  font-size: clamp(2.5rem, 7vw, 5rem);
  line-height: 1;
}

.lede {
  max-width: 62ch;
  color: var(--muted);
  font-size: 1.15rem;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.75rem;
}

.button {
  display: inline-block;
  padding: 0.8rem 1.1rem;
  color: #ffffff;
  background: var(--accent);
  border: 2px solid var(--accent);
  border-radius: 0.65rem;
  font-weight: 800;
  text-decoration: none;
}

.button:hover {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
}

.button.secondary {
  color: var(--accent);
  background: transparent;
}

.panel,
.contact {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 1rem;
  box-shadow: var(--shadow);
}

.panel {
  padding: 2rem;
}

.skills-list {
  margin: 0;
  padding-left: 1.2rem;
}

.section {
  padding-block: 4rem;
}

.contact {
  padding: 2rem;
}

.footer {
  padding-block: 2rem;
  color: var(--muted);
  border-top: 1px solid var(--border);
}

This stylesheet contains every design value, layout rule, navigation style, hero style, button state, panel treatment, and spacing rule used in this step.

Before you test the Projects link, do you think the browser can open its destination from the files currently inside free-portfolio?

  • Reload index.html in Microsoft Edge.
  • Select Projects in the navigation.

Microsoft Edge cannot open the requested Projects page because projects.html does not exist yet. This shortfall is intentional.

What did the link prove?

The link contains href="projects.html", so the browser looks for that file beside index.html. A relative link works only when its target exists at the expected location.

  • Return to the open index.html preview in Microsoft Edge.

Your home page now has a clear structure and a complete first design. Next, you will create the missing page that turns the Projects link into working multi-page navigation.

Fix the Projects Link

Your styled home page now has a Projects link, but its destination is still missing. The browser proved that a relative link only works when its target file exists beside the page that uses it.

This step creates projects.html beside index.html. It also reuses styles.css so both pages feel like one portfolio.

In this step, get ready to:
  • Create the Projects page with shared navigation.
  • Add three visible project cards.
  • Style the cards and test the complete navigation loop.
Create the Projects page

A relative HTML link looks for its target from the current file's location. Placing projects.html beside index.html gives the existing Projects link a real destination.

  • Switch back to Visual Studio Code from the previous step.
  • Select New File... in the Explorer view.
  • Enter projects.html as the file name.
  • Press Enter to create the file.
  • Build the Projects page shell by adding this code to projects.html:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Projects | Your Name</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <header class="site-header">
    <nav class="nav shell" aria-label="Main navigation">
      <a class="brand" href="index.html">Your Name</a>
      <div class="nav-links">
        <a href="index.html">Home</a>
        <a href="projects.html" aria-current="page">Projects</a>
      </div>
    </nav>
  </header>
  <main class="section shell">
    <div class="section-heading">
      <p class="eyebrow">Selected work</p>
      <h1>My Projects</h1>
      <p class="lede">These sample cards can become real projects as I continue learning.</p>
    </div>
  </main>
  <footer class="footer shell"><p><a href="index.html">Return to the home page</a></p></footer>
</body>
</html>

How does the page shell work?

  • The stylesheet link loads the same visual rules used by the home page.
  • The shared navigation points Home to index.html.
  • The aria-current="page" attribute identifies Projects as the current page.
  • The section-heading block introduces the work shown below it.
  • Save projects.html.
  • Return to Microsoft Edge from the previous step.

Before you select Projects, do you expect the browser to find its target now?

  • Select the Projects link on the home page.

You'll see a real page headed My Projects. The missing-page result has disappeared because projects.html now exists in the expected location.

Projects Page Still Missing?

  • Check that the file is named projects.html with the same spelling used by the link.
  • Confirm that projects.html appears beside index.html in the Explorer view.
  • Still stuck? Help me fix my local Projects link.
Add the project cards

The link now works, so the next visible gap is the empty project area. Three article elements give each project its own title, description, and skill tags.

  • Return to projects.html in Visual Studio Code.
  • Find the closing </div> for the section-heading block.
  • Insert the project card grid after that closing tag and before </main> by adding this code:
    <div class="card-grid">
      <article class="project-card"><h2>Responsive Profile</h2><p>A compact profile page that stays readable on desktop and mobile screens.</p><ul class="tag-list"><li>HTML</li><li>CSS</li></ul></article>
      <article class="project-card"><h2>Study Dashboard</h2><p>A dashboard concept for organizing learning goals, progress, and upcoming tasks.</p><ul class="tag-list"><li>Layout</li><li>Accessibility</li></ul></article>
      <article class="project-card"><h2>Community Landing Page</h2><p>A welcoming page that explains a community, its benefits, and how to join.</p><ul class="tag-list"><li>Content</li><li>Design</li></ul></article>
    </div>

What do the cards contain?

  • The card-grid container keeps the three projects together as one layout.
  • Each project-card article groups one project title with its description.
  • Each tag-list identifies the skills represented by that project.
  • Save projects.html.
  • Return to the Projects page in Microsoft Edge.
  • Refresh the page.

You'll see three projects named Responsive Profile, Study Dashboard, and Community Landing Page. Their text is visible before the new card styles arrive.

Don't See All Three Projects?

  • Confirm that the card-grid block sits inside <main>.
  • Check that every project begins with <article class="project-card">.
  • Still stuck? Help me find the missing project cards.

The Projects page structure is complete. Use this comparison if you want to check the whole file before styling it.

✔️ Awesome, I've got everything!

Your projects.html file now contains shared navigation and three project cards.

ⓧ I'd like to double check the full code

  • Compare your complete projects.html file with this reference:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Projects | Your Name</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <header class="site-header">
    <nav class="nav shell" aria-label="Main navigation">
      <a class="brand" href="index.html">Your Name</a>
      <div class="nav-links">
        <a href="index.html">Home</a>
        <a href="projects.html" aria-current="page">Projects</a>
      </div>
    </nav>
  </header>
  <main class="section shell">
    <div class="section-heading">
      <p class="eyebrow">Selected work</p>
      <h1>My Projects</h1>
      <p class="lede">These sample cards can become real projects as I continue learning.</p>
    </div>
    <div class="card-grid">
      <article class="project-card"><h2>Responsive Profile</h2><p>A compact profile page that stays readable on desktop and mobile screens.</p><ul class="tag-list"><li>HTML</li><li>CSS</li></ul></article>
      <article class="project-card"><h2>Study Dashboard</h2><p>A dashboard concept for organizing learning goals, progress, and upcoming tasks.</p><ul class="tag-list"><li>Layout</li><li>Accessibility</li></ul></article>
      <article class="project-card"><h2>Community Landing Page</h2><p>A welcoming page that explains a community, its benefits, and how to join.</p><ul class="tag-list"><li>Content</li><li>Design</li></ul></article>
    </div>
  </main>
  <footer class="footer shell"><p><a href="index.html">Return to the home page</a></p></footer>
</body>
</html>
Style the project cards

The browser can render the cards now, but their class names need matching CSS rules. The shared surface styles create card boundaries before the grid arranges those cards into columns.

  • Switch back to styles.css in Visual Studio Code.
  • Find the section that starts with the .panel selector.
  • Replace everything from that selector through the closing brace of .section with this code:
.panel,
.project-card,
.contact {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 1rem;
  box-shadow: var(--shadow);
}

.panel {
  padding: 2rem;
}

.skills-list {
  margin: 0;
  padding-left: 1.2rem;
}

.section {
  padding-block: 4rem;
}

Why share the surface styles?

Adding .project-card to the shared selector gives every card the same background, border, rounded corners, and shadow as the existing panels. Shared rules keep repeated components visually consistent.

  • Save styles.css.
  • Return to the Projects page in Microsoft Edge.
  • Refresh the page.

You'll see each project gain a white surface with a border, rounded corners, and a shadow. The cards still follow the normal vertical page flow.

Cards Still Look Like Plain Text?

  • Confirm that .project-card appears between .panel, and .contact.
  • Check that projects.html still links to styles.css in its <head>.
  • Still stuck? Help me connect the card surface styles.

The card surfaces are visible. A grid now controls their width and spacing as one coordinated layout.

  • Return to styles.css.
  • Find the closing brace of the .section rule.
  • Add the heading and card layout rules below that brace by pasting this code:
.section-heading {
  margin-bottom: 2rem;
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}

.project-card {
  padding: 1.5rem;
}

.project-card p {
  color: var(--muted);
}

How does the card layout work?

  • The section-heading margin separates the introduction from the cards.
  • The card-grid rule creates three equal columns with a consistent gap.
  • The project-card padding creates breathing room inside each surface.
  • The paragraph color lowers the visual emphasis of each description.
  • Save styles.css.
  • Return to the Projects page in Microsoft Edge.
  • Refresh the page.

You'll see the three cards form equal columns with space between them. Each description now uses the muted text color.

Cards Still Stacked Vertically?

  • Check that the three articles remain inside <div class="card-grid">.
  • Confirm that the selector is written as .card-grid in styles.css.
  • Still stuck? Help me fix the project card grid.

The main card layout is complete. The final style turns each plain skill list into a row of compact labels.

  • Return to styles.css.
  • Find the closing brace of the .project-card p rule.
  • Add the tag styles below that brace by pasting this code:
.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 1.25rem 0 0;
  padding: 0;
  list-style: none;
}

.tag-list li {
  padding: 0.3rem 0.65rem;
  color: var(--accent-dark);
  background: #ece9ff;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 700;
}

What do the tag styles add?

  • The flexible row lets tags wrap when a card has limited horizontal space.
  • Removing the list style hides the default bullet markers.
  • The background, padding, and rounded corners turn each skill into a compact label.
  • Save styles.css.
  • Return to the Projects page in Microsoft Edge.
  • Refresh the page.

You'll see each skill inside a pale purple rounded label. The labels sit in flexible rows beneath their project descriptions.

Tags Still Show Bullet Points?

  • Confirm that each skills list uses class="tag-list" in projects.html.
  • Check that list-style: none remains inside the .tag-list rule.
  • Still stuck? Help me style the project tags.

The stylesheet now contains every rule needed for the two-page portfolio. Use the comparison below if you want to check the complete file.

✔️ Awesome, I've got everything!

Your styles.css file now styles the heading, card grid, project cards, and tags.

ⓧ I'd like to double check the full code

  • Compare your complete styles.css file with this reference:
:root {
  --background: #f7f8fc;
  --surface: #ffffff;
  --text: #172033;
  --muted: #5d6678;
  --accent: #5b45d6;
  --accent-dark: #4332ad;
  --border: #dfe3ec;
  --shadow: 0 16px 40px rgba(23, 32, 51, 0.1);
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  color: var(--text);
  background: var(--background);
  font-family: sans-serif;
  line-height: 1.6;
}

a {
  color: inherit;
}

.shell {
  width: min(1080px, calc(100% - 2rem));
  margin-inline: auto;
}

.site-header {
  background: rgba(255, 255, 255, 0.94);
  border-bottom: 1px solid var(--border);
}

.nav {
  min-height: 72px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.brand {
  color: var(--accent);
  font-size: 1.1rem;
  font-weight: 800;
  text-decoration: none;
}

.nav-links {
  display: flex;
  gap: 1rem;
}

.nav-links a {
  color: var(--muted);
  font-weight: 700;
  text-decoration: none;
}

.nav-links a:hover,
.nav-links a[aria-current="page"] {
  color: var(--accent);
}

.hero {
  min-height: 70vh;
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  align-items: center;
  gap: 3rem;
  padding-block: 5rem;
}

.eyebrow {
  margin: 0 0 0.5rem;
  color: var(--accent);
  font-size: 0.85rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

h1,
h2,
p {
  margin-top: 0;
}

h1 {
  margin-bottom: 1rem;
  font-size: clamp(2.5rem, 7vw, 5rem);
  line-height: 1;
}

.lede {
  max-width: 62ch;
  color: var(--muted);
  font-size: 1.15rem;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.75rem;
}

.button {
  display: inline-block;
  padding: 0.8rem 1.1rem;
  color: #ffffff;
  background: var(--accent);
  border: 2px solid var(--accent);
  border-radius: 0.65rem;
  font-weight: 800;
  text-decoration: none;
}

.button:hover {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
}

.button.secondary {
  color: var(--accent);
  background: transparent;
}

.panel,
.project-card,
.contact {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 1rem;
  box-shadow: var(--shadow);
}

.panel {
  padding: 2rem;
}

.skills-list {
  margin: 0;
  padding-left: 1.2rem;
}

.section {
  padding-block: 4rem;
}

.section-heading {
  margin-bottom: 2rem;
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}

.project-card {
  padding: 1.5rem;
}

.project-card p {
  color: var(--muted);
}

.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 1.25rem 0 0;
  padding: 0;
  list-style: none;
}

.tag-list li {
  padding: 0.3rem 0.65rem;
  color: var(--accent-dark);
  background: #ece9ff;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 700;
}

.contact {
  padding: 2rem;
}

.footer {
  padding-block: 2rem;
  color: var(--muted);
  border-top: 1px solid var(--border);
}

Before you test the complete loop, do you expect both pages to find each other through their relative links?

  • Return to the Projects page in Microsoft Edge.
  • Select the Home navigation link.
  • Select the Projects navigation link.
  • Select the Home navigation link again.

You'll move from the home page to three styled project cards. You'll then return to the home page successfully.

That missing link is now a working round trip between two local pages. Next, you'll replace the sample content with your own details and make the layout adapt to a narrow window.

Personalize and Test the Design

Your Home and Projects pages now form a working two-page portfolio. The navigation proves that each relative link has a matching file.

Sample content and desktop-only styling leave the site unfinished. Your details make the portfolio relevant. A responsive layout keeps it usable in a narrow browser window.

In this step, get ready to:
  • Personalize the content across both pages.
  • Add responsive layout rules and visible keyboard focus styles.
  • Test every local link at wide and narrow browser widths.
Personalize your portfolio content

Visitors need specific details that show who you are. You can replace the sample text without changing the surrounding elements or links.

Keep the page structure intact

In HTML, the editable text sits between opening and closing tags. The classes around that text connect each element to its existing styles.

The values inside href attributes control navigation. Keeping those values intact protects your working links.

  • In Visual Studio Code, switch back to the index.html tab from earlier.
  • Replace every occurrence of Your Name with your own name.
  • Replace the sample introduction with one sentence about what you build or learn.
  • Replace the four skill items with skills you want visitors to notice.
  • Replace the contact paragraph with your preferred professional contact details.
  • Save index.html.
  • Return to the Home page in Microsoft Edge.
  • Refresh the page.

Your home page now presents your own name, introduction, skills, and contact details. The browser tab also uses your name.

Plan each project card

Each card needs a title that identifies the work. Its description should explain what the project helps someone do.

Keep each description to one sentence. A short description is easier to scan across three cards.

  • Switch back to the projects.html tab from earlier.
  • Replace every occurrence of Your Name with your own name.
  • Replace the three sample project titles with projects you have completed or plan to build.
  • Replace each sample description with one sentence about that project.
  • Save projects.html.
  • Return to the Home page in Microsoft Edge.
  • Select Projects in the navigation.

Good progress. Your Projects page now shows work that you can describe to a visitor.

Personal text not appearing?

  • Confirm that you saved the file containing your latest edits.
  • Confirm that Microsoft Edge is displaying the index.html file from your free-portfolio folder.
  • Still stuck? Help me find why my personalized HTML text is not appearing in Microsoft Edge.
Add responsive and focus styles

Keyboard focus shows which link is ready to activate. A media query changes the layout once the browser becomes narrower than 700px.

  • Switch back to styles.css from earlier.
  • Add the keyboard focus rule at the end of the file by pasting this code:
:focus-visible {
  outline: 3px solid #ff9f1c;
  outline-offset: 4px;
}

What does this focus rule do?

  • The :focus-visible selector targets the element currently reached through keyboard navigation.
  • The orange outline makes the active link or button easy to locate.
  • The outline offset leaves space between the element and its focus indicator.
  • Save styles.css.
  • Return to the Home page in Microsoft Edge.
  • Press the Tab key.

You should see a bright orange outline around the first focusable link. Each additional press moves that outline to the next link or button.

Focus outline missing?

  • Confirm that the selector begins with a colon in :focus-visible.
  • Confirm that the closing brace appears after outline-offset.
  • Still stuck? Help me troubleshoot my missing focus-visible outline.
  • Add the responsive media query below the focus rule by pasting this code:
@media (max-width: 700px) {
  .nav,
  .hero {
    align-items: flex-start;
  }

  .nav {
    flex-direction: column;
    padding-block: 1rem;
  }

  .hero,
  .card-grid {
    grid-template-columns: 1fr;
  }

  .hero {
    min-height: auto;
    gap: 1.5rem;
    padding-block: 3rem;
  }

  h1 {
    font-size: 2.6rem;
  }
}

What does this media query do?

  • The max-width: 700px condition activates these rules in a narrow browser window.
  • The navigation switches to a vertical layout.
  • The hero and project card grid switch to one column.
  • The smaller heading and tighter hero spacing keep the content readable.
  • Save styles.css.
  • Return to Microsoft Edge.
  • Make the browser window narrower than 700px.

On the Home page, the navigation should become vertical. The introduction and skills panel should stack into one column.

Layout still using columns?

  • Confirm that the media query appears after the earlier layout rules in styles.css.
  • Confirm that the browser window is narrower than 700px.
  • Still stuck? Help me troubleshoot my responsive portfolio layout.

✔️ I've got everything

Your three files are saved. Your personalized text now sits inside the complete portfolio structure.

ⓧ I'd like to double check the full code

  • Compare the structure of index.html with this reference. Keep your personalized wording where the reference uses sample text.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Your Name | Portfolio</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <header class="site-header">
    <nav class="nav shell" aria-label="Main navigation">
      <a class="brand" href="index.html">Your Name</a>
      <div class="nav-links">
        <a href="index.html" aria-current="page">Home</a>
        <a href="projects.html">Projects</a>
      </div>
    </nav>
  </header>

  <main>
    <section class="hero shell">
      <div>
        <p class="eyebrow">Hello, I am</p>
        <h1>Your Name</h1>
        <p class="lede">I am learning to build clear, useful websites and turn ideas into projects people can see and use.</p>
        <div class="actions">
          <a class="button" href="projects.html">View my projects</a>
          <a class="button secondary" href="#contact">Contact me</a>
        </div>
      </div>

      <aside class="panel" aria-labelledby="skills-title">
        <h2 id="skills-title">Skills I am building</h2>
        <ul class="skills-list">
          <li>HTML structure</li>
          <li>CSS layouts</li>
          <li>Responsive design</li>
          <li>Static-site deployment</li>
        </ul>
      </aside>
    </section>

    <section class="section shell" id="contact">
      <div class="contact">
        <p class="eyebrow">Let us connect</p>
        <h2>Contact</h2>
        <p>Replace this text with your preferred email address or professional contact details before sharing the site.</p>
      </div>
    </section>
  </main>

  <footer class="footer shell">
    <p>Built by Your Name with HTML and CSS.</p>
  </footer>
</body>
</html>
  • Compare the structure of projects.html with this reference. Keep your personalized project content.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Projects | Your Name</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <header class="site-header">
    <nav class="nav shell" aria-label="Main navigation">
      <a class="brand" href="index.html">Your Name</a>
      <div class="nav-links">
        <a href="index.html">Home</a>
        <a href="projects.html" aria-current="page">Projects</a>
      </div>
    </nav>
  </header>

  <main class="section shell">
    <div class="section-heading">
      <p class="eyebrow">Selected work</p>
      <h1>My Projects</h1>
      <p class="lede">These sample cards can become real projects as I continue learning.</p>
    </div>

    <div class="card-grid">
      <article class="project-card">
        <h2>Responsive Profile</h2>
        <p>A compact profile page that stays readable on desktop and mobile screens.</p>
        <ul class="tag-list">
          <li>HTML</li>
          <li>CSS</li>
        </ul>
      </article>

      <article class="project-card">
        <h2>Study Dashboard</h2>
        <p>A dashboard concept for organizing learning goals, progress, and upcoming tasks.</p>
        <ul class="tag-list">
          <li>Layout</li>
          <li>Accessibility</li>
        </ul>
      </article>

      <article class="project-card">
        <h2>Community Landing Page</h2>
        <p>A welcoming page that explains a community, its benefits, and how to join.</p>
        <ul class="tag-list">
          <li>Content</li>
          <li>Design</li>
        </ul>
      </article>
    </div>
  </main>

  <footer class="footer shell">
    <p><a href="index.html">Return to the home page</a></p>
  </footer>
</body>
</html>
  • Compare styles.css with this complete reference.
:root {
  --background: #f7f8fc;
  --surface: #ffffff;
  --text: #172033;
  --muted: #5d6678;
  --accent: #5b45d6;
  --accent-dark: #4332ad;
  --border: #dfe3ec;
  --shadow: 0 16px 40px rgba(23, 32, 51, 0.1);
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  color: var(--text);
  background: var(--background);
  font-family: sans-serif;
  line-height: 1.6;
}

a {
  color: inherit;
}

.shell {
  width: min(1080px, calc(100% - 2rem));
  margin-inline: auto;
}

.site-header {
  background: rgba(255, 255, 255, 0.94);
  border-bottom: 1px solid var(--border);
}

.nav {
  min-height: 72px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.brand {
  color: var(--accent);
  font-size: 1.1rem;
  font-weight: 800;
  text-decoration: none;
}

.nav-links {
  display: flex;
  gap: 1rem;
}

.nav-links a {
  color: var(--muted);
  font-weight: 700;
  text-decoration: none;
}

.nav-links a:hover,
.nav-links a[aria-current="page"] {
  color: var(--accent);
}

.hero {
  min-height: 70vh;
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  align-items: center;
  gap: 3rem;
  padding-block: 5rem;
}

.eyebrow {
  margin: 0 0 0.5rem;
  color: var(--accent);
  font-size: 0.85rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

h1,
h2,
p {
  margin-top: 0;
}

h1 {
  margin-bottom: 1rem;
  font-size: clamp(2.5rem, 7vw, 5rem);
  line-height: 1;
}

.lede {
  max-width: 62ch;
  color: var(--muted);
  font-size: 1.15rem;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.75rem;
}

.button {
  display: inline-block;
  padding: 0.8rem 1.1rem;
  color: #ffffff;
  background: var(--accent);
  border: 2px solid var(--accent);
  border-radius: 0.65rem;
  font-weight: 800;
  text-decoration: none;
}

.button:hover {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
}

.button.secondary {
  color: var(--accent);
  background: transparent;
}

.panel,
.project-card,
.contact {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 1rem;
  box-shadow: var(--shadow);
}

.panel {
  padding: 2rem;
}

.skills-list {
  margin: 0;
  padding-left: 1.2rem;
}

.section {
  padding-block: 4rem;
}

.section-heading {
  margin-bottom: 2rem;
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}

.project-card {
  padding: 1.5rem;
}

.project-card p {
  color: var(--muted);
}

.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 1.25rem 0 0;
  padding: 0;
  list-style: none;
}

.tag-list li {
  padding: 0.3rem 0.65rem;
  color: var(--accent-dark);
  background: #ece9ff;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 700;
}

.contact {
  padding: 2rem;
}

.footer {
  padding-block: 2rem;
  color: var(--muted);
  border-top: 1px solid var(--border);
}

:focus-visible {
  outline: 3px solid #ff9f1c;
  outline-offset: 4px;
}

@media (max-width: 700px) {
  .nav,
  .hero {
    align-items: flex-start;
  }

  .nav {
    flex-direction: column;
    padding-block: 1rem;
  }

  .hero,
  .card-grid {
    grid-template-columns: 1fr;
  }

  .hero {
    min-height: auto;
    gap: 1.5rem;
    padding-block: 3rem;
  }

  h1 {
    font-size: 2.6rem;
  }
}
Test the complete local site

A final test checks the page content, relative links, responsive rules, and keyboard order together. This catches problems before the folder becomes a public website.

Before you test, which parts of the layout do you expect to change as the browser crosses 700px?

  • Return to the Home page in Microsoft Edge.
  • Widen the browser window beyond 700px.

You should see your introduction beside the skills panel. Your own name should appear in the page and browser tab.

  • Select Projects in the navigation.

You should see your three personalized project cards arranged in three columns. Each card should show its updated title and description.

  • Make the browser window narrower than 700px.

The navigation should become vertical. The three project cards should stack into one column.

  • Select Home in the navigation.

The Home page should open successfully. Its introduction and skills panel should now stack into one column.

  • Select Contact me.

The browser should move to your contact section on the same page.

  • Select View my projects.
  • Select Home to return.
  • Press the Tab key repeatedly.

The two buttons should open their intended destinations. The orange focus outline should move through the navigation links and buttons in page order.

Follow the focus indicator

Each press of Tab moves focus forward. The outlined label tells you which destination opens when you press Enter.

A predictable sequence lets someone use the site without a mouse.

Your personalized two-page portfolio now works at wide and narrow widths. Next, you will publish the tested folder with Cloudflare Pages.

Publish with Cloudflare Pages

Your personalized portfolio already works across two local pages in Microsoft Edge. It adapts to a narrow browser window.

A local website remains on your computer. In this step, Cloudflare Pages publishes your complete free-portfolio folder with Direct Upload.

In this step, get ready to:
  • Access the Cloudflare dashboard with a Free plan account.
  • Deploy the complete portfolio folder through Direct Upload.
  • Verify the live portfolio at its public address.
Create your free Cloudflare account

Cloudflare Pages has a Free plan priced at $0 forever. A credit card is not required to start.

The account setup keeps your billing details untouched. You only need access to the Cloudflare dashboard.

  • Switch back to Microsoft Edge from earlier.
  • Visit the official Cloudflare Pages product page.
  • Check whether the Cloudflare dashboard is available through the account options on the page.

✔️ The dashboard is open

  • Keep the Cloudflare dashboard open in Microsoft Edge.

ⓧ I need to sign in

  • Use the Cloudflare sign-in flow from the product page.
  • Enter your existing account details.
  • Continue until the Cloudflare dashboard loads.

ⓧ I need an account

  • Use the Cloudflare account creation flow from the product page.
  • Complete the account form with your own details.
  • Choose the Free plan if Cloudflare presents a plan choice.
  • Finish the account setup without adding billing details.
  • Continue until the Cloudflare dashboard loads.

You should now see the Cloudflare dashboard without having entered a credit card. That's the account hurdle cleared: your dashboard is ready for the deployment.

Dashboard not opening?

  • Check that you completed every account confirmation requested by Cloudflare.
  • Return to the Cloudflare Pages product page if the account flow closed before reaching the dashboard.
  • Still stuck? Help me access my Cloudflare dashboard.
Deploy the complete portfolio folder

Direct Upload accepts prebuilt assets from your local computer. The dashboard accepts a ZIP file or a single folder of assets.

Why Direct Upload?

Direct Upload publishes the files you already tested locally. It keeps this first deployment focused on your website.

This workflow does not require a public repository or Git. Your complete folder becomes the deployment source.

  • Select Workers & Pages in the Cloudflare dashboard.
  • Select Create application.
  • Select Get started.
  • Select Drag and drop your files.
  • Enter my-free-portfolio as the project name.

The upload area now expects the static files that make up your portfolio. Your free-portfolio folder contains the required top-level index.html file.

  • Switch back to Visual Studio Code from earlier.
  • Right-click the free-portfolio folder in the Explorer sidebar.
  • Choose the option that reveals the folder in File Explorer.
  • Switch back to the Cloudflare upload screen.
  • Drag the free-portfolio folder from File Explorer into the upload area.
  • Confirm the upload contains the complete free-portfolio folder.
  • Select Deploy site.
  • Wait for Cloudflare to finish the deployment.

Cloudflare should show your deployed project with an assigned address in the <PROJECT_NAME>.pages.dev format. That address is the public entrance to your portfolio.

That's the local-to-live leap complete: your portfolio now has a public address.

Upload not completing?

  • Check that you dragged the free-portfolio folder itself into the upload area.
  • Confirm that index.html sits at the top level of the uploaded folder.
  • Still stuck? Help me troubleshoot my Direct Upload deployment.
Test the public site

A successful deployment should preserve the same links and responsive layout you tested locally. The public address lets you check the files as a visitor sees them.

Before you open the public address, do you expect both pages to behave exactly like their local versions?

  • Select the assigned <PROJECT_NAME>.pages.dev address on the deployment screen.

Microsoft Edge should display your personalized name in the styled hero. The page should use the same colors as your local version.

  • Select Projects in the live navigation.
  • Confirm that three personalized project cards appear.
  • Select Home in the live navigation.
  • Select Contact me on the live home page.
  • Confirm that the page jumps to your personalized contact section.

The complete navigation loop now works from the public site. Your relative links survived the move from local files to Cloudflare Pages.

  • Select Projects again.
  • Narrow the Microsoft Edge window until the responsive layout activates.
  • Confirm that the three project cards stack into one column.
  • Select Home.
  • Confirm that the navigation changes to a vertical layout.
  • Confirm that the hero content stacks into one column.

Your public portfolio now matches the tested local site. Anyone with its Cloudflare Pages address can move between the pages and read it at narrow widths.

Seeing a 404 or missing styles?

  • Check that index.html sits at the top level of the uploaded free-portfolio folder.
  • Check that styles.css sits beside index.html.
  • Check that projects.html sits beside index.html.
  • Still stuck? Help me fix my live portfolio deployment.

Secret mission

Add an About Page

Build an About page with the classes you already use. Connect all three navigation bars. Publish the updated folder to the same public address.

Clean Up Your Resources

Clean Up Your Resources

Your portfolio uses the Cloudflare Pages Free plan, so keeping it published has no ongoing project cost. Choose whether to keep the site available, pause your updates, or delete the local and hosted copies.

Resources you used:

  • The local free-portfolio folder containing index.html, projects.html, about.html, and styles.css.
  • The my-free-portfolio Cloudflare Pages project on the Free plan.
  • The public my-free-portfolio.pages.dev address served by that project.

Keep everything running

No action needed. Choose this if you want to continue sharing your portfolio or improving it later.

  • Keep the free-portfolio folder on your computer for future edits.
  • Leave the my-free-portfolio Pages project published.
  • Continue sharing my-free-portfolio.pages.dev with visitors.

Pause - I'll come back to this later

Stop editing the local files for now. Your current static site remains published on the Free plan.

  • Keep the free-portfolio folder unchanged on your computer.
  • Avoid creating another Direct Upload deployment until you are ready to continue.
  • Leave my-free-portfolio.pages.dev published so the existing portfolio remains available.

Delete - I don't want to use this again

Choose full deletion only when you no longer want the hosted site or its editable files. The hosted site disappears when you delete the Pages project.

  • Return to the Cloudflare dashboard from earlier.
  • Select Workers & Pages.
  • Select the my-free-portfolio Pages project.
  • Select Settings.
  • Select Delete project.
  • Return to Workers & Pages.

You should no longer see my-free-portfolio in the project list. That confirms the Pages project and its public address are gone.

That is the hosted cleanup done. The next action removes your only local editable copy.

  • Use File Explorer to locate the existing free-portfolio folder.
  • Delete the free-portfolio folder.
  • Search your computer for free-portfolio.

You should find no remaining free-portfolio folder. Your local and hosted project resources are now removed.

Nice Work!

Nice Work!

You made it! Your responsive three-page portfolio is live on Cloudflare Pages. Visitors can follow the complete navigation loop at my-free-portfolio.pages.dev.

You've learned how to:

  • Build a responsive portfolio with HTML and CSS. Keep it readable as the browser window narrows.
  • Diagnose a broken relative link when projects.html is missing. Complete a reliable navigation loop across index.html and projects.html.
  • Check responsive behavior in Microsoft Edge. Confirm a visible keyboard focus outline. Publish the tested folder through Cloudflare Pages Direct Upload at a public pages.dev address.
  • Complete the Secret Mission by adding about.html. Keep the shared navigation consistent across all three pages. Redeploy the updated folder to the same public address.

Ready to quiz yourself?