Build a Portfolio Website on Amazon S3
Build a responsive portfolio and resume with Amazon S3 static hosting.
Introduction
30 Second Summary
Most visitors decide whether to keep reading a portfolio within moments. A scattered mix of documents makes your strongest work easy to miss.
In this project, you will create a one-page portfolio and resume with HTML and CSS. The finished page runs locally before going live through a public Amazon S3 website endpoint.
What You'll Build
You open one link to show a polished portfolio across screen sizes or as a clean printed resume.
By the end of this project, you'll have:
- A responsive portfolio that rearranges its content into a readable single-column layout on a narrow screen.
- A print-ready resume whose preview hides page controls for a clean document.
- A public S3 website that moves from 403 (Access Denied) to a styled portfolio when you grant public read access.
- Secret Mission: A branded 404.html page that guides visitors back to your portfolio when a path is missing.
Are there any prerequisites?
This project assumes an AWS account with permission to create a public S3 bucket.
The local setup uses Visual Studio Code on Windows with a Microsoft Edge check in Step 1.
Before We Start
Before any hands-on work begins, lock in who your portfolio needs to reach. Decide which skill or project visitors should remember after their first 30 seconds.
Prepare Your Local Workspace
A small local workspace keeps your file names predictable. It also proves that Microsoft Edge can display your first HTML page.
Visual Studio Code gives you one place to create the project files. The AWS Management Console confirms that you can reach Amazon S3 before you build anything larger.
In this step, get ready to:
- Make Microsoft Edge available on Windows.
- Create a local test page inside Documents/portfolio-s3.
- Confirm access to the Amazon S3 General purpose buckets page.
Check Microsoft Edge
Microsoft Edge gives you a consistent place to test the portfolio locally. You can install it from Microsoft's official download page if Windows cannot find it.
- Press the Windows key to open search.
- Type Microsoft Edge into search.
The search results show whether Microsoft Edge is already available.
✔️ Microsoft Edge is available
- Select Microsoft Edge from the search results.
Microsoft Edge opens in a new browser window.
ⓧ Microsoft Edge is unavailable
- Visit the official Microsoft Edge download page in your current browser.
- Choose the Windows download offered on that page.
- Open the downloaded installer.
- Approve the installer permission request if Windows shows one.
- Complete the installation instructions shown on screen.
- Press the Windows key to open search.
- Type Microsoft Edge into search.
- Press Enter to open Microsoft Edge.
Microsoft Edge still unavailable?
Restart Windows if the completed installation does not appear in search.
Help me troubleshoot a completed Microsoft Edge installation that does not appear in Windows search.
Your open Microsoft Edge window confirms that the browser is ready for the local page.
Create the local test page
The portfolio-s3 folder keeps every website file in one known location. Your first page contains a single heading that makes local testing obvious.
- Press the Windows key to open search.
- Type File Explorer into search.
The search results show File Explorer.
- Press Enter to open File Explorer.
- Select Documents in the left sidebar.
- Select the new-folder control in the File Explorer toolbar.
- Type portfolio-s3 as the folder name.
- Press Enter to create the folder.
Your Documents folder now contains portfolio-s3.
- Press the Windows key to open search.
- Type Visual Studio Code into search.
The search results show Visual Studio Code.
- Press Enter to open Visual Studio Code.
- Drag the portfolio-s3 folder from File Explorer onto the Visual Studio Code window.
- Confirm that you trust the folder if Visual Studio Code asks.
The Visual Studio Code Explorer sidebar now shows portfolio-s3 as the open folder.
- Select portfolio-s3 in the Explorer sidebar.
- Select the new-file control in the Explorer toolbar.
- Type index.html as the file name.
- Press Enter to create the file.
The Explorer sidebar now lists index.html inside portfolio-s3.
- Fill index.html with the temporary page by pasting this code:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Portfolio Setup</title>
</head>
<body>
<h1>Portfolio setup works</h1>
</body>
</html>
What does this page do?
- The document declaration tells the browser to use modern HTML.
- The page metadata gives Microsoft Edge the character set plus the mobile viewport settings.
- The <title> content names the browser tab.
- The <h1> content creates the visible setup message.
- Save index.html by pressing Ctrl+S.
- Return to the File Explorer window from earlier.
- Drag index.html from Documents/portfolio-s3 onto the Microsoft Edge window.
Microsoft Edge displays Portfolio setup works as a large heading.
Don't see the setup message?
- Confirm that the file is named index.html without an extra file extension.
- Save the file again with Ctrl+S.
- Drag the saved file from Documents/portfolio-s3 onto Microsoft Edge again.
Help me troubleshoot a local HTML file that does not show Portfolio setup works in Microsoft Edge.
✔️ Awesome, I've got everything!
Your saved index.html file displays the setup heading in Microsoft Edge.
ⓧ I'd like to double check the full code
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Portfolio Setup</title>
</head>
<body>
<h1>Portfolio setup works</h1>
</body>
</html>
Confirm Amazon S3 access
Your AWS credentials stay inside the AWS sign-in page. This project never asks you to copy or share them.
- Select the new-tab control at the top of Microsoft Edge.
- Enter https://console.aws.amazon.com/s3/ in the address bar.
- Complete the sign-in flow for your AWS account.
Microsoft Edge opens the Amazon S3 console on the General purpose buckets page.
- Leave the page open without selecting Create bucket.
Why stop before creating a bucket?
Amazon S3 stores website files as objects inside a bucket. Bucket creation comes later when your complete portfolio is ready to upload.
Can't reach General purpose buckets?
Confirm that you signed in with the AWS account intended for this project.
An access restriction requires help from the administrator who manages your AWS permissions.
Help me troubleshoot access to the Amazon S3 General purpose buckets page.
Before the final check, take a moment to predict which two screens will confirm success.
- Switch back to the Microsoft Edge tab showing the local file.
You should see Portfolio setup works on the page.
- Switch to the Microsoft Edge tab showing the Amazon S3 console.
You should see the General purpose buckets page. No new S3 bucket appears in the list.
Your local editor, browser, project file, plus AWS access are ready for the portfolio build.
- Stop here until your workspace check is confirmed.
Your verified workspace is ready. After confirmation, you will replace the setup page with the complete portfolio structure.
Build Your Portfolio Structure
Your workspace now proves that Microsoft Edge can display index.html from your Documents/portfolio-s3 folder. The temporary setup page is ready to become your portfolio.
A semantic HTML structure makes your content readable before any styling exists. This gives you an early working version where every section can be checked in the browser.
In this step, get ready to:
- Replace the temporary page with the complete portfolio structure.
- Personalize every visible placeholder with safe public information.
- Test the in-page navigation in Microsoft Edge.
Replace the temporary page
The document foundation supplies browser metadata plus the main navigation. It also references styles.css so the next step can add visual design without changing the page structure.
- Return to the index.html tab in Visual Studio Code.
- Press Ctrl+A to select the temporary page.
- Replace the selection by pasting this document foundation:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Portfolio and resume for Your Name">
<title>Your Name | Portfolio and Resume</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="hero" id="home">
<nav class="nav container" aria-label="Primary navigation">
<a class="logo" href="#home">YN</a>
<div class="nav-links">
<a href="#about">About</a>
<a href="#projects">Projects</a>
<a href="#resume">Resume</a>
<a href="#contact">Contact</a>
</div>
</nav>
</header>
</body>
</html>
What Does This Code Do?
- The head describes the page to the browser.
- The stylesheet link prepares the document for the design you add later.
- The navigation links point to section IDs that you add below.
- Save index.html by pressing Ctrl+S.
- Switch back to the local page in Microsoft Edge.
- Refresh the page.
You should see the links About, Projects, Resume, plus Contact near the top of the page.
Still See the Setup Heading?
Confirm that you saved index.html inside Documents/portfolio-s3. Refresh the existing local file tab after saving.
Check that the browser address points to the copy inside your portfolio-s3 folder.
Help me refresh the correct local HTML file.
The hero introduces you before a visitor reaches the detailed sections. Its buttons reuse the same section IDs as the navigation.
- Find the closing </nav> tag in index.html.
- Place your cursor below the closing </nav> tag.
- Add the hero content by pasting this code:
<div class="hero-content container">
<p class="eyebrow">Hello, I am</p>
<h1>Your Name</h1>
<p class="tagline">Aspiring cloud professional building reliable, useful experiences on AWS.</p>
<div class="hero-actions">
<a class="button primary" href="#projects">Explore my work</a>
<a class="button secondary" href="#resume">Read my resume</a>
</div>
</div>
How the Hero Works
- The main heading tells visitors whose portfolio they are viewing.
- The tagline summarizes your professional direction.
- The two buttons move visitors to your work or resume.
- Save index.html.
- Switch back to Microsoft Edge.
- Refresh the local page.
You should see Hello, I am above the large Your Name heading. You should also see two links below the tagline.
Hero Missing From the Page?
Make sure the hero content sits between </nav> and </header>. Content outside the header can appear in an unexpected position.
Help me place the hero inside the header.
The main area groups your introduction plus evidence of your skills. Each section receives an ID so the links at the top have a precise destination.
- Find the closing </header> tag.
- Place your cursor below the closing </header> tag.
- Add the About area by pasting this code:
<main>
<section class="section container" id="about">
<div class="section-heading">
<p class="eyebrow">About</p>
<h2>A quick introduction</h2>
</div>
<div class="about-grid">
<div>
<p>I am developing practical cloud and web skills through hands-on projects. I enjoy turning ideas into clear, dependable experiences that people can use.</p>
<p>My current focus is AWS, static web hosting, and building a strong foundation in front-end development.</p>
</div>
<div class="skills-card">
<h3>Core skills</h3>
<ul class="skills-list">
<li>Amazon S3</li>
<li>HTML and CSS</li>
<li>Cloud fundamentals</li>
<li>Problem solving</li>
</ul>
</div>
</div>
</section>
</main>
What the About Area Adds
- The introduction explains your current professional direction.
- The skills list gives visitors a quick summary of your capabilities.
- The about ID connects this section to the matching navigation link.
- Save index.html.
- Refresh the local page in Microsoft Edge.
You should see the About heading followed by two introduction paragraphs. A Core skills list should appear below them.
About Content Outside the Page?
Confirm that the complete main block sits after </header> and before </body>.
Help me place the main content correctly.
Project cards turn your claims into work a visitor can discuss with you. Three entries create space for this portfolio plus two more examples.
- Find the closing </main> tag.
- Place your cursor above the closing </main> tag.
- Add the Projects area by pasting this code:
<section class="section section-tint" id="projects">
<div class="container">
<div class="section-heading">
<p class="eyebrow">Projects</p>
<h2>Work I can demonstrate</h2>
</div>
<div class="project-grid">
<article class="card">
<p class="card-number">01</p>
<h3>S3 Portfolio Website</h3>
<p>A responsive portfolio hosted from an Amazon S3 static website endpoint with controlled public-read access.</p>
</article>
<article class="card">
<p class="card-number">02</p>
<h3>Cloud Learning Project</h3>
<p>Replace this text with a project that shows how you planned, built, tested, and improved a cloud solution.</p>
</article>
<article class="card">
<p class="card-number">03</p>
<h3>Problem-Solving Project</h3>
<p>Replace this text with a concise example of a challenge, your approach, and the result you achieved.</p>
</article>
</div>
</div>
</section>
How the Project Cards Help
- Each article represents one project.
- The card number creates a clear order.
- The title plus description gives visitors a starting point for questions.
- Save index.html.
- Refresh the local page in Microsoft Edge.
You should see a Projects heading followed by three numbered project entries.
Projects Link Goes Nowhere?
Check that the section begins with id="projects". The spelling must match href="#projects" in the navigation.
Help me match my Projects link to its section.
The resume area gives your experience a predictable reading order. It begins with your recent work or learning.
- Find the closing </main> tag.
- Place your cursor above the closing </main> tag.
- Add the Resume area by pasting this code:
<section class="section container" id="resume">
<div class="section-heading">
<p class="eyebrow">Resume</p>
<h2>Experience and education</h2>
</div>
<div class="resume-grid">
<article class="resume-block">
<h3>Experience</h3>
<div class="timeline-item">
<p class="meta">Recent dates</p>
<h4>Your Role or Learning Program</h4>
<p>Describe one responsibility, the action you took, and a measurable or visible result.</p>
</div>
<div class="timeline-item">
<p class="meta">Earlier dates</p>
<h4>Previous Role or Volunteer Experience</h4>
<p>Highlight a transferable skill such as communication, ownership, organization, or customer support.</p>
</div>
</article>
</div>
<p class="print-tip">On Windows, press <kbd>Ctrl</kbd> + <kbd>P</kbd> to print this page or save a PDF copy.</p>
</section>
How the Experience Timeline Works
- Each timeline item pairs a date with a role.
- The supporting paragraph captures your contribution.
- The print tip explains how to open a printable version later.
- Save index.html.
- Refresh the local page in Microsoft Edge.
You should see an Experience and education heading followed by two Experience entries. A print tip should appear beneath them.
Resume Appears Inside Projects?
Confirm that the Resume section starts after the Projects section closes. It must remain above the final </main> tag.
Help me separate the Projects and Resume sections.
Education and credentials complete the second half of the resume grid. This area shows formal study plus current learning.
- Locate the Experience <article class="resume-block"> element.
- Find the closing </article> tag for that Experience element.
- Place your cursor below that closing </article> tag.
- Add the Education area by pasting this code:
<article class="resume-block">
<h3>Education and credentials</h3>
<div class="timeline-item">
<p class="meta">Completion year</p>
<h4>Your Course, Degree, or Certification</h4>
<p>Name the provider and summarize the most relevant subjects or practical skills.</p>
</div>
<div class="timeline-item">
<p class="meta">In progress</p>
<h4>Current Learning Goal</h4>
<p>State the cloud, web, or technical skill you are actively developing.</p>
</div>
</article>
What the Education Area Shows
- The first entry records a completed course or credential.
- The second entry records the skill you are developing now.
- Both entries share the same timeline structure as Experience.
- Save index.html.
- Refresh the local page in Microsoft Edge.
You should see Education and credentials beside or below Experience. The exact position depends on the current browser width.
Education Outside the Resume Area?
Make sure the Education article sits inside <div class="resume-grid">. Place it after the Experience article.
Help me place the Education article inside the resume grid.
The contact panel gives visitors a direct next step. Its email link uses the address as both the visible label and the destination.
- Find the closing </main> tag.
- Place your cursor above the closing </main> tag.
- Add the Contact area by pasting this code:
<section class="section section-tint" id="contact">
<div class="contact-panel container">
<div>
<p class="eyebrow">Contact</p>
<h2>Let us build something useful</h2>
<p>Replace this sentence with the kind of opportunities or conversations you welcome.</p>
</div>
<a class="button primary" href="mailto:your-email@example.com">your-email@example.com</a>
</div>
</section>
How the Contact Link Works
- The contact message tells visitors which conversations you welcome.
- The mailto: destination asks the visitor's device to prepare an email.
- The contact ID gives the navigation link a destination.
- Save index.html.
- Refresh the local page in Microsoft Edge.
You should see a Contact heading followed by an opportunity message. The example email address should appear below it.
Contact Section Missing?
Check that the Contact section remains above </main>. Confirm that its opening and closing section tags are both present.
Help me restore the Contact section.
The footer closes the page with your name plus a quick return link. It sits after the main content because it applies to the whole document.
- Find the closing </main> tag.
- Place your cursor below the closing </main> tag.
- Add the footer by pasting this code:
<footer>
<div class="container footer-content">
<p>Your Name</p>
<a href="#home">Back to top</a>
</div>
</footer>
What the Footer Completes
- The name identifies who owns the portfolio.
- The Back to top link targets the home ID on the header.
- The footer remains separate from the main portfolio content.
- Save index.html.
- Refresh the local page in Microsoft Edge.
You should see Your Name plus a Back to top link at the bottom of the page.
Footer Appears Inside Contact?
Confirm that <footer> begins after </main>. It must remain above </body>.
Help me place the footer after the main content.
✔️ Awesome, I've got everything!
Great. Double check that you saved index.html before personalizing the template.
ⓧ I'd like to double check the full code
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Portfolio and resume for Your Name">
<title>Your Name | Portfolio and Resume</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="hero" id="home">
<nav class="nav container" aria-label="Primary navigation">
<a class="logo" href="#home">YN</a>
<div class="nav-links">
<a href="#about">About</a>
<a href="#projects">Projects</a>
<a href="#resume">Resume</a>
<a href="#contact">Contact</a>
</div>
</nav>
<div class="hero-content container">
<p class="eyebrow">Hello, I am</p>
<h1>Your Name</h1>
<p class="tagline">Aspiring cloud professional building reliable, useful experiences on AWS.</p>
<div class="hero-actions">
<a class="button primary" href="#projects">Explore my work</a>
<a class="button secondary" href="#resume">Read my resume</a>
</div>
</div>
</header>
<main>
<section class="section container" id="about">
<div class="section-heading">
<p class="eyebrow">About</p>
<h2>A quick introduction</h2>
</div>
<div class="about-grid">
<div>
<p>I am developing practical cloud and web skills through hands-on projects. I enjoy turning ideas into clear, dependable experiences that people can use.</p>
<p>My current focus is AWS, static web hosting, and building a strong foundation in front-end development.</p>
</div>
<div class="skills-card">
<h3>Core skills</h3>
<ul class="skills-list">
<li>Amazon S3</li>
<li>HTML and CSS</li>
<li>Cloud fundamentals</li>
<li>Problem solving</li>
</ul>
</div>
</div>
</section>
<section class="section section-tint" id="projects">
<div class="container">
<div class="section-heading">
<p class="eyebrow">Projects</p>
<h2>Work I can demonstrate</h2>
</div>
<div class="project-grid">
<article class="card">
<p class="card-number">01</p>
<h3>S3 Portfolio Website</h3>
<p>A responsive portfolio hosted from an Amazon S3 static website endpoint with controlled public-read access.</p>
</article>
<article class="card">
<p class="card-number">02</p>
<h3>Cloud Learning Project</h3>
<p>Replace this text with a project that shows how you planned, built, tested, and improved a cloud solution.</p>
</article>
<article class="card">
<p class="card-number">03</p>
<h3>Problem-Solving Project</h3>
<p>Replace this text with a concise example of a challenge, your approach, and the result you achieved.</p>
</article>
</div>
</div>
</section>
<section class="section container" id="resume">
<div class="section-heading">
<p class="eyebrow">Resume</p>
<h2>Experience and education</h2>
</div>
<div class="resume-grid">
<article class="resume-block">
<h3>Experience</h3>
<div class="timeline-item">
<p class="meta">Recent dates</p>
<h4>Your Role or Learning Program</h4>
<p>Describe one responsibility, the action you took, and a measurable or visible result.</p>
</div>
<div class="timeline-item">
<p class="meta">Earlier dates</p>
<h4>Previous Role or Volunteer Experience</h4>
<p>Highlight a transferable skill such as communication, ownership, organization, or customer support.</p>
</div>
</article>
<article class="resume-block">
<h3>Education and credentials</h3>
<div class="timeline-item">
<p class="meta">Completion year</p>
<h4>Your Course, Degree, or Certification</h4>
<p>Name the provider and summarize the most relevant subjects or practical skills.</p>
</div>
<div class="timeline-item">
<p class="meta">In progress</p>
<h4>Current Learning Goal</h4>
<p>State the cloud, web, or technical skill you are actively developing.</p>
</div>
</article>
</div>
<p class="print-tip">On Windows, press <kbd>Ctrl</kbd> + <kbd>P</kbd> to print this page or save a PDF copy.</p>
</section>
<section class="section section-tint" id="contact">
<div class="contact-panel container">
<div>
<p class="eyebrow">Contact</p>
<h2>Let us build something useful</h2>
<p>Replace this sentence with the kind of opportunities or conversations you welcome.</p>
</div>
<a class="button primary" href="mailto:your-email@example.com">your-email@example.com</a>
</div>
</section>
</main>
<footer>
<div class="container footer-content">
<p>Your Name</p>
<a href="#home">Back to top</a>
</div>
</footer>
</body>
</html>
Personalize your public content
This portfolio later becomes public through Amazon S3. Include only information you are comfortable showing to anyone who receives the website address.
- Replace every Your Name occurrence with the public name you want visitors to see.
- Replace YN with your initials.
- Rewrite the hero tagline to support your portfolio goal.
- Rewrite the About paragraphs with accurate information.
- Update the Core skills list with skills you can discuss.
- Replace the second project example with work you can demonstrate.
- Replace the third project example with work you can demonstrate.
Keep Personal Details Safe
Use a professional contact address that you are comfortable publishing. Leave out private addresses plus personal phone numbers unless you have chosen to make them public.
- Replace the Experience prompts with your roles plus results.
- Replace the Education prompts with your completed learning.
- Replace the Current Learning Goal prompt with your active focus.
- Replace the contact message with the opportunities you welcome.
- Replace both your-email@example.com values with your public contact address.
- Save index.html.
- Refresh the local page in Microsoft Edge.
You should now see your name plus your own content throughout the unstyled page. The headings should make each section easy to identify.
Still See Template Prompts?
Use Visual Studio Code search to look for Your, Replace, plus your-email@example.com. Review every match before publishing.
Help me find the remaining portfolio placeholders.
Test the in-page navigation
Each navigation link uses a fragment that matches a section ID in the document. A working link moves its destination toward the top of the browser window.
Before you test the page, which section do you expect each link to reveal?
- Click your initials in the logo at the top of the page.
- Click About in the top navigation.
- Click Projects in the top navigation.
- Click Resume in the top navigation.
- Click Contact in the top navigation.
- Click Explore my work in the hero.
- Click Read my resume in the hero.
- Click Back to top in the footer.
Each link should move its matching section toward the top of the window. Your initials plus the Back to top link should return you to the hero.
That is the content foundation complete. Your portfolio now displays navigation plus About, Skills, Projects, Resume, Contact, plus footer content in a readable unstyled layout.
A Link Moves to the Wrong Place?
Compare the link's href value with the destination section's id value. The text after # must match the ID exactly.
Help me debug an in-page navigation link.
Your portfolio content is complete plus navigable. Next, you will turn this readable structure into a responsive and print-ready design.
Add Responsive and Print Styling
Your portfolio already has working navigation plus complete resume content. In Microsoft Edge, that content still appears as an unstyled page.
This step adds the CSS that turns the page into a portfolio-ready website. You will also make the layout responsive and prepare the resume for printing.
In this step, get ready to:
- Add colors, typography, spacing, cards, and buttons to the portfolio.
- Make the navigation and content grids stack below 720 pixels.
- Check the simplified resume layout in Microsoft Edge's print preview.
Style the portfolio
A stylesheet controls how the existing HTML appears without changing its content. The classes already present in index.html give each CSS rule a specific part of the portfolio to style.
- In Visual Studio Code, use the file icon beside the portfolio-s3 folder to create a file.
- Name the file styles.css.
- Select the second tab below.
- Copy the complete stylesheet shown there.
- Paste the stylesheet into styles.css.
✔️ Awesome, I've got everything!
Great. Check that styles.css sits beside index.html inside Documents/portfolio-s3.
ⓧ I'd like to double check the full code
:root {
--navy: #10233f;
--blue: #2563eb;
--sky: #dbeafe;
--ink: #172033;
--muted: #5f6b7a;
--surface: #ffffff;
--tint: #f4f7fb;
--line: #d9e1ec;
--radius: 18px;
--shadow: 0 18px 45px rgba(16, 35, 63, 0.12);
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
color: var(--ink);
background: var(--surface);
font-family: Arial, Helvetica, sans-serif;
line-height: 1.65;
}
a {
color: inherit;
}
.container {
width: min(1100px, calc(100% - 40px));
margin-inline: auto;
}
.hero {
min-height: 72vh;
color: #ffffff;
background: linear-gradient(135deg, var(--navy), #1e4f91);
}
.nav {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
padding-block: 24px;
}
.logo {
display: grid;
width: 46px;
height: 46px;
place-items: center;
border: 1px solid rgba(255, 255, 255, 0.55);
border-radius: 50%;
font-weight: 800;
text-decoration: none;
}
.nav-links {
display: flex;
flex-wrap: wrap;
gap: 22px;
}
.nav-links a,
.footer-content a {
text-decoration: none;
}
.nav-links a:hover,
.footer-content a:hover {
text-decoration: underline;
}
.hero-content {
display: grid;
align-content: center;
min-height: 55vh;
padding-block: 48px 80px;
}
.eyebrow {
margin: 0 0 8px;
color: #60a5fa;
font-size: 0.82rem;
font-weight: 800;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.hero h1 {
max-width: 820px;
margin: 0;
font-size: clamp(3rem, 9vw, 6.5rem);
line-height: 0.95;
}
.tagline {
max-width: 680px;
margin: 28px 0;
color: #dbeafe;
font-size: clamp(1.05rem, 2vw, 1.35rem);
}
.hero-actions {
display: flex;
flex-wrap: wrap;
gap: 14px;
}
.button {
display: inline-block;
padding: 12px 18px;
border: 2px solid transparent;
border-radius: 999px;
font-weight: 800;
text-decoration: none;
}
.button.primary {
color: #ffffff;
background: var(--blue);
}
.button.secondary {
color: #ffffff;
border-color: rgba(255, 255, 255, 0.65);
}
.section {
padding-block: 76px;
}
.section-tint {
background: var(--tint);
}
.section-heading {
max-width: 680px;
margin-bottom: 32px;
}
.section-heading h2,
.contact-panel h2 {
margin: 0;
color: var(--navy);
font-size: clamp(2rem, 5vw, 3rem);
line-height: 1.1;
}
.about-grid,
.resume-grid {
display: grid;
grid-template-columns: 1.2fr 0.8fr;
gap: 32px;
}
.skills-card,
.card,
.resume-block,
.contact-panel {
border: 1px solid var(--line);
border-radius: var(--radius);
background: var(--surface);
box-shadow: var(--shadow);
}
.skills-card,
.card,
.resume-block {
padding: 26px;
}
.skills-card h3,
.card h3,
.resume-block h3,
.timeline-item h4 {
margin-top: 0;
color: var(--navy);
}
.skills-list {
display: flex;
flex-wrap: wrap;
gap: 10px;
padding: 0;
list-style: none;
}
.skills-list li {
padding: 7px 11px;
border-radius: 999px;
color: var(--navy);
background: var(--sky);
font-weight: 700;
}
.project-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 22px;
}
.card-number,
.meta {
color: var(--blue);
font-size: 0.85rem;
font-weight: 800;
text-transform: uppercase;
}
.timeline-item + .timeline-item {
margin-top: 26px;
padding-top: 26px;
border-top: 1px solid var(--line);
}
.timeline-item p {
margin-bottom: 0;
}
.print-tip {
margin-top: 28px;
color: var(--muted);
}
kbd {
padding: 2px 6px;
border: 1px solid var(--line);
border-radius: 5px;
background: var(--tint);
font-family: inherit;
}
.contact-panel {
display: flex;
align-items: center;
justify-content: space-between;
gap: 30px;
padding: 36px;
}
.contact-panel p:not(.eyebrow) {
max-width: 650px;
}
footer {
color: #ffffff;
background: var(--navy);
}
.footer-content {
display: flex;
justify-content: space-between;
gap: 20px;
padding-block: 28px;
}
@media (max-width: 720px) {
.nav,
.contact-panel,
.footer-content {
align-items: flex-start;
flex-direction: column;
}
.about-grid,
.resume-grid,
.project-grid {
grid-template-columns: 1fr;
}
.hero {
min-height: auto;
}
.section {
padding-block: 56px;
}
}
@media print {
:root {
--ink: #000000;
--muted: #333333;
}
body {
color: #000000;
background: #ffffff;
font-size: 11pt;
}
.hero {
min-height: auto;
color: #000000;
background: #ffffff;
}
.nav,
.hero-actions,
.print-tip,
footer {
display: none;
}
.hero-content,
.section {
min-height: auto;
padding-block: 22px;
}
.hero h1,
.section-heading h2,
.contact-panel h2,
.skills-card h3,
.card h3,
.resume-block h3,
.timeline-item h4 {
color: #000000;
}
.tagline,
.eyebrow {
color: #333333;
}
.section-tint {
background: #ffffff;
}
.skills-card,
.card,
.resume-block,
.contact-panel {
border-color: #bbbbbb;
box-shadow: none;
break-inside: avoid;
}
.contact-panel {
display: block;
}
@page {
margin: 14mm;
}
}
How is the stylesheet organized?
- The :root variables keep the portfolio's colors, corner radius, and shadow consistent.
- The layout rules arrange the hero, cards, resume, contact panel, and footer.
- The @media (max-width: 720px) section adapts the page to narrow screens.
- The @media print section creates a simpler layout for printing.
- Save styles.css.
- Switch back to the local portfolio in Microsoft Edge.
- Refresh index.html.
You will see a navy hero with large introductory text. The portfolio sections now use cards, spacing, buttons, and a consistent color palette.
That visual transformation confirms Microsoft Edge found styles.css through the link already present in index.html.
Still seeing the unstyled page?
Confirm that the file is named styles.css in lowercase. It must sit beside index.html inside Documents/portfolio-s3.
Check that index.html still contains the stylesheet reference to styles.css.
Help me find why my local portfolio is not loading styles.css in Microsoft Edge.
Test the responsive layout
A responsive layout adjusts to the width available on the screen. The 720px media query changes wide rows into vertical stacks when the browser becomes narrow.
- Resize the Microsoft Edge window until it is narrower than 720 pixels.
You will see the navigation, contact panel, and footer stack vertically. The About, Resume, and Projects grids switch to one column.
Why does the layout stack?
The media query changes each grid to grid-template-columns: 1fr. Each card receives the full available width, which keeps the content readable on a narrow screen.
Layout staying in columns?
Confirm that the responsive section starts with @media (max-width: 720px). Check that its closing brace remains at the end of the responsive rules.
Refresh the local page after saving styles.css.
Help me troubleshoot why my CSS media query is not stacking the portfolio layout.
Check the print layout
Print CSS gives the same portfolio a document-focused layout. It uses black text, removes decorative backgrounds, and avoids splitting cards where possible.
Before you open the print preview, which page elements do you expect the print rules to remove?
- Press Ctrl+P in Microsoft Edge to open the print dialog.
You will see the portfolio in a clean print layout without the navigation, hero buttons, print tip, or footer. The cards keep their borders while their decorative shadows disappear.
- Choose an available PDF output only if you want to save a local copy.
Keep the PDF optional
The print preview is enough to verify this step. Saving a PDF creates an extra local copy for applications or offline sharing.
Your portfolio now works as a responsive website and a printable resume. Next, you will upload index.html and styles.css to Amazon S3.
Upload the Site and Test Permissions
Your portfolio now looks polished on a wide screen. It also turns into a clean resume in print preview.
You will use the AWS Management Console to place the same files in Amazon S3. Testing its website endpoint reveals what the current access settings allow.
In this step, get ready to:
- Create a dedicated S3 bucket with public access blocked.
- Upload the portfolio files to the bucket.
- Configure static website hosting for the portfolio.
Create a dedicated S3 bucket
Creating this bucket adds a persistent AWS resource. The two tiny files keep usage minimal, but standard S3 charges can still apply on a paid account.
Choosing a bucket name can be fiddly because it must be globally unique across the AWS partition. Avoid sensitive information because the name appears in object URLs.
- Return to the General purpose buckets page in Amazon S3.
- Choose Create bucket to open the bucket creation page.
You should see the creation form with fields for the bucket name and Region.
- Enter portfolio-resume-yourname-1234 in the Bucket name field.
- Choose a nearby AWS Region.
A nearby Region can reduce latency for visitors who are close to you.
- Confirm Block all public access remains selected.
- Keep the remaining settings at their defaults.
- Choose Create bucket to create the bucket.
You should return to the bucket list. Your new bucket name should appear there.
Bucket name unavailable?
- Replace the final four digits with another four-digit combination.
- Enter the revised name in the Bucket name field.
- Choose Create bucket again.
If the bucket still cannot be created, help me troubleshoot my S3 bucket creation.
Upload the website files
Inside the bucket, uploaded files become S3 objects. Their names must remain index.html plus styles.css so the stylesheet link keeps working.
Upload Public Content Only
This bucket becomes public in the next step. Upload only files that you are comfortable sharing on the internet.
- Select portfolio-resume-yourname-1234 from the bucket list.
- Choose Upload.
You should see the upload page for your new bucket.
- Choose Add file.
- Use the Windows file picker to select Documents/portfolio-s3/index.html plus Documents/portfolio-s3/styles.css.
The upload page should now list both files.
- Choose Upload to send the files to the bucket.
The Upload: status page should report success for both files. Your local copies in Documents/portfolio-s3 remain unchanged.
Upload Did Not Succeed?
- Confirm Visual Studio Code has saved both local files.
- Confirm the selected files are named exactly index.html plus styles.css.
- Retry the upload after confirming your AWS session is still active.
For a different upload problem, help me troubleshoot my S3 object upload.
Test the website endpoint
Static website hosting tells Amazon S3 which object to serve as the homepage for the bucket's website endpoint.
- Return to General purpose buckets in Amazon S3.
- Select portfolio-resume-yourname-1234.
- Select the Properties tab.
- Find the Static website hosting section.
- Choose Edit.
You should see the static website hosting configuration form.
- Choose Use this bucket to host a website.
- Choose Enable.
Enabling the setting reveals the document fields that control how Amazon S3 handles homepage requests.
- Enter index.html in the Index document field.
- Choose Save changes.
The Endpoint link should now appear under Static website hosting.
Before you open it, what do you expect the endpoint to show? Take a moment to decide.
- Choose the Endpoint link to load the website in Microsoft Edge.
Microsoft Edge shows 403 (Access Denied). This planned failure proves the endpoint exists while the uploaded homepage remains unreadable to public visitors.
What Controls the Response?
Static website hosting identifies index.html as the home page. Object permissions still control whether a visitor can read it.
Block Public Access remains enabled. No public bucket policy grants read access, so Amazon S3 returns 403 (Access Denied) for the existing file.
Seeing a Different Result?
- Confirm the bucket contains an object named exactly index.html if Microsoft Edge shows 404 (Not Found).
- Confirm the Index document value is exactly index.html.
- Confirm Block all public access remains enabled under Permissions if the portfolio loads publicly.
For another endpoint result, help me diagnose my S3 website response.
Your website endpoint is active, and the deliberate denial confirms that hosting and public read access are separate controls. Next, you will turn that blocked endpoint into a working public portfolio.
Publish the Portfolio with a Bucket Policy
Your Amazon S3 website endpoint still shows 403 (Access Denied). That result proves static website hosting is active while object read access remains blocked.
This step closes that exact permission gap. A public-read bucket policy grants only s3:GetObject access for objects in your dedicated portfolio bucket.
In this step, get ready to:
- Disable bucket-level Block Public Access only for your dedicated portfolio bucket.
- Add a bucket policy that makes the website objects publicly readable.
- Verify the public portfolio across its browser layout and print layout.
Allow public access for the portfolio bucket
Changing public access can feel risky. This change applies only to the dedicated bucket that contains files you intend to publish.
Anyone on the internet can retrieve public objects from this bucket. Private documents belong in a separate bucket with public access blocked.
- Return to the AWS Management Console tab from earlier.
- Record the exact bucket name shown on the General purpose buckets page here: your exact S3 bucket name.
- Select your exact S3 bucket name.
- Confirm the bucket contains only index.html and styles.css.
- Select the Permissions tab.
- Choose Edit under Block public access (bucket settings).
- Clear Block all public access.
- Choose Save changes.
The bucket can now accept a public-read policy. Its objects remain inaccessible through the website endpoint until that policy is saved.
Why are both controls needed?
Block Public Access acts as a guardrail against public permissions. Disabling the bucket-level guardrail allows a bucket policy to define the access you want.
The policy in the next substep limits that access to retrieving objects. This keeps the permission focused on serving website files.
Unable to change public access?
- Check whether account-level Block Public Access still enforces a more restrictive setting.
- Ask an authorized account administrator to approve the public website configuration if your organization manages the setting.
- Confirm your IAM identity has permission to change the bucket configuration.
Help me diagnose why I cannot disable Block Public Access for my S3 portfolio bucket.
Add the public-read bucket policy
The policy identifies who can access the objects. It also limits that access to the s3:GetObject action under your bucket's object resource path.
- Scroll to Bucket Policy on the existing Permissions tab.
- Choose Edit.
- Paste the AWS example policy below as the starting template:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::{{Bucket-Name}}/*"
]
}
]
}
What does this policy allow?
- The Principal value of * allows requests from anyone on the internet.
- The s3:GetObject action permits visitors to retrieve website objects.
- The Resource value scopes that permission to objects stored under the named bucket.
- Find {{Bucket-Name}} in the Resource value.
- Replace {{Bucket-Name}} with your exact S3 bucket name.
- Choose Save changes.
The Bucket Policy section now contains the saved public-read statement. Its Resource value ends with /* to cover the website objects in your bucket.
Policy not saving?
- Check that the bucket name in the resource path matches your bucket exactly.
- Confirm the resource path begins with arn:aws:s3:::.
- Confirm the resource path ends with /*.
- Ask an authorized administrator to review account-level public-access restrictions if the policy remains blocked.
Help me fix my S3 public-read bucket policy.
✔️ Awesome, I've got everything!
Your saved policy grants public read access to the objects in your dedicated portfolio bucket.
ⓧ I'd like to double check the full code
{"Version":"2012-10-17","Statement":[{"Sid":"PublicReadGetObject","Effect":"Allow","Principal":"*","Action":["s3:GetObject"],"Resource":["arn:aws:s3:::portfolio-resume-yourname-1234/*"]}]}
How should the saved policy compare?
This reference matches the target policy for the example bucket named portfolio-resume-yourname-1234.
A different unique bucket name appears in the same position inside your saved Resource value.
Verify the public portfolio
The direct website endpoint uses HTTP. A successful page load proves the public-read policy now reaches the uploaded website objects.
Before you reopen the endpoint, do you expect to see the same 403 (Access Denied) response or your portfolio?
- Return to the Properties tab for your bucket.
- Scroll to Static website hosting.
- Choose the Bucket website endpoint link.
Your styled portfolio now loads in Microsoft Edge instead of the planned permission response. That is the access gap closed.
- Select each navigation link in turn to test the About, Projects, Resume, and Contact sections.
- Select your published email address to test the mailto: link.
- Return to Microsoft Edge after the email test.
- Narrow the Microsoft Edge window until the content grids stack into one column.
- Press Ctrl+P to open the print preview.
Each navigation link jumps to its matching section. The email test opens a draft or prompts you to choose a mail app.
Below 720px, the content grids stack into one column.
The print preview shows a clean resume layout without website controls or decorative shadows.
- Close the print preview to return to the public portfolio.
Still seeing the 403 response?
- Refresh the Bucket website endpoint after saving the policy.
- Confirm bucket-level Block Public Access remains disabled for this dedicated bucket.
- Compare the bucket name in the policy resource with your exact S3 bucket name.
- Confirm the policy resource ends with /*.
Help me resolve the remaining 403 response from my S3 website endpoint.
You have resolved the permission barrier. Your responsive portfolio now loads publicly from its Amazon S3 website endpoint.
Secret mission
Secret Mission: Create a Branded 404 Page
Visitors who follow a broken portfolio link need a clear route back to your work. In this mission, you will create a branded 404 page, upload it to your public bucket, and configure it as the website error document.
Clean Up Your Resources
Clean Up Your Resources
Your portfolio remains public through Amazon S3, so the bucket can continue to generate usage charges on a paid account. Decide whether to keep the site public, pause public access, or delete every project resource.
Cost warning
Amazon S3 charges based on usage that can include storage, requests, and data transfer. A paid account can accrue a small charge while the bucket remains.
Pausing limits public requests. Deleting removes the Amazon S3 storage created by this project.
Resources you used:
- One Amazon S3 general purpose bucket: portfolio-resume-yourname-1234.
- Three public website objects named index.html, styles.css, and 404.html.
- Static website hosting configured with index.html as the Index document and 404.html as the Error document.
- A public-read bucket policy granting s3:GetObject for every bucket object.
- Bucket-level Block Public Access disabled for the dedicated portfolio bucket.
- A local Documents/portfolio-s3 folder containing your editable website files.
Keep everything running
No action needed. Choose this if you want your portfolio to stay public while you keep improving or sharing it.
- Your HTTP website endpoint remains publicly available.
- Anyone on the internet can retrieve the objects in this dedicated bucket.
- Your branded missing-page response remains active through 404.html.
- Your local files remain in Documents/portfolio-s3.
- Amazon S3 usage can continue to generate charges on a paid account.
Pause - I'll come back to this later
Shut down public access while keeping the bucket and its objects available for later. Stored objects can still generate storage charges.
- Return to the bucket's Permissions tab in the AWS Management Console.
- Remove the existing public-read policy from Bucket Policy.
- Under Block public access (bucket settings), choose Edit.
- Select Block all public access.
- Choose Save changes.
- Return to the Bucket website endpoint in Microsoft Edge to verify the pause.
You'll see 403 (Access Denied). This confirms that public reads are blocked while the objects remain stored.
Delete - I don't want to use this again
Remove the published AWS resources and start fresh. Deleting the bucket is permanent, but your local copies remain available until you remove that folder at the end.
Deletion is permanent
Emptying the bucket permanently deletes index.html, styles.css, and 404.html. The bucket remains until you complete the separate bucket deletion.
- Return to the General purpose buckets page in the Amazon S3 console.
- Select portfolio-resume-yourname-1234.
- Choose Empty.
- Enter portfolio-resume-yourname-1234 in the confirmation field.
- Choose Empty.
The website files are now gone from Amazon S3. The empty bucket is ready for deletion.
- Return to the General purpose buckets page.
- Select portfolio-resume-yourname-1234.
- Choose Delete.
- Enter portfolio-resume-yourname-1234 in the confirmation field.
- Choose Delete bucket.
- Check the bucket list for portfolio-resume-yourname-1234.
The bucket name no longer appears in the list. Its website configuration and public-read policy are gone with it.
Your AWS resources are now removed. The local Documents/portfolio-s3 folder remains until you delete it.
- Return to your Documents folder in the Windows file browser.
- Select the portfolio-s3 folder.
- Delete the selected folder.
- Check your Documents folder for portfolio-s3.
The portfolio-s3 folder no longer appears in Documents. You have removed every project resource.
Nice Work!
Nice Work!
You did it. Your responsive portfolio now runs from a public Amazon S3 website endpoint with a print-ready resume.
You've learned how to:
- Build a semantic one-page portfolio using plain HTML. Shape it for narrow screens with responsive CSS. Produce a clean resume preview with print CSS.
- Publish website objects through the AWS Management Console. Serve them from an Amazon S3 website endpoint.
- Resolve the planned 403 (Access Denied) response by changing Block Public Access for the dedicated bucket. Grant public reads through a bucket policy containing s3:GetObject.
- Secret Mission: Add a branded 404.html error document. Guide visitors home with the Return to portfolio link.
Ready to quiz yourself?