How I prototype a Web Page
By Flavio Copes
The simple workflow I use to prototype a web page: set up Tailwind with PostCSS, run a watch task, and live-reload the browser with browser-sync as I edit.
This is a historical Tailwind CSS 1 and PostCSS 7 workflow. Keep it for an older project, but do not use this setup to start a new one.
When I prototype a web page I use a small setup: Tailwind compiled through PostCSS, a watch task that rebuilds the CSS on save, and browser-sync to reload the browser for me. Here’s the whole thing.
Sometimes I work on single web pages for my projects.
Maybe I want to redesign the blog. Maybe it’s a landing page for a new project.
I don’t want a full framework for this. No build tool config to fight, no components, no routing. One HTML file, one CSS pipeline, and a fast feedback loop. The goal is to see every change in the browser within a second of saving.
This is the process I use.
Setting up Tailwind and PostCSS
I like to use Tailwind to build prototypes, because I can style everything with classes right in the HTML, without switching files.
I set up all the pipeline for Tailwind and PostCSS first:
Create postcss.config.js:
const purgecss = require('@fullhuman/postcss-purgecss')
const cssnano = require('cssnano')
module.exports = {
plugins: [
require('tailwindcss'),
require('autoprefixer'),
cssnano({ preset: 'default' }),
purgecss({
content: ['./layouts/**/*.html', './src/**/*.vue', './src/**/*.jsx'],
defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
})
]
}
Each plugin has a job. Tailwind generates the utility classes, autoprefixer adds vendor prefixes, cssnano minifies, and purgecss deletes every class I don’t actually use in my HTML. Without purging, the generated CSS file is huge.
Create tailwind.config.js:
module.exports = {
theme: {},
variants: {},
plugins: [],
}
It’s empty, but Tailwind wants it to exist. This is also where I’d add custom colors later.
Create a tailwind.css file:
@tailwind base;
@tailwind components;
@tailwind utilities;
Create a package.json file:
{
"main": "index.js",
"scripts": {
"build:css": "postcss tailwind.css -o output.css",
"watch": "watch 'npm run build:css' ./layouts"
},
"dependencies": {
"@fullhuman/postcss-purgecss": "^1.3.0",
"autoprefixer": "^9.7.1",
"cssnano": "^4.1.10",
"postcss": "^7.0.21",
"tailwindcss": "^1.1.3",
"watch": "^1.0.2"
}
}
Run npm install to pull everything in.
The build:css script compiles tailwind.css into output.css, the file the page will link to. The watch script reruns that build every time something in layouts changes.
Create a layouts/index.html page, and add your HTML.
Watching and live reloading
Start a terminal shell, go to the project folder and run:
npm run watch
Then I make the browser automatically sync the changes every time I save the page or the CSS is regenerated, using browser-sync, a great utility you can install using npm install -g browser-sync:
browser-sync start --server --files "."
This starts a server and also automatically opens the browser and points at the newly created local web server. The --files "." flag tells it to reload whenever any file changes, including the regenerated output.css.
Now I open VS Code and the browser side by side, and I start prototyping!
When classes mysteriously don’t work
One thing to watch out for: purgecss only keeps classes it finds in the content paths.
If you put an HTML file outside layouts, its classes get stripped from the CSS, and the page renders unstyled. It looks like Tailwind is broken. It isn’t, the classes were purged.
The fix: add the file’s path to the content array, or remove the purgecss plugin entirely while prototyping. The big CSS file doesn’t matter until you ship.
Related posts about tutorial: