In 2020, I rediscovered the enjoyment of building a website with plain ol’ HTML, CSS, and JavaScript — no transpilin’, no compilin’, no build tools other than my hands on the keyboard.
Seeing as my personal brand could be summed up “so late to the game that the stadium has been demolished,” I decided to start a podcast in 2020. It’s the podcast of my agency, Clearleft, and it has been given the soaringly imaginative title of The Clearleft Podcast. I’m really pleased with how the first season turned out. I’m also really pleased with the website I put together for it.
The website isn’t very big, though it will grow with time. I had a think about what the build process for the site should be and after literally seconds of debate, I settled on a build process of none. Zero. Nada.
This turned out to be enormously liberating. It felt very hands-on to write the actual HTML and CSS that will be delivered to end users, without any mediation. I felt like I was getting my hands into the soil of the site.

CSS has evolved so much in recent years—with features like calc()
and custom properties—that you don’t have to use preprocessors like Sass. And vanilla JavaScript is powerful, fully-featured, and works across browsers without any compiling.
Don’t get me wrong—I totally understand why complicated pipelines are necessary for complicated websites. If you’re part of a large team, you probably need to have processes in place so that everyone can contribute to the codebase in a consistent way. The more complex that codebase is, the more technology you need to help you automate your work and catch errors before they go live.
But that setup isn’t appropriate for every website. And all those tools and processes that are supposed to save time sometimes end up wasting time further down the road. Ever had to revisit a project after, say, six or twelve months? Maybe you just want to make one little change to the CSS. But you can’t because a dependency is broken. So you try to update it. But it relies on a different version of Node. Before you know it, you’re Bryan Cranston changing a light bulb. You should be tweaking one line of CSS but instead, you’re battling entropy.
Whenever I’m tackling a problem in front-end development, I like to apply the principle of least power: choose the least powerful language suitable for a given purpose. A classic example would be using a simple HTML button element instead of trying to recreate all the native functionality of a button using a div with lashings of ARIA and JavaScript. This year, I realized that this same principle applies to build tools too.
Instead of reaching for all-singing all-dancing toolchain by default, I’m going to start with a boring baseline. If and when that becomes too painful or unwieldy, then I’ll throw in a task manager. But every time I add a dependency, I’ll be limiting the lifespan of the project.
My new year’s resolution for 2021 will be to go on a diet. No more weighty node_modules
folders; just crispy and delicious HTML, CSS, and JavaScript.
Amen.
One problem is that so many cool things (like libraries, components, etc.) nowadays use and, therefore, drag along with them all these galaxies of dependencies which you might be forced at least to read about and understand a bit. Like… ‘Oh, that’s a nice, little, lightweight, starter code base for my site! I think I wanna use it. Maaan… that’s SASS… All I wanted was CSS…’
It does not have to be all or nothing. Recently I did a small PWA app in lit-element. Very thin layer focused on webcomponents. Interpolation similar to react. No runtime dependencies, but a good dev experience.
Most libraries and components are available via CDN, so npm is still avioidable.
I feel the same!
That said – I’ve regained my joy of front-end coding when I discovered svelte.
Sounds like Hugo is the solution. A single binary provides enough power to replace entire tech stacks and servers.
HTML+CSS+JS with Markdown or HTML for content source. My personal mod to this is to use TailwindCSS and AlpineJS for style and JS goodness. Also, I just referred to the Bryan Cranston scene this morning about 2 hours before seeing your article, someone is listening.
As a newbie to the game I’ve often wanted to stick to the tools available by default.
Mostly because of fear and a lack of understanding. But now having dabbled with build tools, modules, and don’t be judgy…Bootstrap and the like, I’ve found a new love for the simple additions.
I haven’t had enough experience with the ‘old code, old projects: broken dependencies’ yet but I know that’s coming.
Because of my love for default, I do sometimes just use standard HTML, JS, and CSS but the twinkling eyes of depdencies like SelectJS, the grinning face of Vue and the enticing nature of Svelte & tools like Tailwind…they’re simply irresistible.
I enjoyed the article
I’ve really tried to get into svelte but then I feel like I’m going to end up in niche hell and choose something else. I start running scared when I realised how hard it was to set up typescript because I want static typing. Etc.
CSS and vanilla Javascript can get you so much of the way in one-person projects it’s beautiful. Onwards into the buildstep free future! . . . Except maybe the lure of Svelte will keep me installing node modules for a while longer
Amen.
One more thing: Avoiding long dependency chains isn’t just good for staying out of dependency hell, it’s also a godsend for users with slow connections. On slow WiFi, many pages with “modern” build pipelines take 10+ seconds to load.
If you hate bloated sites, you’ll probably like this page https://idlewords.com/talks/website_obesity.htm
Never heard of that “principle of the least power”, but that resonates to me with the one and only approach to ever work for whatever web piece you’re attempting to build — the “progressive enhancement”. Too bad web development has quickly become a quest for the most complex workflow, rather than sticking to its original purpose of communicating.
Yes. A billion times: yes, please. So called modern web development absolutely ruined my job for me. So much has been foisted on me by industry groupthink, but many of those tools I willing adopted because at first I felt the features were worth it. A few years later, I realized I didn’t create user experiences anymore. I just fought with tools and dependency integrations. I would give almost anything to go back.
I so feel this right now. I’ve been struggling for weeks on a new frontend methodology to replace the old angularjs I’ve been using. All the react, vue, typescript, compiling, transpiling, troubleshooting code I didn’t actually write has me so frustrated. Back to basics with pure html, css, and tiny JS libraries I can directly link to via cdn for a bit of fancy stuff seems to be what I’ve been looking for.
Sounds like heaven.
I’m a front-end web dev.
Given that the final outcome of our work is HTML, CSS and JavaScript, what on Earth am I doing battling with Docker and Azure?!
Feel good to hear that
How do you maintain elements suchs as navigation bars? So you won’t havr to manually modify these for each page individually?
Thanks.
Now I can trust humanity.
https://john-doe.neocities.org/
That’s great for a single page website. Once you have two pages you are repeating yourself and having to make changes to multiple files now for the same update. A process for at least handling partial templates is required for most websites.
Jeremy can correct me if I’m wrong, but I don’t the article is against the idea of partial templates.
For my own needs, the rule of least resistance would be using a PHP on an absolute basic LAMP stack.
A couple of PHP includes and I’m done – no compilation necessary and still a zero build process.
And the same goes for server side scripting.
I wonder if this is really the experience that folks are having these days? Sure, I’ve been burned more than once, assuming a project from a few years ago would be easy to update, but now with pretty much zero or very little config for webpack/rollup, is that still really a problem?
Definitely still happens.
Had to remind dev team not to run
npm update
and only runnpm install
on pulls.Some random library changes and you’re chasing it down half a day.
Sometimes I do wonder what is actually happening with modern front end dev when I see a 100MB
node_modules
folder…@Jeremy Keith exactly
Finally, I have found some more dinosaurs out here. We have a team of 8 people who are always coming up with newer and better ideas and libraries. In the beginning I everything is fun, but after a period of time, all the dependencies en updates are killing my joy in the work. These tools tend to take more time then they save me sometimes. I’m glad every once in a while a small project can be done with some good old HTML, CSS, JS (and some PHP).
So true!
I totally agree!
I even took the time during covid quarantines to write 2 open source projects that rely only on proxies, thus leaving the JS code completely vanilla.
The docs are a work in progress, but you can already use it, for example for 2 way binding, without changing your current project’s native code.
In the future you are not bounded to my libraries and u can ditch them at any point without breaking your code.
https://www.noaml.in/projects
Just my words, KISS, nothing more. Thank you for this post!
Totally fine for a simple non interactive onepager. Add dynamic forms, non trivial UI and you’re in trouble :)
Totally agree! I’ve done a lot of “vanilla” projects this year – and one thing I noticed about all those: They all get “100%” in performance in Lighthouse – simply because there’s not a large overhead of unused CSS and JS.
Oh yes, web developers discover that can still build powerful webs without using 50 different technologies and using all the system resources
This would also mean no eslint, prettier and stylint.
Just use dreamweaver and be done with it.
Download your dependencies by yourself and include the versions offline in your project files so you don’t have to update all the time.
Adding a dependency doesn’t limit the life span of a site! It only limits the life span of your liking of using that library in your project, but the same goes for your handwritten code that you may dislike when you leave it and come back to it after a while and wonder “why did I write it that way?!”.
After adding a specific version of a lib, it can stay that way forever, just like the code you hand wrote, thanks to stable web APIs.
You can even commit node_modules into the repo if you fear a dependency may disappear.
I can agree, but at this point i want to ask: what if i need to do some stuff like css prefixing, minifying etc?
I can agree about the bloatness of a bundler, but if i need an external library, i need to put the CDN (losing caching advantages) or manually download the stuff, which is possible but tedious.
And please, don’t tell me about how much CSS is awesome: CSS is utterly unmantainable without something like SASS, unless you make something very KISS (and a lot of designers don’t make KISS layouts :P).
Maybe snowpack is the right path, but i still think we need some kind of tooling. Maybe a simpler one, but a tool.
I can understand the concept that there are situations where you may need to npm your life. Nonetheless everytime I stumble into it I find myself swearing loudly with my friends because how much complicated want to be things that should be trivial. I simply hate it. Maybe I’ve never encountered one of those situations yet, or maybe I’m so fond of your final statement, Chris, that I don’t wish to encounter them. Ever.
Young people knows how to “use”, but many of them already don’t know how to “do”. In the next few decades, which is my lifespan, I think this is gonna be a nice problem…
I built a single page web app using jQuery and vanilla JS/CSS, but I could have very easily written it entirely in vanilla. So I always wondered why everyone was so excited about frameworks/libraries. I concluded that they may be easier for many developers to work together on, and things like Babel help ensure older browsers are supported. But if you write your code well, and don’t need unit tests, there’s no need to use frameworks/libraries!
I sincerely disagree. A single pwa with a big ol’ chunk of Jquery stuff is a manteinance and debugging nightmare.
You can’t be sure that the code you wrote is well written, especially with a quirky language such as JS. You need some kind of standard.
I think we only need simpler tooling, svelte is a nice example even if it is far from perfect.
I am working an approach with plain html, css, but TypeScript. The project is heavily based on web components, service worker and the assumption that browsers supports http/2 (so no more bundling required).
There is a tiny build script invoking tsc, rsync and node to compile TypeScript, copy files, and run additional build time scripts (written in typescript, for static content generation), into target directory, or public/ for gitlab pages.
There is still node_modules, for typescript and @types/node, but it enables typescript and build time scripting.
I have to say I love it so much. Mainly because there is no webpack, maybe.
So… use the right tool for the job. Think instead of repeating the same patterns. In general I agree, but sometimes generalization is wrong. One of the disadvantages of manually written code is that other people may have a hard time trying to read that code. We are writing for the others after all.
Good luck to solve minifying your CSS, or even miss the idea of mixins…
I think that if you have a basic gulp it’s still a good solution.
Another thing that I was thinking is: gulp blame you when you do a bad structure, imagine working with another person that missed a comma… You will lose a good time to identify this issue, and the css will try to load as usual.
I hope that you can reply that things as well, because seems that you only work by yourself.
Couldn’t agree more. I love how effective is the old plain HTML/CSS. It make the most lightweight websites. I made my own this way. And if gets bigger I would choose a SSG.
Love it. I’m biased in favor of vanilla everything – there’s something deeply satisfying about writing your things from scratch.
I try to stay abreast with the most popular tools so I can collaborate with teams on projects, but for my personal projects, I enjoy barebones CSS, Vanilla JS and some humble tweaking as I go along.
I quite agree. The only way I feel I can learn [which I have been doing on a part-time amateur basis for about 20 years] is get my hands dirty by working directly with the code. The 2 sites I’ve built might not be spiffy, but they work, and that’s what counts, for me: I can build on that.
Hi Jeremy,
Great article.
I recently made the same choice on a project of mine. There is one problem though, copying the header and footer to all your HTML files.
I made this to fix that issue:
htmlsync.js
There is a lot to unpack here, but the general idea is that it would come down to your use-case.
CDN’s are great for hosting libraries (And If I’m not mistaken, there’s a CDN that hosts all NPMJS libraries), but there are valid use-cases where hosting the packages on your own server is a far better option.
Privacy, for one, which is a huge trend in the world lately. Hosting libraries on your own servers ensures you have the full ability to control access and logging (or lack thereof). CDN’s may track usage per IP, and through sheer volume can deduce users’ internet patterns.
I’ve been a part-time web developer for nearly 20 years now, starting when vanilla was the only choice. jQuery was essential to bridge the inconsistencies of browsers. As a one-man band, I currently build most sites using WordPress because it is such a complete ecosystem and clients can do simple maintenance by themselves. Performance can be an issue, but as CSS-Tricks itself shows you, there are solutions. I loved the site I built using Django for one client who really needed a solid database. Felt like it offered the best combination of control and power.
I have experimented with React and Vue, but their value seems aimed at large group projects, or complex projects where vanilla code is overwhelmed, or a team that churns out lots of projects where components can be easily reused. I do find Svelte exciting, and expect it to take off in a year once Svelte-kit is solid.
The Jamstack approach seems to provide a good middle ground offering performance, ability for clients to add or modify content using Markup, and relative simplicity of build process.
Certainly, as #Mike said, “The right tool for the job” is rule #1.