Build Your Own Website

Open access website building

All of the files for this website are free to view and download via the GitHub link on this site. I’m also providing a full set of beginner templates and a step-by-step guide here so you can build your own website with little to no experience.

Website building is often presented as difficult, or hidden behind paywalls and subscriptions. That can lock people out of having a website of their own through no fault of their own. My goal is to make the basics clear, slow, and genuinely beginner-friendly — so you can leave with a working site you control. This was in a sense a goal of making this website, the other uses are incidental.

What you are making

You are making a multi-page website hosted for free using GitHub Pages. The website is just a collection of files (mostly HTML and CSS) stored in a GitHub repository.

Think of it like: HTML = the building, CSS = the design, JS = the moving parts.

Your website folder structure

Your GitHub repository (your online folder) will look like this:

your-website/
  index.html
  pages/
    about.html
    projects.html
    cv.html
    more.html
  stylesheets/
    base.css
  js/
    main.js
  assets/
    images-and-files-go-here.png
    cv.pdf

The most important file is index.html. It is your homepage. GitHub Pages looks for it first.

Step-by-step: GitHub Pages

  1. Create a GitHub account
    Go to GitHub and sign up. Choose a username you are happy to show publicly.
  2. Create a repository (this is your website folder)
    On GitHub, click the + top-right → New repository.
  3. Name it
    Two options:
    • Easy option: call it my-website (or anything).
    • Classic personal site option: call it yourusername.github.io.
    Either works — you can still use a custom domain later.
  4. Set it to Public
    Public repositories can be hosted for free with GitHub Pages.
  5. Create index.html
    In your repository:
    • Click Add fileCreate new file
    • Name it exactly: index.html
    • Copy/paste the template from below
    • Scroll down → click Commit changes
  6. Create folders in GitHub
    There isn’t always a “New folder” button. Instead:
    • Click Add fileCreate new file
    • In the filename box type: pages/about.html
    • This creates a folder called pages automatically
    • Paste the template → commit changes
  7. Create your CSS file
    Make stylesheets/base.css using the same method:
    • Create new file: stylesheets/base.css
    • Paste the CSS template from below
    • Commit changes
  8. Create JavaScript (optional)
    Make js/main.js:
    • Create new file: js/main.js
    • Paste the JS template from below
    • Commit changes
  9. Turn on GitHub Pages
    In the repository:
    • Go to Settings
    • Click Pages in the left sidebar
    • Under Build and deployment, select Deploy from a branch
    • Select branch: main and folder: / (root)
    • Click Save
  10. Visit your website
    GitHub will show a website link in the Pages settings. It may take a minute to go live, then refresh.

Optional: yourname.com instead of github.io

Your site works perfectly on a free GitHub address. If you want, you can buy a domain like yourname.com and connect it to GitHub Pages.

Step 1: buy a domain

Buy a domain from a provider you trust (examples: Namecheap, GoDaddy, Cloudflare Registrar, etc.). Search for the domain you want and purchase it.

Step 2: add the domain to GitHub Pages

  1. Repository → SettingsPages
  2. Find Custom domain
  3. Type: yourname.com (or www.yourname.com)
  4. Save

Step 3: update DNS at your domain provider

DNS is what “points” your domain to GitHub. Your domain provider has a DNS page. GitHub Pages will show you exactly what to add. Commonly you add:

DNS changes can take time to spread across the internet. GitHub will confirm when it’s connected.

Templates (copy and paste)

Below are starter templates for every file. They contain no personal content and are designed to be reused. Copy each block into the matching file in your repository.

Recommended order: 1) index.html, 2) stylesheets/base.css, 3) pages in pages/, 4) js/main.js.

Template 1 — index.html (homepage)

This file goes in the root of your repository (not inside pages/). It links to the shared CSS and JavaScript using paths that work from the root.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>Home</title>
  <link rel="stylesheet" href="stylesheets/base.css"/>
