📖 Original Reference: Originally published with full semantic markup templates and Cloudflare DNS setup at alexmaina.dev/guida_sito.
In an era where personal portfolio sites and simple blogs pull in 250MB of node_modules, hydrate megabytes of JavaScript, and suffer from layout shifts, going back to pure semantic HTML5, modern CSS, and vanilla JS feels like a superpower.
By hosting static files on GitHub Pages paired with Cloudflare's Global Edge Network, you get:
- Perfect 100/100 Lighthouse performance on mobile and desktop.
- Sub-50ms Time to First Byte (TTFB) worldwide.
- Enterprise DDoS mitigation, automatic HTTP/3, and free SSL certificates.
- \$0/month forever hosting costs.
Here is how to set up the entire stack from scratch.
1. The Modern Zero-Framework Project Structure
You do not need a bloated build tool to get responsive layouts, dark mode, and offline caching:
my-website/
├── index.html # Clean semantic HTML5
├── style.css # Modern CSS with Custom Properties (variables)
├── script.js # Vanilla JS for interactive widgets & theme toggle
├── sw.js # Lightweight Service Worker for offline support
├── robots.txt # Search engine crawler rules
├── sitemap.xml # XML sitemap for SEO indexing
└── .github/
└── workflows/
└── deploy.yml # Automated linting and deployment
2. Flash-Free Dark Mode in Modern CSS
The most common bug in static websites is the dark mode flash: the page renders bright white for 100ms before JavaScript executes and toggles the dark theme.
To prevent the flash completely, place an inline, blocking script in the <head> before any CSS renders:
<head>
<meta charset="UTF-8">
<title>Developer Portfolio</title>
<!-- âš¡ Prevents theme flicker before CSS paints -->
<script>
(function() {
const savedTheme = localStorage.getItem('theme') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
document.documentElement.setAttribute('data-theme', savedTheme);
})();
</script>
<link rel="stylesheet" href="style.css">
</head>
In style.css, leverage CSS custom properties:
:root {
--bg-color: #ffffff;
--text-color: #1e293b;
--accent-color: #0284c7;
}
[data-theme="dark"] {
--bg-color: #0b0f19;
--text-color: #f1f5f9;
--accent-color: #38bdf8;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: system-ui, -apple-system, sans-serif;
transition: background-color 0.2s ease, color 0.2s ease;
}
3. Offline Caching with a Vanilla Service Worker (sw.js)
Add native offline capability and instant page transitions using the Cache API:
// sw.js
const CACHE_NAME = 'site-cache-v1';
const ASSETS_TO_CACHE = [
'/',
'/index.html',
'/style.css',
'/script.js',
'/offline.html'
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => cache.addAll(ASSETS_TO_CACHE))
);
self.skipWaiting();
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
// Return cached asset or fetch from network
return response || fetch(event.request).catch(() => caches.match('/offline.html'));
})
);
});
Register it in script.js:
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js');
});
}
4. Pairing GitHub Pages with Cloudflare DNS & SSL
Deploying your site to a custom domain (e.g., alexmaina.dev) with Cloudflare provides edge caching and HTTPS enforcement:
- In your GitHub repository settings, go to Pages → Source: Deploy from a branch (
main/ root). - Enter your custom domain in the Custom domain field (creates a
CNAMEfile in your repo). - In your Cloudflare Dashboard:
- Add a
CNAMErecord for@pointing to<username>.github.io. - Add a
CNAMErecord forwwwpointing to<username>.github.io. - Toggle the proxy status to Orange Cloud (Proxied).
- Add a
- Under SSL/TLS, set encryption mode to Full (Strict).
5. Automated CI/CD Validation with GitHub Actions
Catch broken links, unclosed tags, and syntax errors automatically on every git push:
Create .github/workflows/deploy.yml:
name: Deploy & Validate Static Site
on:
push:
branches: [ main ]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate HTML5 Syntax
uses: Cyb3r-Jak3/html5validator-action@v7.2.0
with:
root: .
blacklist: "node_modules"
- name: Check for Broken Links
uses: gaurav-nelson/github-action-markdown-link-check@v1
with:
use-quiet-mode: 'yes'
Results & Benchmarks
- Performance: 100/100
- Accessibility: 100/100
- Best Practices: 100/100
- SEO: 100/100
- Monthly Infrastructure Cost: \$0.00
Conclusion
Before reaching for complex React/Next.js scaffolds for personal portfolios, documentation sites, or small marketing landing pages, consider the elegance of vanilla web technologies. It is simpler to maintain, faster for your users, and immune to framework deprecation cycles.
Author: Alessandro Mainardi — Computer Engineering Student @ UniBo & Full-Stack Developer. Explore the live implementation at alexmaina.dev.
Top comments (0)