Just HTML/css, no JavaScript, using Zola, pico.css, and CloudFlare

Introduction

It is 2026, so why on earth would anyone want the most basic website using only HTML/css for their blog? Well, I can list a few reasons:

In this article, I will go through my personal journey of building a simple blog site for myself. I will start with the requirements, search for the right building blocks, and show you the step-by-step instructions to build the website.

My Requirements

Here are my requirements for the simple personal website solution in 2026:

Functional Requirements

Non-Functional Requirements:

The Building Blocks

Zola

Zola is a powerful, yet lightweight, static site generator written in Rust. It distinguishes itself by compiling content quickly and having minimal external dependencies, offering a single-executable solution for creating static websites. Unlike more complex platforms, Zola provides all the necessary features—such as templates, Markdown parsing, and a built-in server—without the bloat, making it an excellent choice for a simple, fast, and maintainable minimalist blog.

https://www.getzola.org/

Pico.css

Pico.css is a minimalist CSS framework designed for creating clean, simple, and responsive websites with minimal effort. It embraces the philosophy of "no-class" styling, meaning it primarily uses native HTML elements (like <h1>, <table>, <button>) to apply modern, aesthetically pleasing styles, effectively turning semantic HTML into a ready-to-use modern interface. It is light, fast, and fully accessible, making it an ideal choice for a minimalist blog where speed, simplicity, and a clean aesthetic are paramount.

https://picocss.com/


CloudFlare Workers (Previously Pages)

We know Cloudflare primarily as the most important content delivery network (CDN). Handling over 20% of all internet traffic and powering approximately 50% of managed DNS zones globally, plus fending off most DDoS attacks, its massive scale provides industry-leading performance and security. In short, it will be more than good enough for my paltry little blog site.

Cloudflare Pages provides a platform for front-end developers to collaboratively build, deploy, and host static websites. It simplifies the deployment pipeline by integrating directly with Git repositories, automatically building the site (using static site generators like Zola) upon code commits, and instantly deploying it to Cloudflare's global edge network. This ensures high performance, reliability, and security with zero-cost hosting for basic usage, aligning perfectly with the goal of a fast, free, and maintainable minimalist blog. Besides, its free plan is sufficient for most static websites.

https://pages.cloudflare.com/

However, Cloudflare Pages has been “migrated” to Cloudflare Workers, which is a more generic and more powerful application deployment tool. Unfortunately, the native support for Zola has ended, thus we will cover the additional tweaks we need to add to make the automatic build and deployment work for our static website using Zola.

Getting Your Content Ready

The Lazy Way

I downloaded all my published articles and converted them to Zola format using an OpenClaw agent. You can also vibe code some scripts to do it. So, this will probably be the easiest approach, and you can skip the rest of this chapter if you do that.

Prepare Markdown

In order to use Zola, first I need to get all my content into the right format:

If you are unfamiliar with markdown, you can head to this website for the most basic syntax. It is really easy, and you can get by with just the 10 most-used marks.

https://www.markdownguide.org/

There are plenty of tools to convert your existing Google Doc or Microsoft Doc(x) files or HTML pages into markdown.

Zola Specific

First, you set up the Zola

# Install Zola (macOS)
brew install zola

# Install Zola (Linux)
# Download from https://github.com/getzola/zola/releases

# Run dev server
zola serve

# Build for production
zola build

After that, your local file structure will look like this:

bruces-blog/
├── config.toml          # Site configuration
├── content/
│   ├── _index.md        # Home page
│   ├── about.md         # About page
│   └── blog/
│       ├── _index.md    # Blog listing
│       └── *.md         # Blog posts
├── templates/           # Tera templates
├── static/css/          # Custom CSS
└── public/              # Generated site (git-ignored)

Next, you add small snippets of additional metadata into each blog post’s markdown files:

+++
title = "Post Title"
date = 2026-02-11
description = "Brief description"
[taxonomies]
tags = ["tag1", "tag2"]
+++

Your content here. Use `<!-- more -->` for summary break.

Note on use `<!-- more -->` for summary break. Anything before this summary break will appear in the preview of the article along with the title.

You definitely want to install and run the zola serve locally (in my case, macOS) to test out the site before committing the website to a wider audience. For example, I found one hiccup.

Zola version 0.22.1 is incompatible with older versions of config.toml, especially the markdown themes and highlighting. So, the modified config.toml will look like this:

# Bruce's Personal Blog
# Zola configuration

base_url = "https://zbruceli.org"
title = "Bruce Li"
description = "Personal blog and thoughts"
default_language = "en"
# No theme - using custom templates