</head>
<body>

  <div id="scroll-progress"></div>

  <header class="site-header fade-in">
    <div class="header-inner">
      <a class="brand" href="index.html">Your Name</a>

      <nav class="site-nav">
        <ul class="nav-pill">
          <li><a class="active" href="index.html">Home</a></li>
          <li><a href="pages/projects.html">Projects</a></li>
          <li><a href="pages/cv.html">CV</a></li>
          <li><a href="pages/about.html">About</a></li>
          <li><a href="pages/more.html">More</a></li>
        </ul>
      </nav>
    </div>
  </header>

  <main class="container">
    <h1 class="page-title fade-in">Welcome</h1>

    <section class="card fade-in">
      <p style="max-width:70ch;">
        This is a simple starter website you can host for free using GitHub Pages.
        Replace this text with your own introduction.
      </p>

      <p style="max-width:70ch; margin-top:14px;">
        Tip: keep paragraphs short and readable. Use clear headings and consistent navigation.
      </p>

      <p style="margin-top:14px;">
        <a class="btn" href="pages/more.html">Learn how to build this</a>
      </p>
    </section>
  </main>

  <footer>
    <div>© Your Name</div>
  </footer>

  <script src="js/main.js"></script>
</body>
</html>

Template 2 — pages/about.html

This file goes inside the pages/ folder. Because it is one folder deeper, it links to CSS/JS using ../.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>About</title>
  <link rel="stylesheet" href="../stylesheets/base.css"/>
</head>
<body>

  <div id="scroll-progress"></div>

  <header class="site-header fade-in">
    <div class="header-inner">
      <a class="brand" href="../index.html">Your Name</a>

      <nav class="site-nav">
        <ul class="nav-pill">
          <li><a href="../index.html">Home</a></li>
          <li><a href="projects.html">Projects</a></li>
          <li><a href="cv.html">CV</a></li>
          <li><a class="active" href="about.html">About</a></li>
          <li><a href="more.html">More</a></li>
        </ul>
      </nav>
    </div>
  </header>

  <main class="container">
    <h1 class="page-title fade-in">About</h1>

    <section class="card fade-in">
      <p style="max-width:70ch;">
        Write a short introduction here: who you are, what you do, and what you care about.
      </p>

      <p style="max-width:70ch; margin-top:14px;">
        You can add links, a short CV summary, interests, or anything else.
      </p>
    </section>
  </main>

  <footer>
    <div>© Your Name</div>
  </footer>

  <script src="../js/main.js"></script>
</body>
</html>

Template 3 — pages/projects.html

This is a simple projects page that uses repeated “project cards”. You can add as many as you want.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>Projects</title>
  <link rel="stylesheet" href="../stylesheets/base.css"/>
</head>
<body>

  <div id="scroll-progress"></div>

  <header class="site-header fade-in">
    <div class="header-inner">
      <a class="brand" href="../index.html">Your Name</a>

      <nav class="site-nav">
        <ul class="nav-pill">
          <li><a href="../index.html">Home</a></li>
          <li><a class="active" href="projects.html">Projects</a></li>
          <li><a href="cv.html">CV</a></li>
          <li><a href="about.html">About</a></li>
          <li><a href="more.html">More</a></li>
        </ul>
      </nav>
    </div>
  </header>

  <main class="container">
    <h1 class="page-title fade-in">Projects</h1>

    <section class="card fade-in">
      <h2 style="margin-bottom:8px;">Project Title</h2>
      <p style="max-width:70ch;">
        Write 3–6 sentences explaining what you did, what tools you used, and the result.
      </p>
      <p style="margin-top:12px;">
        <a href="#">Optional link</a>
      </p>
    </section>

    <div style="height:16px;"></div>

    <section class="card fade-in">
      <h2 style="margin-bottom:8px;">Another Project</h2>
      <p style="max-width:70ch;">
        Add more project cards like this. Keep the layout consistent.
      </p>
    </section>

  </main>

  <footer>
    <div>© Your Name</div>
  </footer>

  <script src="../js/main.js"></script>
