Back to Blog
Web Development

Building a Modern Portfolio Website with Cloudflare Pages & Vanilla JS

Your portfolio website is your digital storefront. Whether you're a freelancer, developer, designer, or business owner, a fast, well-designed portfolio can make the difference between landing a client and losing them to a competitor.

In this guide, we'll walk through building a complete portfolio website using nothing but vanilla HTML, CSS, and JavaScript — no frameworks, no build tools, no complicated setup. And we'll deploy it on Cloudflare Pages for free, with HTTPS, custom domain, and global CDN baked in.

Why Vanilla JS + Cloudflare Pages?

Modern web development often feels like a maze of frameworks, bundlers, and config files. But for a portfolio website, simplicity wins. Here's why this stack makes sense:

Step 1: Project Structure

Let's start with a clean project structure that keeps things organized without overcomplicating things:

portfolio/
├── index.html
├── about.html
├── projects.html
├── contact.html
├── css/
│   └── style.css
├── js/
│   └── main.js
└── assets/
    ├── images/
    └── resume.pdf

Each page is a standalone HTML file. Shared styles live in style.css, and interactivity goes in main.js. Simple, predictable, and easy to maintain.

Step 2: Building the Layout

We'll use a mobile-first approach with CSS custom properties for theming. Here's the foundation:

:root {
  --primary: #2563eb;
  --dark: #0f172a;
  --light: #f8fafc;
  --gray: #64748b;
  --border: #e2e8f0;
  --shadow: 0 4px 14px rgba(0,0,0,0.08);
  --radius: 12px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  font-family: 'Inter', system-ui, sans-serif;
  color: var(--dark);
  background: var(--light);
  line-height: 1.7;
}

.container {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 1.5rem;
}

Tip: Use system-ui as the font stack. It adapts to the user's operating system font, giving a native feel on every device without loading external fonts.

Step 3: Creating a Reusable Header and Footer

Instead of repeating the same navigation code on every page, we'll use a small JavaScript snippet that loads the header and footer dynamically:

<!-- In each HTML page -->
<div id="header"></div>
<div id="footer"></div>

<script src="js/main.js" defer></script>
// main.js
fetch('components/header.html')
  .then(r => r.text())
  .then(html => document.getElementById('header').innerHTML = html);

fetch('components/footer.html')
  .then(r => r.text())
  .then(html => document.getElementById('footer').innerHTML = html);

This keeps your navigation and footer in one place. Update it once, and every page reflects the change.

Step 4: Designing the Hero Section

The hero is the first thing visitors see. Keep it clean and focused:

<section class="hero">
  <h1>Hi, I'm Alex</h1>
  <p>Full-stack developer & designer</p>
  <p>I build fast, accessible websites and web applications.</p>
  <a href="/projects" class="btn">View My Work</a>
</section>
.hero {
  padding: 6rem 1.5rem;
  text-align: center;
  background: linear-gradient(135deg, #0f172a, #2563eb);
  color: white;
  border-radius: 0 0 var(--radius) var(--radius);
}

Step 5: Adding a Projects Grid

Showcase your work with a responsive CSS grid. No frameworks needed:

.projects-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 1.5rem;
}

.project-card {
  background: white;
  border-radius: var(--radius);
  padding: 1.5rem;
  box-shadow: var(--shadow);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.project-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 30px rgba(0,0,0,0.12);
}

The auto-fit and minmax() combination ensures the grid automatically adjusts from 3 columns on desktop to 1 column on mobile — no media queries required.

Step 6: Deploying to Cloudflare Pages

Cloudflare Pages makes deployment incredibly simple. Here's how:

  1. Push your code to GitHub — Create a repository and push your project.
  2. Log in to Cloudflare Pages — Go to the Cloudflare dashboard and click Pages.
  3. Connect your Git provider — Authorize Cloudflare to access your repository.
  4. Configure build settings — Set the build command to empty (no build step) and publish directory to / (or your project root).
  5. Deploy — Click "Deploy" and your site will be live in under a minute.
# Cloudflare Pages configuration
Build command: (none)
Publish directory: /
Root directory: /

Pro tip: Add a _redirects file in your publish root to enable clean URLs. For example: /about /about.html 200 turns /about.html into /about.

Step 7: Adding a Custom Domain

Cloudflare Pages lets you add a custom domain with one click:

Step 8: Performance Optimization

A portfolio website should load in under 2 seconds. Here's how to keep it fast:

<!-- Lazy loading example -->
<img src="project-thumbnail.webp" alt="Project screenshot" loading="lazy">

Conclusion

Building a portfolio website doesn't require a complex framework or a build pipeline. With vanilla HTML, CSS, and JavaScript, you can create a fast, beautiful, and maintainable site that loads instantly and ranks well on search engines.

Cloudflare Pages handles the hosting, CDN, HTTPS, and deployment pipeline for free — letting you focus on what matters most: showcasing your work and attracting clients.

Ready to build yours? Start with a single index.html file, add your content, push to Git, and deploy. Your portfolio could be live in under an hour.

HTML CSS JavaScript Cloudflare