# Compilation settings
compile_sass = false
build_search_index = false
generate_feeds = true
feed_filenames = ["rss.xml"]

[markdown]
[markdown.highlighting]
theme = "github-light"
error_on_missing_language = false

[extra]
author = "Bruce Li"

Git/GitHub for Version Management

Since we will be using GitHub repository linking directly to Cloudflare Workers, we need to:

You can find git/GitHub tutorial here:

https://product.hubspot.com/blog/git-and-github-tutorial-for-beginners

Personal Domain Name

I reckon it is important for any personal blog to have its own unique domain name, for example, in my case, zbruceli.org. You can probably buy it from GoDaddy or any other prominent domain name vendors.

I bought my domain from Google Domains, which eventually became part of Squarespace. But since I will be using Cloudflare to manage my DNS resolving and my website caching, I need to do a few things.

Add a Domain to Cloudflare

Add the domain to Cloudflare.

Find both name servers: they will be like nnnn.ns.cloudflare.com. You will need them for the configuration in the next step.

Update Domain Records on Squarespace

Basically, you will still pay Squarespace for the domain name, but everything else will be handled by Cloudflare from now on.

Configure name servers, delete all other servers (use 4 Google name servers).


Delete all DNS records on Squarespace, since DNS will be managed by Cloudflare now.

Add www Redirect

Add a CNAME for www to redirect to the root domain, since some browsers automatically add the www prefix to my website. I want to make sure both www.zbruceli.org and zbruecli.org land on the same page.

Hosting and Deployment

Now, you should have the following ready:

We will move on to starting a new Cloudflare Worker that connects to your blog repository, auto-builds your website, and deploys on Cloudflare's global network.

Make Zola Work Again in Cloudflare Worker

Since the “upgraded” Cloudflare Worker no longer natively supports Zola, we need a workaround. I followed the following tutorial to add wrangler.toml (tells Cloudflare how to deploy the website) and build.sh (tells Cloudflare how to build the website using Zola)

https://pablomarti.dev/deploy-zola-to-clouflare-workers/

My build.sh looks like this. Make sure you make the file executable: chmod +x build.sh

#!/usr/bin/env bash

main() {
  ZOLA_VERSION=0.22.1

  export TZ=US/Pacific

  # Install Zola if not already in PATH
  if ! command -v zola &> /dev/null; then
    echo "Installing Zola ${ZOLA_VERSION}..."
    curl -sLJO "https://github.com/getzola/zola/releases/download/v${ZOLA_VERSION}/zola-v${ZOLA_VERSION}-x86_64-unknown-linux-gnu.tar.gz"
    mkdir "${HOME}/.local/zola"
    tar -C "${HOME}/.local/zola" -xf "zola-v${ZOLA_VERSION}-x86_64-unknown-linux-gnu.tar.gz"
    rm "zola-v${ZOLA_VERSION}-x86_64-unknown-linux-gnu.tar.gz"
    export PATH="${HOME}/.local/zola:${PATH}"
  else
    echo "Zola already installed, skipping installation..."
  fi

  # Verify installations
  echo "Verifying installations..."
  echo Zola: "$(zola --version)"

  # Build the site
  echo "Building the site..."
  zola build --minify
}

set -euo pipefail
main "$@"

My wrangler.toml looks like this. I need to remove the www pattern since it is already configured as a CNAME in the DNS record.

name = "zola-worker"
compatibility_date = "2026-02-11"

routes = [
  { pattern = "zbruceli.org", custom_domain = true }
]

[build]
command = './build.sh'

[assets]
directory = "./public/"
not_found_handling = "404-page"

Create Cloudflare Worker

You can easily follow the “Cloudflare Workers & Pages” page to add a new worker, connect your worker to your GitHub blog repo, and use default settings (you do NOT need to specify build commands since wrangler.toml already specifies this)

After you create the worker, it should automatically build and deploy. But there is one extra step: associate your personal domain with this worker by “add custom domain”:

One More Thing

To strictly follow my rule of "No Third Parties," I should not link to Pico.css via a public CDN (like jsDelivr). Instead, I should download the pico.min.css file, put it under the /statis/css folder, and host it inside my Zola site. This ensures Cloudflare caches it along with your HTML.

https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css

Conclusions

Now you have it, the minimalist personal blog website built in 2026 that can handle millions of views per day (if you get that popular). It is simple and elegant, super fast, and renders on my phone browser just fine. I can manage my blog content fairly easily, and they live on both local files and GitHub for the rest of human history. Nobody can paywall your content or deplatform you. And for the time being, it costs me nothing.