</body>
</html>

Template 4 — pages/cv.html

This page includes a button to download a CV PDF. If you don’t have a PDF yet, remove the button. If you do, place it in assets/ as cv.pdf.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>CV</title>
  <link rel="stylesheet" href="../stylesheets/base.css"/>
</head>
<body>

  <div id="scroll-progress"></div>

  <header class="site-header fade-in">
    <div class="header-inner">
      <a class="brand" href="../index.html">Your Name</a>

      <nav class="site-nav">
        <ul class="nav-pill">
          <li><a href="../index.html">Home</a></li>
          <li><a href="projects.html">Projects</a></li>
          <li><a class="active" href="cv.html">CV</a></li>
          <li><a href="about.html">About</a></li>
          <li><a href="more.html">More</a></li>
        </ul>
      </nav>
    </div>
  </header>

  <main class="container">
    <h1 class="page-title fade-in">CV</h1>

    <section class="card fade-in">
      <p style="max-width:70ch;">
        Add a short summary of your background here.
      </p>

      <p style="margin-top:14px;">
        <a class="btn" href="../assets/cv.pdf" download>Download CV (PDF)</a>
      </p>

      <p style="max-width:70ch; margin-top:14px; color: var(--muted);">
        Tip: if the download button does not work, check the file path and make sure your PDF is inside the assets folder.
      </p>
    </section>
  </main>

  <footer>
    <div>© Your Name</div>
  </footer>

  <script src="../js/main.js"></script>
</body>
</html>

Template 5 — pages/more.html (minimal page)

If you’re copying this guide, you already have a more.html. But if you want a clean “More” page without the big tutorial, use this minimal template.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>More</title>
  <link rel="stylesheet" href="../stylesheets/base.css"/>
</head>
<body>

  <div id="scroll-progress"></div>

  <header class="site-header fade-in">
    <div class="header-inner">
      <a class="brand" href="../index.html">Your Name</a>
      <nav class="site-nav">
        <ul class="nav-pill">
          <li><a href="../index.html">Home</a></li>
          <li><a href="projects.html">Projects</a></li>
          <li><a href="cv.html">CV</a></li>
          <li><a href="about.html">About</a></li>
          <li><a class="active" href="more.html">More</a></li>
        </ul>
      </nav>
    </div>
  </header>

  <main class="container">
    <h1 class="page-title fade-in">More</h1>

    <section class="card fade-in">
      <p style="max-width:70ch;">
        Add anything you want here: links, resources, FAQs, guides, etc.
      </p>
    </section>
  </main>

  <footer>
    <div>© Your Name</div>
  </footer>

  <script src="../js/main.js"></script>
</body>
</html>

Template 6 — stylesheets/base.css (shared styling)

This single CSS file controls the look of every page (fonts, colours, layout). All pages link to it. When you change this file, your whole website updates.

:root{
  --bg:#F8FAFC;
  --surface:#FFFFFF;
  --text:#0F172A;
  --muted:#475569;
  --border:#E2E8F0;

  --accent:#1D4ED8;
  --accent-hover:#1E40AF;

  --header-bg:#0B1220;
  --header-text:#FFFFFF;

  --radius:14px;
  --container:980px;

  --s1:8px;
  --s2:16px;
  --s3:24px;
  --s4:40px;

  --font: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial,
          "Apple Color Emoji","Segoe UI Emoji";
}

*{margin:0;padding:0;box-sizing:border-box}
html,body{overflow-x:hidden}
body{
  font-family:var(--font);
  background:var(--bg);
  color:var(--text);
  line-height:1.7;
}

.container{
  max-width:var(--container);
  margin:0 auto;
  padding:0 var(--s2);
}

.site-header{
  background:var(--header-bg);
  position:sticky;
  top:0;
  z-index:1000;
  box-shadow:0 1px 0 rgba(255,255,255,0.08);
}
.header-inner{
  max-width:1100px;
  margin:0 auto;
  padding:12px 16px;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:12px;
}
.brand{
  color:var(--header-text);
  text-decoration:none;
  font-weight:800;
  letter-spacing:.2px;
}
.site-nav .nav-pill{
  list-style:none;
  display:flex;
  gap:10px;
  padding:6px 8px;
  border-radius:9999px;
  background:rgba(255,255,255,0.06);
}
.site-nav .nav-pill a{
  color:var(--header-text);
  text-decoration:none;
  padding:8px 12px;
  border-radius:9999px;
  opacity:.92;
  font-weight:650;
  transition:background .2s ease, transform .15s ease, opacity .2s ease;
}
.site-nav .nav-pill a:hover{
  background:rgba(255,255,255,0.10);
  transform:translateY(-1px);
  opacity:1;
}
.site-nav .nav-pill a.active{
  background:rgba(255,255,255,0.16);
  opacity:1;
  outline:1px solid rgba(255,255,255,0.18);
}

.page-title{
  text-align:center;
  font-size:clamp(1.9rem,3.2vw,2.4rem);
  font-weight:900;
  letter-spacing:-0.01em;
  margin:var(--s4) 0 var(--s3);
}
.page-title::after{
  content:"";
  display:block;
  width:96px;
  height:2px;
  background:var(--border);
  margin:var(--s1) auto 0;
  border-radius:999px;
}

.card{
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  box-shadow:0 12px 30px rgba(15,23,42,0.08);
  padding:var(--s3);
}

a{color:var(--accent);text-decoration:none}
a:hover{color:var(--accent-hover);text-decoration:underline;text-decoration-thickness:2px}
a:focus-visible{
  outline:3px solid rgba(29,78,216,0.25);
  outline-offset:3px;
  border-radius:6px;
}

.btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  padding:12px 16px;
  border-radius:9999px;
  background:var(--accent);
  color:#fff;
  font-weight:850;
  text-decoration:none;
  border:1px solid transparent;
  box-shadow:0 12px 26px rgba(29,78,216,0.18);
  transition:transform .15s ease, background .15s ease;
}
.btn:hover{background:var(--accent-hover);transform:translateY(-1px);text-decoration:none}
.btn:active{transform:translateY(0)}

footer{
  margin-top:var(--s4);
  padding:var(--s3) 0;
  border-top:1px solid var(--border);
  color:var(--muted);
  text-align:center;
}

/* scroll progress bar */
#scroll-progress{
  position:fixed;
  top:0;left:0;
  height:3px;
  width:0%;
  background:var(--accent);
  z-index:2000;
  transition:width .15s ease-out;
}

/* fade-in */
.fade-in{
  opacity:0;
  transform:translateY(16px);
  transition:opacity .6s ease-out, transform .6s ease-out;
  will-change:opacity,transform;
}
.fade-in.visible{opacity:1;transform:translateY(0)}

@media (max-width:760px){
  .header-inner{flex-direction:column;align-items:flex-start}
  .site-nav .nav-pill{flex-wrap:wrap}
}

@media (prefers-reduced-motion: reduce){
  *{transition:none !important; animation:none !important;}
}

Template 7 — js/main.js (scroll bar + fade-in)

This file controls the scroll progress bar and fade-in animation. If you don’t want animations, you can delete this file and remove the script tags from your HTML pages.

// Scroll progress bar
window.addEventListener("scroll", () => {
  const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
  const scrollHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
  const progress = scrollHeight > 0 ? (scrollTop / scrollHeight) * 100 : 0;

  const bar = document.getElementById("scroll-progress");
  if (bar) bar.style.width = progress + "%";
});

// Fade-in on scroll
document.addEventListener("DOMContentLoaded", () => {
  const observer = new IntersectionObserver((entries, obs) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        entry.target.classList.add("visible");
        obs.unobserve(entry.target);
      }
    });
  }, { threshold: 0.1 });

  document.querySelectorAll(".fade-in").forEach(el => observer.observe(el));
});